[CLJ-445] Method/Constructor resolution does not factor in widening conversion of primitive args Created: 29/Sep/10 Updated: 20/Feb/12 |
|
| Status: | In Progress |
| Project: | Clojure |
| Component/s: | None |
| Affects Version/s: | None |
| Fix Version/s: | Reviewed Backlog |
| Type: | Enhancement | Priority: | Major |
| Reporter: | Alexander Taggart | Assignee: | Alexander Taggart |
| Resolution: | Unresolved | Votes: | 2 |
| Labels: | None | ||
| Attachments: |
|
| Approval: | Incomplete |
| Description |
|
Problem: Examples: user=> (Integer. (byte 0)) java.lang.IllegalArgumentException: No matching ctor found for class java.lang.Integer (NO_SOURCE_FILE:0) </code></pre> The above occurs because there is no Integer(byte) constructor, though it should match on Integer(int). <pre><code>user=> (bit-shift-left (byte 1) 1) Reflection warning, NO_SOURCE_PATH:3 - call to shiftLeft can't be resolved. 2 In the above, a call is made via reflection to Numbers.shiftLeft(Object, Object) and its associated auto-boxing, instead of directly to the perfectly adequate Numbers.shiftLeft(long, int). Workarounds: Ancillary benefits of fixing: |
| Comments |
| Comment by Assembla Importer [ 23/Oct/10 6:43 PM ] |
|
Converted from http://www.assembla.com/spaces/clojure/tickets/445 |
| Comment by Assembla Importer [ 23/Oct/10 6:43 PM ] |
|
ataggart said: [file:b6gDSUZOur36b9eJe5cbCb] |
| Comment by Assembla Importer [ 23/Oct/10 6:43 PM ] |
|
ataggart said: Also fixes #446. |
| Comment by Stuart Halloway [ 03/Dec/10 12:50 PM ] |
|
The patch is causing a test failure [java] Exception in thread "main" java.lang.IllegalArgumentException:
More than one matching method found: equiv, compiling:(clojure/pprint/cl_format.clj:428)
Can you take a look? |
| Comment by Stuart Halloway [ 28/Jan/11 12:30 PM ] |
|
The failing test happens when trying to find the correct equiv for signature (Number, long). Is the compiler wrong to propose this signature, or is the resolution method wrong in not having an answer? (It thinks two signatures are tied: (Object, long) and (Number, Number).) Exception in thread "main" java.lang.IllegalArgumentException: More than one matching method found: equiv, compiling:(clojure/pprint/cl_format.clj:428) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6062) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6050) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.access$100(Compiler.java:35) at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:5492) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6055) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6043) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6043) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler$IfExpr$Parser.parse(Compiler.java:2372) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6055) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6043) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3277) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6057) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5231) at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:5527) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6055) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6043) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5231) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6055) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler$IfExpr$Parser.parse(Compiler.java:2385) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6055) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5231) at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:5527) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6055) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6043) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler$IfExpr$Parser.parse(Compiler.java:2385) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6055) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5231) at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:5527) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6055) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6043) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5231) at clojure.lang.Compiler$FnMethod.parse(Compiler.java:4667) at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3397) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6053) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6043) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.access$100(Compiler.java:35) at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:480) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6055) at clojure.lang.Compiler.analyze(Compiler.java:5866) at clojure.lang.Compiler.analyze(Compiler.java:5827) at clojure.lang.Compiler.eval(Compiler.java:6114) at clojure.lang.Compiler.load(Compiler.java:6545) at clojure.lang.RT.loadResourceScript(RT.java:340) at clojure.lang.RT.loadResourceScript(RT.java:331) at clojure.lang.RT.load(RT.java:409) at clojure.lang.RT.load(RT.java:381) at clojure.core$load$fn__1427.invoke(core.clj:5308) at clojure.core$load.doInvoke(core.clj:5307) at clojure.lang.RestFn.invoke(RestFn.java:409) at clojure.pprint$eval3969.invoke(pprint.clj:46) at clojure.lang.Compiler.eval(Compiler.java:6110) at clojure.lang.Compiler.load(Compiler.java:6545) at clojure.lang.RT.loadResourceScript(RT.java:340) at clojure.lang.RT.loadResourceScript(RT.java:331) at clojure.lang.RT.load(RT.java:409) at clojure.lang.RT.load(RT.java:381) at clojure.core$load$fn__1427.invoke(core.clj:5308) at clojure.core$load.doInvoke(core.clj:5307) at clojure.lang.RestFn.invoke(RestFn.java:409) at clojure.core$load_one.invoke(core.clj:5132) at clojure.core$load_lib.doInvoke(core.clj:5169) at clojure.lang.RestFn.applyTo(RestFn.java:143) at sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:77) at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:28) at clojure.core$apply.invoke(core.clj:602) at clojure.core$load_libs.doInvoke(core.clj:5203) at clojure.lang.RestFn.applyTo(RestFn.java:138) at sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:77) at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:28) at clojure.core$apply.invoke(core.clj:604) at clojure.core$use.doInvoke(core.clj:5283) at clojure.lang.RestFn.invoke(RestFn.java:409) at clojure.main$repl.doInvoke(main.clj:196) at clojure.lang.RestFn.invoke(RestFn.java:422) at clojure.main$repl_opt.invoke(main.clj:267) at clojure.main$main.doInvoke(main.clj:362) at clojure.lang.RestFn.invoke(RestFn.java:409) at clojure.lang.Var.invoke(Var.java:401) at clojure.lang.AFn.applyToHelper(AFn.java:163) at clojure.lang.Var.applyTo(Var.java:518) at clojure.main.main(main.java:37) Caused by: java.lang.IllegalArgumentException: More than one matching method found: equiv at clojure.lang.Reflector.getMatchingParams(Reflector.java:639) at clojure.lang.Reflector.getMatchingParams(Reflector.java:578) at clojure.lang.Reflector.getMatchingMethod(Reflector.java:569) at clojure.lang.Compiler$StaticMethodExpr.<init>(Compiler.java:1439) at clojure.lang.Compiler$HostExpr$Parser.parse(Compiler.java:896) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6055) ... 115 more |
| Comment by Alexander Taggart [ 08/Feb/11 6:27 PM ] |
|
In working on implementing support for vararg methods, I found a number of flaws with the previous solutions. Please disregard them. I've attached a single patch (reflector-compiler-numbers.diff) which is a rather substantial overhaul of the Reflector code, with some enhancements to the Compiler and Numbers code. The patch notes:
|
| Comment by Alexander Taggart [ 10/Feb/11 7:35 PM ] |
|
Updated patch to fix a bug where a concrete class with multiple identical Methods (e.g., one from an interface, another from an abstract class) would result in ambiguity. Now resolved by arbitrary selection (this is what the original code did as well albeit not explicitly). |
| Comment by Alexander Taggart [ 25/Feb/11 9:29 PM ] |
|
Updated patch to work with latest master branch. |
| Comment by Stuart Halloway [ 06/Mar/11 1:54 PM ] |
|
patch appears to be missing test file clojure/test_clojure/reflector.clj. |
| Comment by Alexander Taggart [ 06/Mar/11 2:39 PM ] |
|
Bit by git. Patch corrected to contain clojure.test-clojure.reflector. |
| Comment by Stuart Halloway [ 11/Mar/11 10:30 AM ] |
|
Rich: I verified that the patch applied but reviewed only briefly, knowing you will want to go over this one closely. |
| Comment by Stuart Halloway [ 11/Mar/11 10:55 AM ] |
|
After applying this patch, I am getting method missing errors: java.lang.NoSuchMethodError: clojure.lang.Numbers.lt(JLjava/lang/Object;)
but only when using compiled code, e.g. the same code works in the REPL and then fails after compilation. Haven't been able to isolate an example that I can share here yet, but hoping this will cause someone to have an "a, hah" moment... |
| Comment by Alexander Taggart [ 02/Apr/11 12:55 PM ] |
|
The patch now contains only the minimal changes needed to support widening conversion. Cleanup of Numbers overloads, etc., can wait until this patch gets applied. The vararg support is in a separate patch on CLJ-440. |
| Comment by Christopher Redinger [ 15/Apr/11 12:50 PM ] |
|
Please test patch |
| Comment by Christopher Redinger [ 21/Apr/11 11:02 AM ] |
|
FYI: Patch applies cleanly on master and all tests pass as of 4/21 (2011) |
| Comment by Christopher Redinger [ 22/Apr/11 9:57 AM ] |
|
This work is too big to take into the 1.3 beta right now. We'll revisit for a future release. |
| Comment by Alexander Taggart [ 28/Apr/11 1:19 PM ] |
|
To better facilitate understanding of the changes, I've broken them up into two patches, each with a number of isolable, incremental commits: reorg-reflector.patch: Moves the reflection/invocation code from Compiler to Reflector, and eliminates redundant code. The result is a single code base for resolving methods/constructors, which will allow for altering that mechanism without excess external coordination. This contains no behaviour changes. prim-conversion.patch: Depends on the above. Alters the method/constructor resolution process:
This also provides a base to add further features, e.g., CLJ-666. |
| Comment by Alexander Taggart [ 29/Apr/11 3:01 PM ] |
|
It's documented in situ, but here are the conversion rules that the reflector uses to find methods:
|
| Comment by Alexander Taggart [ 10/May/11 3:13 PM ] |
|
prim-conversion-update-1.patch applies to current master. |
| Comment by Alexander Taggart [ 11/May/11 2:15 PM ] |
|
Created CLJ-792 for the reflector reorg. |
| Comment by Stuart Sierra [ 17/Feb/12 2:29 PM ] |
|
prim-conversion-update-1.patch does not apply as of f5bcf64. Is CLJ-792 now a prerequisite of this ticket? |
| Comment by Alexander Taggart [ 17/Feb/12 3:15 PM ] |
|
Yes, after the original patch was deemed "too big". After this much time with no action from TPTB, feel free to kill both tickets. |
| Comment by Andy Fingerhut [ 20/Feb/12 2:04 PM ] |
|
Again, not sure if this is any help, but I've tested starting from Clojure head as of Feb 20, 2012, applying clj-792-reorg-reflector-patch2.txt attached to CLJ-792, and then applying clj-445-prim-conversion-update-2-patch.txt attached to this ticket, and the result compiles and passes all but 2 tests. I don't know whether those failures are easy to fix or not, or whether issues may have been introduced with these patches. |