Skip to content

Commit 5590b8d

Browse files
authored
CLJS-3324: hash-map behavior differs from Clojure (#102)
* CLJS-3324: hash-map behavior differs from Clojure Add runtime check to hash-map w/o changing perf. Add runtime check to PersistentHashMap.fromArrays w/o significant perf change. hash-map is also an inlining macro which invokes PersistentHashMap.fromArrays. naive use of partition leads to garbage in / out. Pad to fill in the missing value, then remove - then when computing the values drop when we hit a non-pair. This way we get non-matching array lengths and can defer to the runtime check. Add tests.
1 parent 29363bb commit 5590b8d

File tree

3 files changed

+19
-4
lines changed

3 files changed

+19
-4
lines changed

src/main/cljs/cljs/core.cljs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8052,7 +8052,9 @@ reduces them without incurring seq initialization"
80528052
(let [len (alength ks)]
80538053
(loop [i 0 ^not-native out (transient (.-EMPTY PersistentHashMap))]
80548054
(if (< i len)
8055-
(recur (inc i) (-assoc! out (aget ks i) (aget vs i)))
8055+
(if (<= (alength vs) i)
8056+
(throw (js/Error. (str "No value supplied for key: " (aget ks i))))
8057+
(recur (inc i) (-assoc! out (aget ks i) (aget vs i))))
80568058
(persistent! out))))))
80578059

80588060
(set! (.-createWithCheck PersistentHashMap)
@@ -8926,7 +8928,10 @@ reduces them without incurring seq initialization"
89268928
[& keyvals]
89278929
(loop [in (seq keyvals), out (transient (.-EMPTY PersistentHashMap))]
89288930
(if in
8929-
(recur (nnext in) (assoc! out (first in) (second in)))
8931+
(let [in' (next in)]
8932+
(if (nil? in')
8933+
(throw (js/Error. (str "No value supplied for key: " (first in))))
8934+
(recur (next in') (assoc! out (first in) (first in')) )))
89308935
(persistent! out))))
89318936

89328937
(defn array-map

src/main/clojure/cljs/core.cljc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2623,9 +2623,12 @@
26232623
(core/defmacro hash-map
26242624
([] `(.-EMPTY cljs.core/PersistentHashMap))
26252625
([& kvs]
2626-
(core/let [pairs (partition 2 kvs)
2626+
(core/let [pairs (map
2627+
(core/fn [pair]
2628+
(remove #{::missing} pair))
2629+
(partition 2 2 (repeat ::missing) kvs))
26272630
ks (map first pairs)
2628-
vs (map second pairs)]
2631+
vs (map second (take-while #(= 2 (count %)) pairs))]
26292632
(vary-meta
26302633
`(.fromArrays cljs.core/PersistentHashMap (array ~@ks) (array ~@vs))
26312634
assoc :tag 'cljs.core/PersistentHashMap))))

src/test/cljs/cljs/collections_test.cljs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,13 @@
10841084
(testing "persistent vector invoke matches clojure"
10851085
(is (thrown-with-msg? js/Error #"Key must be integer" ([1 2] nil)))))
10861086

1087+
(deftest test-cljs-3324
1088+
(testing "hash-map behavior with missing values matches clojure"
1089+
(is (thrown-with-msg? js/Error #"No value supplied for key: :a"
1090+
(hash-map :a)))
1091+
(is (thrown-with-msg? js/Error #"No value supplied for key: :a"
1092+
(apply hash-map [:a])))))
1093+
10871094
(comment
10881095

10891096
(run-tests)

0 commit comments

Comments
 (0)