ClojureScript

Warnings are generated when using a macro in argument position

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Minor Minor
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None

Description

Using a macro in argument position (e.g. (map macro [])) generates a warning:
WARNING: Use of undeclared Var test/node at line 4 src/test.cljs

Find a reproduction project here.

Activity

Hide
Jozef Wagner added a comment -

and what would you like, a better warning? Clojurescript allows same name for macro and for function, so you can both have macro + and fn +. Macro version will be used when is first in the list, fn version otherwise.

Show
Jozef Wagner added a comment - and what would you like, a better warning? Clojurescript allows same name for macro and for function, so you can both have macro + and fn +. Macro version will be used when is first in the list, fn version otherwise.
Hide
Jonas Enlund added a comment - - edited

For reference, Clojure generates the following error message:

user=> (map when [])
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/when, compiling:(NO_SOURCE_PATH:1:1)

The "obvious" approach would be to add

(when-let [m (get-expander sym env)]
  (throw (error env (str "Can’t take value of a macro: " m))))

to resolve-var[1]. Unfortunately this doesn’t work in ClojureScript due to the way inlining works. A simple workaround is to add {:inline true} metadata to macros that are later redefined as functions in core.cljs and check for invalid macro usage like this:

(when-let [m (get-expander sym env)]
  (and (-> m meta :inline not)    
       (throw (error env (str "Can’t take value of a macro: " m)))))

Another approach would perhaps be to rethink how inlining works as it seems kind of brittle to have macros in cljs/core.clj with the same name as functions in cljs/core.cljs (especially since both namespaces are auto-imported. Is cljs.core/inc a function, a macro, or both?). Maybe there’s a better way?

[1] https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/analyzer.clj#L193

Show
Jonas Enlund added a comment - - edited For reference, Clojure generates the following error message:
user=> (map when [])
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/when, compiling:(NO_SOURCE_PATH:1:1)
The "obvious" approach would be to add
(when-let [m (get-expander sym env)]
  (throw (error env (str "Can’t take value of a macro: " m))))
to resolve-var[1]. Unfortunately this doesn’t work in ClojureScript due to the way inlining works. A simple workaround is to add {:inline true} metadata to macros that are later redefined as functions in core.cljs and check for invalid macro usage like this:
(when-let [m (get-expander sym env)]
  (and (-> m meta :inline not)    
       (throw (error env (str "Can’t take value of a macro: " m)))))
Another approach would perhaps be to rethink how inlining works as it seems kind of brittle to have macros in cljs/core.clj with the same name as functions in cljs/core.cljs (especially since both namespaces are auto-imported. Is cljs.core/inc a function, a macro, or both?). Maybe there’s a better way? [1] https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/analyzer.clj#L193
Hide
Julien Eluard added a comment -

My bad, didn't realize it didn't make sense. Of course it's obvious now. I was confused by recent changes around function/macro name validation.
Now the warning could probably be improved a little but that doesn't seem very important. The Clojure warning is not that much better.

Show
Julien Eluard added a comment - My bad, didn't realize it didn't make sense. Of course it's obvious now. I was confused by recent changes around function/macro name validation. Now the warning could probably be improved a little but that doesn't seem very important. The Clojure warning is not that much better.
Hide
David Nolen added a comment -

We're not going to change how inlining works - the whole point is that we can reuse the same names. Adding :inline metadata seems like a promising way to warn of incorrect usage of inlining macros.

Show
David Nolen added a comment - We're not going to change how inlining works - the whole point is that we can reuse the same names. Adding :inline metadata seems like a promising way to warn of incorrect usage of inlining macros.

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated: