Skip to content

Commit 4d54c04

Browse files
mfikesswannodette
authored andcommitted
CLJS-3034: Truthy-induced inference
1 parent 75e4e52 commit 4d54c04

File tree

2 files changed

+23
-11
lines changed

2 files changed

+23
-11
lines changed

src/main/clojure/cljs/analyzer.cljc

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,19 +1593,27 @@
15931593
(get-in env [:locals sym]))
15941594
[sym tag])))))))
15951595

1596-
(defn- add-predicate-induced-tags
1597-
"Looks at the test and adds any tags which are induced by virtue
1598-
of the predicate being satisfied. For example in (if (string? x) x :bar)
1596+
(defn- truth-induced-tag
1597+
"Refine a tag to exclude clj-nil if the test is a simple symbol."
1598+
[env test]
1599+
(when (and (symbol? test)
1600+
(nil? (namespace test)))
1601+
(let [analyzed-symbol (no-warn (analyze (assoc env :context :expr) test))]
1602+
(when-let [tag (:tag analyzed-symbol)]
1603+
(when (and (set? tag)
1604+
(contains? tag 'clj-nil))
1605+
[test (canonicalize-type (disj tag 'clj-nil))])))))
1606+
1607+
(defn- set-test-induced-tags
1608+
"Looks at the test and sets any tags which are induced by virtue
1609+
of the test being truthy. For example in (if (string? x) x :bar)
15991610
the local x in the then branch must be of string type."
16001611
[env test]
16011612
(let [[local tag] (or (simple-predicate-induced-tag env test)
1602-
(type-check-induced-tag env test))]
1613+
(type-check-induced-tag env test)
1614+
(truth-induced-tag env test))]
16031615
(cond-> env
1604-
local (update-in [:locals local :tag] (fn [prev-tag]
1605-
(if (or (nil? prev-tag)
1606-
(= 'any prev-tag))
1607-
tag
1608-
prev-tag))))))
1616+
local (assoc-in [:locals local :tag] tag))))
16091617

16101618
(defmethod parse 'if
16111619
[op env [_ test then else :as form] name _]
@@ -1614,7 +1622,7 @@
16141622
(when (> (count form) 4)
16151623
(throw (compile-syntax-error env "Too many arguments to if" 'if)))
16161624
(let [test-expr (disallowing-recur (analyze (assoc env :context :expr) test))
1617-
then-expr (allowing-redef (analyze (add-predicate-induced-tags env test) then))
1625+
then-expr (allowing-redef (analyze (set-test-induced-tags env test) then))
16181626
else-expr (allowing-redef (analyze env else))]
16191627
{:env env :op :if :form form
16201628
:test test-expr :then then-expr :else else-expr

src/test/clojure/cljs/analyzer_tests.clj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,11 @@
267267
(is (= (a/no-warn
268268
(e/with-compiler-env test-cenv
269269
(:tag (a/analyze test-env '(let [x ^any []] (if (seqable? x) x :kw))))))
270-
'#{cljs.core/ISeqable array string cljs.core/Keyword})))
270+
'#{cljs.core/ISeqable array string cljs.core/Keyword}))
271+
(is (= (a/no-warn
272+
(e/with-compiler-env test-cenv
273+
(:tag (a/analyze test-env '(let [x (namespace :x)] (if x x :kw))))))
274+
'#{string cljs.core/Keyword})))
271275

272276
(deftest loop-recur-inference
273277
(is (= (a/no-warn

0 commit comments

Comments
 (0)