Lazy transformers now return a LazySeq even over a concrete vector, matching
Clojure: (seq? (map inc [1 2 3])) is true, (vector? ...) false. Replaces the
"preserve representation" eager branch (which returned a vector over vector
input) by routing concrete colls through lazy-from + the lazy step machinery.
Flipping these surfaced four boundary bugs, all fixed here:
- cons over a lazy-seq returned a raw cell @[x thunk]; a cons-of-a-cons then
treated it as a plain 2-array and leaked the rest-thunk as an element (broke
interleave). cons over lazy now returns a proper LazySeq.
- coll->cells mistook a user vector whose 2nd elem is a function ([first last]
from juxt) for a cons cell. Cons cells are mutable arrays; user data is
immutable — route pvec/plist/tuple through immutable tuples and apply the
[val,fn] cell heuristic only to mutable arrays. Also coerce set/map/string/
buffer via core-seq.
- ~@ splice over a lazy map result iterated a LazySeq as a Janet table (broke
lazy-cat / self-ref fib). syntax-quote* now realizes via d-realize before
splicing; core-sqcat (self-host) already realized.
- core-next did (length r) on a lazy rest (never 0 on a table) and ls-rest
could return nil → (length nil) crash. core-rest never returns nil; core-next
uses seq-done? (realizes one cell). seq-done? moved above core-rest.
normalize-pvecs (test helper) realizes lazy-seqs so Janet-= comparisons work.
Gate: conformance 239x3 (interpret/compile/self-host, +10 Option A cases),
lazy-infinite 18/18, fixpoint, self-host, all specs+unit green. (sci-bootstrap
and clojure-test-suite skip — vendored dirs absent in this checkout.)
Remaining for full Option A consistency (jolt-7w4): drop/map-indexed/keep/
keep-indexed/take-nth/interpose/distinct/partition/partition-all still eager
over concrete input.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>