Welcome! Please see the About page for a little more info on how this works.

0 votes
in Compiler by

The use of macroexpand on short class name symbols triggers a RuntimeException.

`
user=> (import 'java.net.URI)
java.net.URI
user=> (macroexpand '(java.net.URI "http://google.com")) ;; fine
(java.net.URI "http://google.com")
user=> (macroexpand '(URI "http://google.com")) ;; huh?
java.lang.RuntimeException: Expecting var, but URI is mapped to class java.net.URI
user=> (pst *e)
RuntimeException Expecting var, but URI is mapped to class java.net.URI

clojure.lang.Util.runtimeException (Util.java:221)
clojure.lang.Compiler.lookupVar (Compiler.java:7092)
clojure.lang.Compiler.isMacro (Compiler.java:6571)
clojure.lang.Compiler.macroexpand1 (Compiler.java:6626)
clojure.core/macroexpand-1 (core.clj:3870)
clojure.core/macroexpand (core.clj:3879)

`

Neither of these should throw an error during macroexpansion (basically should be same after expansion. Both should throw the same error when evaluated (ClassCast trying to invoke a Class as an IFn).

Approach: Throw the runtime error in lookupVar only if internNew is true. In that case we unexpectedly found something other than a var and should still report. Otherwise, just let lookupVar flow through to return a null (no var found.

2 Answers

0 votes
by

Comment made by: alexmiller

The compiler is trying to determine if the thing in function position is a var that is a macro that requires expansion in Compiler.isMacro().

In the case of (java.net.URI "http://google.com"), lookupVar determines that java.net.URI is an unmapped symbol and does nothing, meaning no expansion is necessary (this of course will fail at evaluation time with "ClassCastException java.lang.Class cannot be cast to clojure.lang.IFn").

In the case of (URI "http://google.com"), lookupVar finds a symbol mapped to something that's not a var and throws the RuntimeException that is seen.

I would expect that neither of these should throw an error during macroexpansion (basically the same thing they start as) and that both should throw the same error when evaluated. Attaching a patch that will only throw the error if internNew - in that case you unexpectedly found something other than a var and you should still report (otherwise, just return null - lookupVar didn't find a var).

The internNew case comes up with:

(import java.net.URI) (def URI "abc") ;; java.lang.RuntimeException: Expecting var, but URI is mapped to class java.net.URI

with the patch:

user=> (macroexpand '(java.net.URI "http://google.com")) (java.net.URI "http://google.com") user=> (macroexpand '(URI "http://google.com")) (URI "http://google.com") user=> (java.net.URI "http://google.com") ClassCastException java.lang.Class cannot be cast to clojure.lang.IFn user/eval9 (NO_SOURCE_FILE:6) user=> (URI "http://google.com") ClassCastException java.lang.Class cannot be cast to clojure.lang.IFn user/eval11 (NO_SOURCE_FILE:7)

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-1759 (reported by venantius)
...