ClojureScript

Metadata on function literal inside of a let produces invalid Javascript

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: 1.7.145
  • Fix Version/s: 1.9.671
  • Component/s: None
  • Labels:
  • Environment:
    Originally found with [org.clojure/clojurescript "0.0-2496"]
    Still reproducible with the latest cljsc (b5e9a5116259fc9f201bee4b9c6564f35306f9a5)

Description

Here is a minimal test case that produces the invalid Javascript:

(defn f []
  (let [a 0]
    ^{"meta" "data"}
    (fn [] true)))

The compiled Javascript includes the invalid token sequence "return return". (Per Chrome: Uncaught SyntaxError: Unexpected token return)

The problem does not occur if the metadata applies to a map literal instead of a function literal.
The problem only occurs when the function and metadata are inside of a let.

Activity

Hide
Bobby Eickhoff added a comment -

I forgot to try with-meta. Using with-meta does not produce this syntax error, so it's only a problem with the reader macro for metadata.

Show
Bobby Eickhoff added a comment - I forgot to try with-meta. Using with-meta does not produce this syntax error, so it's only a problem with the reader macro for metadata.
Hide
David Nolen added a comment - - edited

Any quick thoughts about this one Nicola? Quite possibly a compiler issue on the CLJS side.

Show
David Nolen added a comment - - edited Any quick thoughts about this one Nicola? Quite possibly a compiler issue on the CLJS side.
Hide
Nicola Mometto added a comment -

David, I understand why this happens but I don't know enough about how cljs's js emission to propose a fix.
The issue is that with this commit: https://github.com/clojure/clojurescript/commit/d54defd32d6c5ffcf6b0698072184fe8ccecc93a the following scenario is possible:

{:op :meta
 :env {:context :return}
 :expr {:op :fn
        :env {:context :expr}
        :methods [{:op :fn-method 
                   :env {:context :return} ..}]
        ..}
 ..}

i.e. analyze-wrap-meta changes the context of the :fn node to :expr but keeps the context of the :fn-methods to :return.

This causes both
https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/compiler.clj#L575-L576
and
https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/compiler.clj#L488 (https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/compiler.clj#L233)

to be true and emit a "return".

Show
Nicola Mometto added a comment - David, I understand why this happens but I don't know enough about how cljs's js emission to propose a fix. The issue is that with this commit: https://github.com/clojure/clojurescript/commit/d54defd32d6c5ffcf6b0698072184fe8ccecc93a the following scenario is possible:
{:op :meta
 :env {:context :return}
 :expr {:op :fn
        :env {:context :expr}
        :methods [{:op :fn-method 
                   :env {:context :return} ..}]
        ..}
 ..}
i.e. analyze-wrap-meta changes the context of the :fn node to :expr but keeps the context of the :fn-methods to :return. This causes both https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/compiler.clj#L575-L576 and https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/compiler.clj#L488 (https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/compiler.clj#L233) to be true and emit a "return".
Hide
David Nolen added a comment -

Hrm, it appears analyze-wrap-meta may need to defer to a helper to change the :context of the given AST node.

Show
David Nolen added a comment - Hrm, it appears analyze-wrap-meta may need to defer to a helper to change the :context of the given AST node.
Hide
Herwig Hochleitner added a comment -

I just randomly ran into this, when upgrading an old project. There is also a duplicate already: http://dev.clojure.org/jira/browse/CLJS-1482

Show
Herwig Hochleitner added a comment - I just randomly ran into this, when upgrading an old project. There is also a duplicate already: http://dev.clojure.org/jira/browse/CLJS-1482
Hide
Jonathan Chu added a comment -

This issue occurs for me even without a let.

(fn []
  ^{"meta" "data"}
  (fn [] true))

gives me

#object[SyntaxError SyntaxError: Unexpected token return]
Show
Jonathan Chu added a comment - This issue occurs for me even without a let.
(fn []
  ^{"meta" "data"}
  (fn [] true))
gives me
#object[SyntaxError SyntaxError: Unexpected token return]

People

Vote (2)
Watch (1)

Dates

  • Created:
    Updated: