Skip to content

Commit 60c9055

Browse files
authored
CLJS-3438: Inference for goog.object/containsKey returns any, not boolean (#262)
- fix cljs.analyzer/desugar-dotted-expr, generated malformed AST in the case of goog.module var - compiler test for goog.object/containsKey - fix parameter parsing in cljs.externs to properly handle var args and optional arguments - fix fn-arity warning so that we use unaliased names if available (goog.module names are aliases) - cljs.core: goog.object/containsKey hint no longer needed
1 parent aa5e751 commit 60c9055

File tree

5 files changed

+52
-25
lines changed

5 files changed

+52
-25
lines changed

src/main/cljs/cljs/core.cljs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12180,7 +12180,7 @@ reduces them without incurring seq initialization"
1218012180
(let [k (munge (str_ sym))]
1218112181
;; FIXME: this shouldn't need ^boolean due to GCL library analysis,
1218212182
;; but not currently working
12183-
(when ^boolean (gobject/containsKey obj k)
12183+
(when (gobject/containsKey obj k)
1218412184
(let [var-sym (symbol (str_ name) (str_ sym))
1218512185
var-meta {:ns this}]
1218612186
(Var. (ns-lookup obj k) var-sym var-meta)))))

src/main/clojure/cljs/analyzer.cljc

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,9 +1214,12 @@
12141214

12151215
(defmethod resolve* :goog-module
12161216
[env sym full-ns current-ns]
1217-
{:name (symbol (str current-ns) (str (munge-goog-module-lib full-ns) "." (name sym)))
1218-
:ns current-ns
1219-
:op :var})
1217+
(let [sym-ast (gets @env/*compiler* ::namespaces full-ns :defs (symbol (name sym)))]
1218+
(merge sym-ast
1219+
{:name (symbol (str current-ns) (str (munge-goog-module-lib full-ns) "." (name sym)))
1220+
:ns current-ns
1221+
:op :var
1222+
:unaliased-name (symbol (str full-ns) (name sym))})))
12201223

12211224
(defmethod resolve* :global
12221225
[env sym full-ns current-ns]
@@ -3887,15 +3890,15 @@
38873890
bind-args? (and HO-invoke?
38883891
(not (all-values? args)))]
38893892
(when ^boolean fn-var?
3890-
(let [{^boolean variadic :variadic? :keys [max-fixed-arity method-params name ns macro]} (:info fexpr)]
3891-
;; don't warn about invalid arity when when compiling a macros namespace
3893+
(let [{^boolean variadic :variadic? :keys [max-fixed-arity method-params name unaliased-name ns macro]} (:info fexpr)]
3894+
;; don't warn about invalid arity when compiling a macros namespace
38923895
;; that requires itself, as that code is not meant to be executed in the
38933896
;; `$macros` ns - António Monteiro
38943897
(when (and #?(:cljs (not (and (gstring/endsWith (str cur-ns) "$macros")
38953898
(symbol-identical? cur-ns ns)
38963899
(true? macro))))
38973900
(invalid-arity? argc method-params variadic max-fixed-arity))
3898-
(warning :fn-arity env {:name name :argc argc}))))
3901+
(warning :fn-arity env {:name (or unaliased-name name) :argc argc}))))
38993902
(when (and kw? (not (or (== 1 argc) (== 2 argc))))
39003903
(warning :fn-arity env {:name (first form) :argc argc}))
39013904
(let [deprecated? (-> fexpr :info :deprecated)
@@ -3946,14 +3949,20 @@
39463949
{:op :host-field
39473950
:env (:env expr)
39483951
:form (list '. prefix field)
3949-
:target (desugar-dotted-expr (-> expr
3952+
;; goog.module vars get converted to the form of
3953+
;; current.ns/goog$module.theDef, we need to dissoc
3954+
;; actual extern var info so we get something well-formed
3955+
:target (desugar-dotted-expr (-> (dissoc expr :info)
39503956
(assoc :name prefix
39513957
:form prefix)
39523958
(dissoc :tag)
39533959
(assoc-in [:info :name] prefix)
39543960
(assoc-in [:env :context] :expr)))
39553961
:field field
39563962
:tag (:tag expr)
3963+
;; in the case of goog.module var if there is :info,
3964+
;; we need to adopt it now as this is where :ret-tag info lives
3965+
:info (:info expr)
39573966
:children [:target]})
39583967
expr)
39593968
;:var

src/main/clojure/cljs/externs.clj

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
[clojure.string :as string])
1414
(:import [com.google.javascript.jscomp
1515
CompilerOptions CompilerOptions$Environment SourceFile CompilerInput CommandLineRunner]
16-
[com.google.javascript.jscomp.parsing Config$JsDocParsing]
16+
[com.google.javascript.jscomp.parsing Config$JsDocParsing JsDocInfoParser$ExtendedTypeInfo]
1717
[com.google.javascript.rhino
18-
Node Token JSTypeExpression JSDocInfo$Visibility]
18+
Node Token JSTypeExpression JSDocInfo JSDocInfo$Visibility]
1919
[java.util.logging Level]
2020
[java.net URL]))
2121

@@ -88,14 +88,13 @@
8888
(some-> (.getRoot texpr) parse-texpr simplify-texpr))
8989

9090
(defn params->method-params [xs]
91-
(letfn [(not-opt? [x]
92-
(not (string/starts-with? (name x) "opt_")))]
93-
(let [required (into [] (take-while not-opt? xs))
94-
opts (drop-while not-opt? xs)]
95-
(loop [ret [required] opts opts]
96-
(if-let [opt (first opts)]
97-
(recur (conj ret (conj (last ret) opt)) (drop 1 opts))
98-
(seq ret))))))
91+
(let [not-opt? (complement :optional?)
92+
required (into [] (map :name (take-while not-opt? xs)))
93+
opts (map :name (drop-while not-opt? xs))]
94+
(loop [ret [required] opts opts]
95+
(if-let [opt (first opts)]
96+
(recur (conj ret (conj (last ret) opt)) (drop 1 opts))
97+
(seq ret)))))
9998

10099
(defn generic? [t]
101100
(let [s (name t)]
@@ -108,6 +107,18 @@
108107
(= t 'Array) 'array
109108
:else t)))
110109

110+
(defn get-params
111+
"Return param information in JSDoc appearance order. GCL is relatively
112+
civilized, so this isn't really a problem."
113+
[^JSDocInfo info]
114+
(map
115+
(fn [n]
116+
(let [t (.getParameterType info n)]
117+
{:name (symbol n)
118+
:optional? (.isOptionalArg t)
119+
:var-args? (.isVarArgs t)}))
120+
(.getParameterNames info)))
121+
111122
(defn get-var-info [^Node node]
112123
(when node
113124
(let [info (.getJSDocInfo node)]
@@ -124,15 +135,15 @@
124135
(if (or (.hasReturnType info)
125136
(as-> (.getParameterCount info) c
126137
(and c (pos? c))))
127-
(let [arglist (into [] (map symbol (.getParameterNames info)))
138+
(let [arglist (get-params info)
128139
arglists (params->method-params arglist)]
129140
{:tag 'Function
130141
:js-fn-var true
131142
:ret-tag (or (some-> (.getReturnType info)
132143
get-tag gtype->cljs-type)
133144
'clj-nil)
134-
:variadic? (boolean (some '#{var_args} arglist))
135-
:max-fixed-arity (count (take-while #(not= 'var_args %) arglist))
145+
:variadic? (boolean (some :var-args? arglist))
146+
:max-fixed-arity (count (take-while (complement :var-args?) arglist))
136147
:method-params arglists
137148
:arglists arglists}))))
138149
{:file *source-file*

src/test/clojure/cljs/compiler_tests.clj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,16 @@
391391
(if (gstring/contains "foobar" "foo") true false)]))]
392392
(is (nil? (re-find #"truth_" code))))))
393393

394+
(deftest test-goog-module-infer-cljs-3438
395+
(testing "goog.object/containKey requires correct handling of vars from
396+
goog.module namespace"
397+
(let [code (env/with-compiler-env (env/default-compiler-env)
398+
(compile-form-seq
399+
'[(ns test.foo
400+
(:require [goog.object :as gobject]))
401+
(if (gobject/containsKey nil nil) true false)]))]
402+
(is (nil? (re-find #"truth_" code))))))
403+
394404
;; CLJS-1225
395405

396406
(comment

src/test/clojure/cljs/type_inference_tests.clj

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,14 +403,11 @@
403403
(:require [goog.string :as gstring]))
404404
(gstring/contains "foobar" "foo")]
405405
{} true)))))
406-
;; FIXME: infers any instead of boolean, nothing wrong w/ the externs parsing
407-
;; but this definitely does not work at the moment
408-
#_(is (= 'boolean
406+
(is (= 'boolean
409407
(:tag
410408
(env/with-compiler-env (env/default-compiler-env)
411409
(ana/analyze-form-seq
412410
'[(ns test.foo
413411
(:require [goog.object :as gobject]))
414412
(gobject/containsKey (js-object) "foo")]
415413
{} true))))))
416-

0 commit comments

Comments
 (0)