From 271411b3e226a52882a5fa678ef0119928f55ef3 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Fri, 26 Jun 2026 21:25:10 -0400 Subject: [PATCH] Fix conj on a lazy-seq, add lazy-seq interop regression rows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rest = more() change made (rest coll) return a jolt-lazyseq, so the very common (conj (rest xs) y) hit jolt-conj1's base case, which doesn't recognize a lazyseq, and threw "conj: unsupported collection" (caught by core.match's seq-pattern compiler). conj on a lazy-seq now prepends like conj on any seq. The corpus had no row exercising a collection op on a rest-derived seq, so the class slipped past the gate; add a seqs/lazy-seq-interop suite (conj/into/first/ count/nth/reduce/map/filter/apply/cons/=/empty?/seq over (rest …) and lazy-seq), all JVM-certified. --- host/chez/lazy-bridge.ss | 7 +++++++ test/chez/corpus.edn | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/host/chez/lazy-bridge.ss b/host/chez/lazy-bridge.ss index acd7dd9..76e0043 100644 --- a/host/chez/lazy-bridge.ss +++ b/host/chez/lazy-bridge.ss @@ -49,6 +49,13 @@ (cseq-lazy x (lambda () (force-lazyseq coll))) (%ls-cons x coll)))) +;; (conj lazyseq x): conj onto a seq prepends, like any seq — (conj (rest xs) y). +;; rest returns a lazyseq, so this is a common path; without it conj reports the +;; lazyseq as an "unsupported collection". +(define %ls-conj1 jolt-conj1) +(set! jolt-conj1 (lambda (coll x) + (if (jolt-lazyseq? coll) (jolt-cons x coll) (%ls-conj1 coll x)))) + ;; A lazyseq is a NEW value type, so the dispatchers that DON'T route through ;; jolt-seq must learn it or a raw (unrealized) lazyseq escapes — e.g. the corpus ;; compares (= [1 3 5] (take-nth 2 …)) against the raw lazyseq, and jolt=2 would diff --git a/test/chez/corpus.edn b/test/chez/corpus.edn index 0ea113d..67b70b7 100644 --- a/test/chez/corpus.edn +++ b/test/chez/corpus.edn @@ -3278,4 +3278,19 @@ {:suite "interop / uri equality" :label "URIs are value-equal and usable as set members" :expected "[true true]" :actual "[(= (java.net.URI. \"/\") (java.net.URI. \"/\")) (= #{(java.net.URI. \"/\")} #{(java.net.URI. \"/\")})]"} {:suite "stdlib / clojure.walk" :label "macroexpand-all expands a form" :expected "true" :actual "(do (require (quote clojure.walk)) (seq? (clojure.walk/macroexpand-all (quote (when true 1)))))"} {:suite "regex / re-seq zero-width" :label "a zero-width match advances by one without repeating" :expected "[\"a\" \"\" \"a\" \"\"]" :actual "(vec (re-seq #\"a*\" \"aba\"))"} + {:suite "seqs / lazy-seq interop" :label "conj onto a rest-derived seq prepends" :expected "true" :actual "(= [9 2 3] (vec (conj (rest [1 2 3]) 9)))"} + {:suite "seqs / lazy-seq interop" :label "conj onto a lazy-seq prepends" :expected "true" :actual "(= [9 1 2] (vec (conj (lazy-seq (list 1 2)) 9)))"} + {:suite "seqs / lazy-seq interop" :label "into over a conj'd rest-seq" :expected "true" :actual "(= [0 2 3] (into [] (conj (rest [1 2 3]) 0)))"} + {:suite "seqs / lazy-seq interop" :label "first of a conj'd rest-seq" :expected "true" :actual "(= 9 (first (conj (rest [1 2 3]) 9)))"} + {:suite "seqs / lazy-seq interop" :label "count of a conj'd rest-seq" :expected "true" :actual "(= 3 (count (conj (rest [1 2 3]) 9)))"} + {:suite "seqs / lazy-seq interop" :label "nth into a rest-seq" :expected "true" :actual "(= 3 (nth (rest [1 2 3]) 1))"} + {:suite "seqs / lazy-seq interop" :label "reduce over a rest-seq" :expected "true" :actual "(= 5 (reduce + (rest [1 2 3])))"} + {:suite "seqs / lazy-seq interop" :label "a rest-seq equals the literal tail" :expected "true" :actual "(= (quote (2 3)) (rest [1 2 3]))"} + {:suite "seqs / lazy-seq interop" :label "map over a rest-seq" :expected "true" :actual "(= [3 4] (vec (map inc (rest [1 2 3]))))"} + {:suite "seqs / lazy-seq interop" :label "filter over a rest-seq" :expected "true" :actual "(= [3] (vec (filter odd? (rest [1 2 3 4]))))"} + {:suite "seqs / lazy-seq interop" :label "apply over a rest-seq" :expected "true" :actual "(= 5 (apply + (rest [1 2 3])))"} + {:suite "seqs / lazy-seq interop" :label "seq of an empty rest is nil" :expected "true" :actual "(nil? (seq (rest [1])))"} + {:suite "seqs / lazy-seq interop" :label "empty? of an empty rest" :expected "true" :actual "(empty? (rest [1]))"} + {:suite "seqs / lazy-seq interop" :label "cons onto a rest-seq" :expected "true" :actual "(= [0 2 3] (vec (cons 0 (rest [1 2 3]))))"} + {:suite "seqs / lazy-seq interop" :label "into a set from a rest-seq" :expected "true" :actual "(= #{2 3} (into #{} (rest [1 2 3])))"} ]