fix: merge nil/empty + conj semantics to match Clojure

core-merge returned {} for (merge) and errored on nil args. Rewrite to follow
Clojure: (when (some identity maps) (reduce conj (or (first maps) {}) (rest maps))).

- (merge) and (merge nil nil) -> nil
- nil args elsewhere are no-ops: (merge {} nil) -> {}, (merge nil {:a 1}) -> {:a 1}
- later args follow conj semantics: a map merges its entries, a [k v]
  vector/map-entry adds that entry ((merge {} [:foo 1]) -> {:foo 1},
  (merge {} (first {:a 1})) -> {:a 1})
- collection keys preserved (first arg's phm type kept; entries via core-assoc
  which promotes struct->phm for collection keys)

spec: 9 new merge cases in maps-spec. merge.cljc 13/18/11 -> 29/11/2.
clojure-test-suite pass 1688->1704. jpm test green.

Remaining merge.cljc fails are the lenient-where-Clojure-throws class (atomic
args, >2-element vectors). Fixes jolt-dxx.
This commit is contained in:
Yogthos 2026-06-05 09:22:27 -04:00
parent 2885650ef6
commit e75771084e
3 changed files with 36 additions and 5 deletions

View file

@ -34,6 +34,15 @@
["dissoc many" "{:a 1}" "(dissoc {:a 1 :b 2 :c 3} :b :c)"]
["merge" "{:a 1, :b 2}" "(merge {:a 1} {:b 2})"]
["merge overwrites" "{:a 2}" "(merge {:a 1} {:a 2})"]
["merge lattermost wins" "{:a 3}" "(merge {:a 1} {:a 2} {:a 3})"]
["merge no args -> nil" "nil" "(merge)"]
["merge all nil -> nil" "nil" "(merge nil nil)"]
["merge nil arg no-op" "{:a 1}" "(merge {:a 1} nil)"]
["merge nil then map" "{:a 1}" "(merge nil {:a 1})"]
["merge empty + nil" "{}" "(merge {} nil)"]
["merge map-entry (conj)" "{:a 1}" "(merge {} (first {:a 1}))"]
["merge [k v] vector" "{:foo 1}" "(merge {} [:foo 1])"]
["merge collection key" "true" "(= {[2 3] :foo} (merge {[2 3] :foo} nil {}))"]
["merge-with" "{:a 3}" "(merge-with + {:a 1} {:a 2})"]
["update" "{:a 2}" "(update {:a 1} :a inc)"]
["update missing w/ fnil" "{:a 1}" "(update {} :a (fnil inc 0))"]