core: strict map?/coll? — tagged structs are values, sorted colls are colls

map? treated ANY struct as a map, so (map? 'sym), (map? \a), and
(map? (random-uuid)) were all true; coll? had the same wart. Meanwhile both
were FALSE for sorted maps (and coll? for sorted sets and records), which are
collections in Clojure. Now: a map is a plain struct literal, a phm, a sorted
map, or a record; coll? additionally includes sorted sets. Tagged structs
(anything with :jolt/type) are values.

The loose-map? dependents (destructure's clause ordering, defn's attr-map
guard) already guarded with symbol? first, so nothing relied on the wart —
full gate green, and the suite gained: 4074 -> 4081 pass / 72 clean files
(map_qmark/coll_qmark assertions now correct); baselines raised. 22 new
strictness spec cases.
This commit is contained in:
Yogthos 2026-06-10 10:34:59 -04:00
parent b836a5d499
commit 526de12ad1
3 changed files with 47 additions and 4 deletions

View file

@ -167,11 +167,27 @@
(defn core-keyword? [x] (keyword? x))
(defn core-symbol? [x] (and (struct? x) (= :symbol (x :jolt/type))))
(defn core-vector? [x] (jvec? x))
(defn core-map? [x] (or (phm? x) (struct? x) (if (and (table? x) (get x :jolt/deftype)) true false)))
# map? is STRICT: a plain struct map literal, a phm, a sorted map, or a record.
# Tagged structs (symbols/chars/uuids — anything with :jolt/type) are VALUES,
# not maps. (sorted-map? is defined later, so the table check is inlined.)
(defn core-map? [x]
(or (phm? x)
(and (struct? x) (nil? (get x :jolt/type)))
(and (table? x)
(or (not (nil? (get x :jolt/deftype)))
(= :jolt/sorted-map (get x :jolt/type))))))
# seq? is true only for actual sequences (lists, lazy-seqs) — NOT vectors, which
# are not ISeq in Clojure. (A Janet array represents a Clojure list/seq result.)
(defn core-seq? [x] (or (array? x) (plist? x) (lazy-seq? x)))
(defn core-coll? [x] (or (array? x) (tuple? x) (pvec? x) (plist? x) (struct? x) (phm? x) (set? x) (lazy-seq? x)))
# coll? mirrors map?'s strictness for structs/tables, and includes the sorted
# collections and records (IPersistentCollection in Clojure).
(defn core-coll? [x]
(or (array? x) (tuple? x) (pvec? x) (plist? x) (phm? x) (set? x) (lazy-seq? x)
(and (struct? x) (nil? (get x :jolt/type)))
(and (table? x)
(or (not (nil? (get x :jolt/deftype)))
(= :jolt/sorted-map (get x :jolt/type))
(= :jolt/sorted-set (get x :jolt/type))))))
(defn core-true? [x] (= true x))
(defn core-false? [x] (= false x))

View file

@ -43,9 +43,9 @@
# Raised 4004 -> 4034 / clean 66 -> 67 porting partition-all + repeatedly to the
# overlay, which required fixing two leniencies (a char is not callable; take
# validates its count) — correct beyond those fns, so the suite rose broadly.
(def baseline-pass 4074)
(def baseline-pass 4081)
# A file is "clean" when it ran with zero failures AND zero errors.
(def baseline-clean-files 71)
(def baseline-clean-files 72)
# Per-file wall-clock budget (seconds). Normal files finish in well under 1s, so
# this normally only fires on genuinely-infinite-sequence hangs. It's an env var
# (JOLT_SUITE_TIMEOUT) so CI — whose runners are slower than a dev machine — can

View file

@ -90,6 +90,33 @@
# Tagged-value predicates moved to the overlay in Phase 4 (read the value's
# :jolt/type via get). The constructors stay native.
# map?/coll? are STRICT (jolt-6s2 cleanup): tagged structs (symbols, chars,
# uuids) are values, not collections; sorted maps/sets and records ARE
# collections (and sorted-map/record are map?), matching Clojure.
(defspec "predicates / map? & coll? strictness"
["map? symbol" "false" "(map? (quote sym))"]
["map? char" "false" "(map? \\a)"]
["map? uuid" "false" "(map? (random-uuid))"]
["map? literal" "true" "(map? {:a 1})"]
["map? hash-map" "true" "(map? (hash-map :a 1))"]
["map? sorted-map" "true" "(map? (sorted-map :a 1))"]
["map? record" "true" "(do (defrecord Mr [a]) (map? (->Mr 1)))"]
["map? sorted-set" "false" "(map? (sorted-set 1))"]
["map? vector" "false" "(map? [1])"]
["coll? symbol" "false" "(coll? (quote sym))"]
["coll? char" "false" "(coll? \\a)"]
["coll? uuid" "false" "(coll? (random-uuid))"]
["coll? keyword" "false" "(coll? :k)"]
["coll? string" "false" "(coll? \"s\")"]
["coll? map literal" "true" "(coll? {:a 1})"]
["coll? sorted-map" "true" "(coll? (sorted-map :a 1))"]
["coll? sorted-set" "true" "(coll? (sorted-set 1))"]
["coll? record" "true" "(do (defrecord Cr [a]) (coll? (->Cr 1)))"]
["coll? vector" "true" "(coll? [1])"]
["coll? list" "true" "(coll? (list 1))"]
["coll? set" "true" "(coll? #{1})"]
["coll? lazy seq" "true" "(coll? (map inc [1]))"])
(defspec "predicates / tagged-value (Phase 4)"
["atom? yes" "true" "(atom? (atom 1))"]
["atom? no" "false" "(atom? 1)"]