Skip to content

Commit 9e9b6d9

Browse files
authored
CLJS-3373: Externs Inference issue with vars invoked from foreign libs (#173)
Fix invoke inference to handle invokes on vars from foreign libs. If we have a :js-var we cannot know whether it is a function or property. Note this is different from the `:js-fn-var` case where a provided extern did disambiguate. In the case of `:js-var` we throw away the leading prefix since the types simply cannot be known. Add a test case based on the one provided by Timothy Pratley.
1 parent 40358fc commit 9e9b6d9

File tree

2 files changed

+43
-7
lines changed

2 files changed

+43
-7
lines changed

src/main/clojure/cljs/analyzer.cljc

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,15 +1514,31 @@
15141514
else-tag #{else-tag})]
15151515
(into then-tag else-tag))))))))
15161516

1517-
(defn infer-invoke [env {f :fn :keys [args] :as e}]
1518-
(let [me (assoc (find-matching-method f args) :op :fn-method)]
1517+
(defn js-var? [ast]
1518+
(= :js-var (:op ast)))
1519+
1520+
(defn js-var-fn? [fn-ast]
1521+
(js-var? (:info fn-ast)))
1522+
1523+
(defn fn-ast->tag
1524+
[{:keys [info] :as fn-ast}]
1525+
(cond
1526+
;; ClojureScript Fn
1527+
(:fn-var info) (:ret-tag info)
1528+
;; Global foreign JS Fn inferred via externs
1529+
(:js-fn-var info) (:ret-tag info)
1530+
;; Node foreign JS *var*, we cannot distinguish between properties
1531+
;; and functions from such libs at this time, we cannot possibly
1532+
;; know the returns so break the leading prefix (start with raw 'js tag)
1533+
(js-var-fn? fn-ast) 'js
1534+
:else (when (= 'js (:ns info)) 'js)))
1535+
1536+
(defn infer-invoke [env {fn-ast :fn :keys [args] :as e}]
1537+
(let [me (assoc (find-matching-method fn-ast args) :op :fn-method)]
15191538
(if-some [ret-tag (infer-tag env me)]
15201539
ret-tag
1521-
(let [{:keys [info]} f]
1522-
(if-some [ret-tag (if (or (true? (:fn-var info))
1523-
(true? (:js-fn-var info)))
1524-
(:ret-tag info)
1525-
(when (= 'js (:ns info)) 'js))]
1540+
(let []
1541+
(if-some [ret-tag (fn-ast->tag fn-ast)]
15261542
ret-tag
15271543
impl/ANY_SYM)))))
15281544

src/test/clojure/cljs/externs_infer_tests.clj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,26 @@
413413
:with-core? true}))]
414414
(is (empty? @ws))))
415415

416+
(deftest test-cljs-3373
417+
(testing "var from foreign libraries that are invoked as fn should propagate 'js hints"
418+
(let [ws (atom [])
419+
res (infer-test-helper
420+
{:js-dependency-index {"firebase" {:global-exports '{firebase Firebase}}}
421+
:forms '[(ns foo.core
422+
(:require [firebase :refer [getAuth]]))
423+
(def auth
424+
(doto (getAuth)
425+
(.useDeviceLanguage)
426+
(.onAuthStateChanged (fn [user]))))]
427+
:warnings ws
428+
:warn true
429+
:with-core? false})]
430+
(is (= (unsplit-lines
431+
["Object.getAuth;"
432+
"Object.useDeviceLanguage;"
433+
"Object.onAuthStateChanged;"])
434+
res)))))
435+
416436
(comment
417437
(binding [ana/*cljs-ns* ana/*cljs-ns*]
418438
(ana/no-warn

0 commit comments

Comments
 (0)