Merge pull request #101 from jolt-lang/fix-record-vector-pred

Records are not vectors: fix vector?/sequential? for shape-recs (jolt-14k)
This commit is contained in:
Dmitri Sotnikov 2026-06-14 22:21:17 +00:00 committed by GitHub
commit cf271e218a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 13 additions and 2 deletions

View file

@ -204,7 +204,12 @@
(defn core-fn? [x] (or (function? x) (cfunction? x)))
(defn core-keyword? [x] (keyword? x))
(defn core-symbol? [x] (and (struct? x) (= :symbol (x :jolt/type))))
(defn core-vector? [x] (jvec? x))
# A record shape-rec is a Janet tuple (jvec? true), but a record is NOT a vector
# in Clojure — `(vector? record)` is false, and so is `(sequential? record)`.
# Excluding it here keeps map-destructuring of a record off the `& {:keys}` kwargs
# coerce path (which does `(apply hash-map x)` for a sequential x). jvec? itself
# stays as-is for internal representation dispatch.
(defn core-vector? [x] (and (jvec? x) (not (shape-rec? x))))
# 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.)

View file

@ -29,7 +29,13 @@
["record? true" "(do (defrecord Rd [x y]) (record? (->Rd 1 2)))"]
["record vs map not=" "(do (defrecord Re [x y]) (not (= (->Re 1 2) {:x 1 :y 2})))"]
["assoc keeps type" "(do (defrecord Rf [x y]) (record? (assoc (->Rf 1 2) :x 9)))"]
["pr declared order" "(do (defrecord Rg [b a c]) (= \"#user.Rg{:b 10, :a 20, :c 30}\" (pr-str (->Rg 10 20 30))))"]])
["pr declared order" "(do (defrecord Rg [b a c]) (= \"#user.Rg{:b 10, :a 20, :c 30}\" (pr-str (->Rg 10 20 30))))"]
# a record shape-rec is a Janet tuple, but a record is NOT a vector/sequential
# in Clojure — else map-destructuring it takes the kwargs coerce path and
# corrupts (reitit router crash, jolt-14k).
["vector? record false" "(do (defrecord Rh [x y]) (not (vector? (->Rh 1 2))))"]
["sequential? record false" "(do (defrecord Ri [x y]) (not (sequential? (->Ri 1 2))))"]
["destructure record :or" "(do (defrecord Rj [a b c d e]) (let [{:keys [a e] :or {a 0}} (->Rj 1 2 3 4 5)] (= 6 (+ a e))))"]])
(each [label prog] cases
(check label (eval-string dl prog) true))