Skip to content

Commit 88e2470

Browse files
mfikesswannodette
authored andcommitted
CLJS-2865: Optimize string expression concatenation
Borrow a bit of the logic used for boolean expressions to check if arguments to the str macro are of string or clj-nil type, and to also cause the str macro to indicate that its return type is string.
1 parent 7bd33f5 commit 88e2470

2 files changed

Lines changed: 26 additions & 4 deletions

File tree

src/main/clojure/cljs/core.cljc

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -827,22 +827,35 @@
827827
(core/quot c 32)
828828
(core/inc (core/quot c 32)))))
829829

830+
(core/defn- compatible? [inferred-tag allowed-tags]
831+
(if (set? inferred-tag)
832+
(clojure.set/subset? inferred-tag allowed-tags)
833+
(contains? allowed-tags inferred-tag)))
834+
835+
(core/defn- typed-expr? [env form allowed-tags]
836+
(compatible? (cljs.analyzer/infer-tag env
837+
(cljs.analyzer/no-warn (cljs.analyzer/analyze env form)))
838+
allowed-tags))
839+
840+
(core/defn- string-expr [e]
841+
(vary-meta e assoc :tag 'string))
842+
830843
(core/defmacro str
831844
([] "")
832845
([x]
833-
(if (core/string? x)
846+
(if (typed-expr? &env x '#{string})
834847
x
835-
(core/list 'js* "cljs.core.str.cljs$core$IFn$_invoke$arity$1(~{})" x)))
848+
(string-expr (core/list 'js* "cljs.core.str.cljs$core$IFn$_invoke$arity$1(~{})" x))))
836849
([x & ys]
837850
(core/let [interpolate (core/fn [x]
838-
(if (core/string? x)
851+
(if (typed-expr? &env x '#{string clj-nil})
839852
"~{}"
840853
"cljs.core.str.cljs$core$IFn$_invoke$arity$1(~{})"))
841854
strs (core/->> (core/list* x ys)
842855
(map interpolate)
843856
(interpose ",")
844857
(apply core/str))]
845-
(list* 'js* (core/str "[" strs "].join('')") x ys))))
858+
(string-expr (list* 'js* (core/str "[" strs "].join('')") x ys)))))
846859

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

src/test/cljs/cljs/core_test.cljs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,15 @@
16371637
(is (= "xyzzy" (str "x" "y" "z" "z" "y")))
16381638
(is (= "a1b2c3" (str "a" 1 "b" 2 "c" 3))))
16391639

1640+
(defn str-fn-2865 []
1641+
"hello")
1642+
1643+
(deftest test-cljs-2865
1644+
(is (= "ab" (str "a" (let [x true] (when x "b")))))
1645+
(is (= "ab" (str "a" js/undefined "b")))
1646+
(is (= "ab" (str "a" nil "b")))
1647+
(is (= "ahellob" (str "a" (str-fn-2865) "b"))))
1648+
16401649
(deftest test-cljs-2934
16411650
(let [x (delay 1)]
16421651
(is (= "#object[cljs.core.Delay {:status :pending, :val nil}]" (pr-str x)))

0 commit comments

Comments
 (0)