Reader attaches collection metadata to data, not a with-meta form

The reader lowered ^meta on a vector/map/set literal to a runtime
(with-meta form meta) list, so read-string/edn of data with metadata
returned the form and lost the metadata. Attach it to the value instead,
as Clojure does; the analyzer re-emits (with-meta coll meta) for a
meta-carrying collection literal in code, so a literal still carries its
metadata at runtime and ^Type/^long arglist hints (consumed by
analyze-arity directly) are unaffected.

Also: pr honors *print-meta*, and clojure.walk/clojure.edn re-attach
metadata to the collections they rebuild (matches Clojure; a
metadata-driven config lib like aero relies on it).
This commit is contained in:
Yogthos 2026-06-24 12:04:36 -04:00
parent 091d2c4b62
commit 473d1002b7
8 changed files with 763 additions and 716 deletions

View file

@ -5,19 +5,21 @@
[inner outer form]
(cond
; vectors/maps first so seq? can't swallow them (a vector is not seq? on
; jolt, but keep the concrete branches authoritative)
(vector? form) (outer (vec (map inner form)))
; jolt, but keep the concrete branches authoritative). Re-attach the form's
; metadata to the rebuilt collection, as Clojure does — a metadata-driven walk
; (aero/spec) needs ^:ref and friends to survive the rebuild.
(vector? form) (outer (with-meta (vec (map inner form)) (meta form)))
; a record is also map?, but (empty record) yields a plain map — rebuild by
; conj-ing the walked entries back onto the original so the record TYPE
; survives. Type-dispatched walks depend on it (e.g. integrant resolves
; #ig/ref by detecting its Ref record while postwalking the config).
(record? form) (outer (reduce (fn [r x] (conj r (inner x))) form form))
(map? form) (outer (into (empty form) (map inner form)))
(map? form) (outer (with-meta (into (empty form) (map inner form)) (meta form)))
; lists rebuild as lists, other seqs (incl. macro/template output: cons/
; concat/lazy-seq) walk too — without this, postwalk-replace silently no-op'd
; a quoted list, breaking clojure.template/apply-template
(list? form) (outer (apply list (map inner form)))
(seq? form) (outer (map inner form))
(list? form) (outer (with-meta (apply list (map inner form)) (meta form)))
(seq? form) (outer (with-meta (map inner form) (meta form)))
:else (outer form)))
(defn postwalk