Skip to content

Commit 5c25acb

Browse files
committed
Merge branch 'master' into cljs-3454/set-identical
2 parents db5cbfd + 249faa2 commit 5c25acb

File tree

6 files changed

+87
-25
lines changed

6 files changed

+87
-25
lines changed

src/main/cljs/cljs/core.cljs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3110,7 +3110,7 @@ reduces them without incurring seq initialization"
31103110
([] "")
31113111
([x] (if (nil? x)
31123112
""
3113-
(.join #js [x] "")))
3113+
(.toString x)))
31143114
([x & ys]
31153115
(loop [sb (StringBuffer. (str x)) more ys]
31163116
(if more
@@ -6002,6 +6002,10 @@ reduces them without incurring seq initialization"
60026002
(-empty [coll]
60036003
())
60046004

6005+
ICounted
6006+
(-count [coll]
6007+
(- (-count vec) (+ i off)))
6008+
60056009
IChunkedSeq
60066010
(-chunked-first [coll]
60076011
(array-chunk node off))
@@ -12611,10 +12615,14 @@ reduces them without incurring seq initialization"
1261112615
(let [k (if-not (keyword? k) k (keyword->obj-map-key k))]
1261212616
(if (string? k)
1261312617
(if-not (nil? (scan-array 1 k strkeys))
12614-
(let [new-strobj (obj-clone strobj strkeys)]
12615-
(gobject/set new-strobj k v)
12616-
(ObjMap. meta strkeys new-strobj nil)) ;overwrite
12617-
(let [new-strobj (obj-clone strobj strkeys) ; append
12618+
(if (identical? v (gobject/get strobj k))
12619+
coll
12620+
; overwrite
12621+
(let [new-strobj (obj-clone strobj strkeys)]
12622+
(gobject/set new-strobj k v)
12623+
(ObjMap. meta strkeys new-strobj nil)))
12624+
; append
12625+
(let [new-strobj (obj-clone strobj strkeys)
1261812626
new-keys (aclone strkeys)]
1261912627
(gobject/set new-strobj k v)
1262012628
(.push new-keys k)
@@ -12820,10 +12828,12 @@ reduces them without incurring seq initialization"
1282012828
i (scan-array-equiv 2 k new-bucket)]
1282112829
(aset new-hashobj h new-bucket)
1282212830
(if (some? i)
12823-
(do
12824-
; found key, replace
12825-
(aset new-bucket (inc i) v)
12826-
(HashMap. meta count new-hashobj nil))
12831+
(if (identical? v (aget new-bucket (inc i)))
12832+
coll
12833+
(do
12834+
; found key, replace
12835+
(aset new-bucket (inc i) v)
12836+
(HashMap. meta count new-hashobj nil)))
1282712837
(do
1282812838
; did not find key, append
1282912839
(.push new-bucket k v)
@@ -12962,7 +12972,10 @@ reduces them without incurring seq initialization"
1296212972

1296312973
ICollection
1296412974
(-conj [coll o]
12965-
(Set. meta (assoc hash-map o o) nil))
12975+
(let [new-hash-map (assoc hash-map o o)]
12976+
(if (identical? new-hash-map hash-map)
12977+
coll
12978+
(Set. meta new-hash-map nil))))
1296612979

1296712980
IEmptyableCollection
1296812981
(-empty [coll] (with-meta (. Set -EMPTY) meta))

src/main/clojure/cljs/core.cljc

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -866,23 +866,29 @@
866866
(apply core/str))]
867867
(string-expr (list* 'js* (core/str "[" strs "].join('')") x ys)))))
868868

869+
(core/defn- compile-time-constant? [x]
870+
(core/or
871+
(core/string? x)
872+
(core/keyword? x)
873+
(core/boolean? x)
874+
(core/number? x)))
875+
869876
;; TODO: should probably be a compiler pass to avoid the code duplication
870877
(core/defmacro str
871-
([] "")
872-
([x]
873-
(if (typed-expr? &env x '#{string})
874-
x
875-
(string-expr (core/list 'js* "cljs.core.str.cljs$core$IFn$_invoke$arity$1(~{})" x))))
876-
([x & ys]
877-
(core/let [interpolate (core/fn [x]
878-
(if (typed-expr? &env x '#{string clj-nil})
879-
"~{}"
880-
"cljs.core.str.cljs$core$IFn$_invoke$arity$1(~{})"))
881-
strs (core/->> (core/list* x ys)
882-
(map interpolate)
883-
(interpose ",")
884-
(apply core/str))]
885-
(string-expr (list* 'js* (core/str "[" strs "].join('')") x ys)))))
878+
[& xs]
879+
(core/let [interpolate (core/fn [x]
880+
(core/cond
881+
(typed-expr? &env x '#{clj-nil})
882+
nil
883+
(compile-time-constant? x)
884+
["+~{}" x]
885+
:else
886+
;; Note: can't assume non-nil despite tag here, so we go through str 1-arity
887+
["+cljs.core.str.cljs$core$IFn$_invoke$arity$1(~{})" x]))
888+
strs+args (keep interpolate xs)
889+
strs (string/join (map first strs+args))
890+
args (map second strs+args)]
891+
(string-expr (list* 'js* (core/str "(\"\"" strs ")") args))))
886892

887893
(core/defn- bool-expr [e]
888894
(vary-meta e assoc :tag 'boolean))

src/test/cljs/cljs/core_test.cljs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,3 +1978,11 @@
19781978
(is (= "1two:threefour#{:five}[:six]#{:seven}{:eight :nine}"
19791979
(apply cljs.core/str_ 1 ["two" :three 'four #{:five} [:six] #{:seven} {:eight :nine}])))
19801980
(is (= "1234" (apply cljs.core/str_ 1 2 [3 4]))))
1981+
1982+
(deftest test-cljs-3452
1983+
(let [obj #js {:valueOf (fn [] "dude")
1984+
:toString (fn [] "correct")}
1985+
str-fn (fn [x y]
1986+
(str x obj y "\"foobar\"" 1 :foo nil))]
1987+
(testing "object is stringified using toString"
1988+
(is (= "correct6\"foobar\"1:foo" (str-fn nil (+ 1 2 3)))))))

src/test/cljs/cljs/lite_collections_test.cljs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@
2828
(= 1 (aget (clj->js (obj-map :x 1)) "x"))
2929
(= 1 (aget (clj->js {:x 1}) "x")))
3030

31+
(deftest test-unchanged-identical?
32+
(let [m (obj-map :foo 1)]
33+
(identical? m (assoc m :foo 1)))
34+
(let [m (simple-hash-map :foo 1)]
35+
(identical? m (assoc m :foo 1)))
36+
(let [s (simple-set [:foo])]
37+
(identical? s (conj s :foo))))
38+
3139
(comment
3240

3341
(require '[cljs.lite-collections-test] :reload)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
(ns cljs-3452-str-optimizations.core)
2+
3+
(defn my-str-fn [x y]
4+
(str x y nil ::foobar "my
5+
6+
multiline
7+
8+
string with `backticks`"
9+
true false 3.14))

src/test/clojure/cljs/build_api_tests.clj

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,3 +940,21 @@
940940
(.delete (io/file "package.json"))
941941
(test/delete-node-modules)
942942
(test/delete-out-files out))))
943+
944+
(deftest test-cljs-3452-str-optimizations
945+
(testing "Test that uses compile time optimizations from str macro"
946+
(let [out (.getPath (io/file (test/tmp-dir) "cljs-3452-str-optimizations-out"))]
947+
(test/delete-out-files out)
948+
(let [{:keys [inputs opts]} {:inputs (str (io/file "src" "test" "cljs_build"))
949+
:opts {:main 'cljs-3452-str-optimizations.core
950+
:output-dir out
951+
:optimizations :none
952+
:closure-warnings {:check-types :off}}}
953+
cenv (env/default-compiler-env)]
954+
(build/build (build/inputs (io/file inputs "cljs_3452_str_optimizations/core.cljs")) opts cenv))
955+
(let [source (slurp (io/file out "cljs_3452_str_optimizations/core.js"))]
956+
(testing "only seven string concats, compile time nil is ignored"
957+
(is (= 7 (count (re-seq #"[\+]" source)))))
958+
(testing "only two 1-arity str calls, compile time constants are optimized"
959+
(is (= 2 (count (re-seq #"\$1\(.*?\)" source))))))
960+
(test/delete-out-files out))))

0 commit comments

Comments
 (0)