cljs-dev

ClojureScript compiler & std lib dev, https://clojurescript.org/community/dev
2019-08-17T17:32:12.152300Z

Is it a bug?

(when ^boolean (aget js/window "location")
  (js/console.log 1))
emits checked if
if(cljs.core.truth_((window["location"]))){
console.log((1));
} else {
}

mfikes 2019-08-17T21:02:36.153600Z

Man, on the surface, that does seem like a reasonable hint. It seems easy to support

diff --git a/src/main/clojure/cljs/analyzer.cljc b/src/main/clojure/cljs/analyzer.cljc
index e021b5e9..efe5f714 100644
--- a/src/main/clojure/cljs/analyzer.cljc
+++ b/src/main/clojure/cljs/analyzer.cljc
@@ -1647,7 +1647,9 @@
     (throw (compile-syntax-error env "Too few arguments to if" 'if)))
   (when (> (count form) 4)
     (throw (compile-syntax-error env "Too many arguments to if" 'if)))
-  (let [test-expr (disallowing-recur (analyze (assoc env :context :expr) test))
+  (let [test-tag (:tag (meta test))
+        test-expr (cond-> (disallowing-recur (analyze (assoc env :context :expr) test))
+                    test-tag (assoc :tag test-tag))
         then-expr (allowing-redef (analyze (set-test-induced-tags env test) then))
         else-expr (allowing-redef (analyze env else))]
     {:env env :op :if :form form

mfikes 2019-08-17T21:22:22.158600Z

I suspect the problem here is that if the test is a macro, it will get expanded, and, in the process, the tag is discarded. If you think about it, this probably couldn't be generally fixed with a revision to the macroexpansion logic because a macro could expand to some code that can't hold meta. So maybe it could indeed be deemed a corner case bug in the situation where hints on macro expressions evaporate. (And the change above really only fixes it for the if test case.)

2019-08-17T22:22:13.159600Z

Which sort of object in JS couldn’t hold meta? Just curious since it seems like everything in JS can be extended

mfikes 2019-08-17T23:50:32.162400Z

For the primitive types which couldn't hold meta without extending them to IMeta, it's probably a moot point anyway because the compiler can infer their types. But even for types that can hold meta, preserving meta through macroexpansion would differ from Clojure, which doesn't do that:

user=> (defmacro foo [] [])
#'user/foo
user=> (meta ^:bar (foo))
nil

1
✅ 1