<< Back to previous view

[TANAL-24] clojure.tools.analyzer.passes.jvm/validate throws an exception when :tag metadata cannot be resolved to a Class Created: 04/Dec/13  Updated: 09/Aug/14  Resolved: 09/Aug/14

Status: Closed
Project: tools.analyzer
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Andy Fingerhut Assignee: Nicola Mometto
Resolution: Completed Votes: 1
Labels: None


 Description   

While the Clojure Compiler silently ignores :tag metadata in some forms when it cannot be resolved to a class, c.t.a.passes.jvm/validate throws an exception every time.

Some libraries (test.generators) use :tag metadata to store instructions for generating test input data, those can be everything, from symbols to quoted clojure expressions – the Clojure Compiler allows for this but validate throws an exception.

Generally however, when :tag cannot be resolved to a class it's not beacause of a design choice, but because of a Clojure bug or a user-code bug.

Some examples are:

  • tagging a defn form in the fn name with a primitive type hint:
    user=> (defn ^long x [] 1)
    #'user/x
    user=> (:tag (meta #'x))
    #<core$long clojure.core$long@6596f6ef>
  • using extend-type with a run-time resolved class http://dev.clojure.org/jira/browse/CLJ-1308
    user=> (defprotocol p (f [_]))
    p
    user=> (binding [*print-meta* true] (pr (macroexpand-1 '(extend-type (class 1) p (f [_])))))
    (clojure.core/extend (class 1) p {:f (fn ([^(class 1) _]))})
    nil
  • type hinting a form in a namespace with an imported class doesn't qualify the class in :tag http://dev.clojure.org/jira/browse/CLJ-1232
    user=> (ns foo (:import clojure.lang.RT))
    nil
    foo=> (defn x ^RT [])
    #'foo/x
    foo=> (ns bar (:use foo))
    nil
    bar=> (:tag (meta #'x))
    RT
    bar=> (.hashCode (x))
    CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: RT, compiling:(NO_SOURCE_PATH:5:1)

A clojure-dev post has been opened asking whether tools.analyzer.jvm is correct in assuming that non class-resolvible tags are an error and thus an exception could be thrown, or if the current behaviour of the Cloure implementation of throwing in some special places and silently ignoring malformed :tag values is by design. It hasn't have received an official reply yet. https://groups.google.com/d/msg/clojure-dev/hRZFuaiB_50/mzKLirgZWmUJ



 Comments   
Comment by Nicola Mometto [ 05/Dec/13 9:23 AM ]

This is somewhat an undefined behaviour in clojure, it's not clear to me from the documentation wether tagging elements with things that cannot be resolved to a class should work or not.

I'll ask the clojure-dev ML about this before doing anything.

Thanks

Comment by Nicola Mometto [ 05/Dec/13 2:00 PM ]

clojure-dev post: https://groups.google.com/d/msg/clojure-dev/hRZFuaiB_50/mzKLirgZWmUJ

Comment by Andy Fingerhut [ 02/Apr/14 1:24 PM ]

Ticket TGEN-5 was created on test.generative as a result of this issue, too, with a suggested patch so that test.generative no longer 'leaks' such tag values.

Comment by Nicola Mometto [ 09/Aug/14 10:10 AM ]

A workaround is now available in tools.analyzer.jvm master, the default behaviour is still to throw on "wrong" tags but it's now available a wrong-tag handler that allows user to customize the behaviour of the validate pass on wrong tags.
PoC: https://github.com/clojure/tools.analyzer.jvm/blob/master/src/test/clojure/clojure/tools/analyzer/jvm/passes_test.clj#L209-L216

Generated at Sat Oct 25 02:16:23 CDT 2014 using JIRA 4.4#649-r158309.