When you type hint a var such as:
(def ^{:tag 'long} k 100)
And refer to it in a let binding:
(let [i k]
(+ i 10))
The binding is unable to properly infer that it is a primitive type as it was hinted:
(set! *unchecked-math* :warn-on-boxed)
(def ^{:tag 'long} k 100)
(let [i k]
(+ i 10))
;;=> Boxed math warning, unchecked_add(java.lang.Object,long).
It looks like it might be caused by a bug in the Compiler where for some reason, the expression of the var k is marked as not having a java class, even though it has one:
(defmacro inspect-local []
(println
(into {}
(map (fn[[k v]]
[k {:tag (.-tag v)
:class (.getJavaClass v)
:primitive? (.isPrimitive (.getJavaClass v))
:has-java-class? (.hasJavaClass v)}]))
&env)))
(let [i k]
(inspect-local)
(+ i 10))
;;=> {i {:tag nil, :class long, :primitive? true, :has-java-class? false}}
As we can see, .hasJavaClass returns false, but .getJavaClass returns the Long/TYPE class.
I suspect that the compiler checks for .hasJavaClass before calling .getJavaClass, and since .hasJavaClass is erroneously false here, it would cause the compiler to think it isn't, and that the type can't be inferred.
I'm not too sure where in the Compiler this is, but I found the following: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L1341
Where we see the compiler is first checking for .hasJavaClass:
if(e instanceof MaybePrimitiveExpr && e.hasJavaClass() && ((MaybePrimitiveExpr)e).canEmitPrimitive())