2024 Clojure 状况调查!中分享你的想法。

欢迎!请查看关于页面以了解更多的关于这的工作方式信息。

0投票
Clojure
已关闭

问题
当进行java调用(或内联函数),如果参数和参数都是原始类型,不会使用宽泛转换来定位合适的重载方法/构造函数。

示例

`user=> (Integer. (byte 0))
java.lang.IllegalArgumentException: 没有找到匹配的构造器用于类 java.lang.Integer (NO_SOURCE_FILE:0)

上面发生是因为没有 Integer(byte) 构造器,尽管它应该与 Integer(int) 匹配。

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:
Explicitly casting to the formal type. Ancillary benefits of fixing:
It would also reduce the amount of method overloading, e.g., RT.intCast(char), intCast(byte), intCast(short), could all be removed, since such calls would pass to RT.intCast(int).
在备注中标为已关闭: 作为 CLJ-2843 1.11.3 和 1.12.0-alpha10 的副作用而得到修复

26 答案

0投票

评论由:importer 制作

ataggart 说:(链接: [文件:b6gDSUZOur36b9eJe5cbCb)])

0投票

评论由:importer 制作

ataggart 说:同时也修复了 #446。

0投票

评论者:stu

补丁导致测试失败

`

 [java] Exception in thread "main" java.lang.IllegalArgumentException: 
 More than one matching method found: equiv, compiling:(clojure/pprint/cl_format.clj:428)

`

你能看看吗?

0投票

评论者:stu

失败的测试发生在尝试找到签名 {{(Number, long)}} 的正确等价物时。编译器提出这个签名是错误的,还是解析方法在未给出答案时是错误的?(它认为两个签名绑定:{{(Object, long)}} 和 {{(Number, Number)}}。)

`
主线程中发生异常 "main" java.lang.IllegalArgumentException: 找到多个匹配的方法:equiv,编译:(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)

原因:java.lang.IllegalArgumentException: 找到多个匹配的方法: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

`

0投票

评论者:ataggart

在实施 vararg 方法支持的过程中,我发现先前的解决方案存在许多缺陷。请忽略它们。

我已经附加了一个补丁(reflector-compiler-numbers.diff),这个补丁是对 Reflector 代码的重大 overhaul,同时也增强了 Compiler 和 Numbers 代码的一些功能。

补丁说明

  • 将从 Compiler 中移除反射功能到 Reflector。
  • Reflector 支持通过拓宽转换、装箱转换和强制类型转换查找重载的方法。
  • 在编译过程中,Reflector 尝试找到最佳通配符匹配。
  • 在反射调用方法和构造函数时,Reflector 使用 *。
  • Reflector 和 Compiler 都支持可变参数的 Java 方法和构造函数;向后兼容通过传递数组或 nil 到可变参数槽中。
  • 向 Reflector 添加了更多有用的错误消息。
  • 向 clojure.test-clojure.reflector 添加了测试。
  • 修改了 clojure.lang.Numbers 的重载函数以服务于 Object/double/long 参数;修复了一些歧义问题并避免在某些情况下不必要的装箱。
  • 补丁解决了问题 380、440、445、666,以及可能的问题 259(提供的信息不够详细)。
0投票

评论者:ataggart

更新补丁以修复一个错误,即当存在多个相同名称的方法(例如,一个来自接口,另一个来自抽象类)的 konkret 类时,会导致歧义。现在通过任意选择解决(原始代码也是这样做的,尽管并没有明确说明)。

0投票

评论者:ataggart

更新补丁以与最新主分支兼容。

0投票

评论者:stu

补丁似乎缺少测试文件 clojure/test_clojure/reflector.clj。

0投票

评论者:ataggart

通过git源码做了修改。

修复后的补丁现在包含 clojure.test-clojure.reflector。

0投票

评论者:stu

Rich:我已验证补丁已应用,但只是简要地审查了它,因为我知道您会想仔细研读这个。

0投票

评论者:stu

应用此补丁后,我遇到了方法缺失错误

java.lang.NoSuchMethodError: clojure.lang.Numbers.lt(JLjava/lang/Object;)

但仅在编译代码时才会出现,例如,相同的代码在REPL中工作正常,编译后会失败。尚未能隔离一个可以在此分享的例子,但希望这能引起某个人的“啊哈”时刻...

0投票

评论者:ataggart

该补丁现在只包含支持扩展转换所需的最小更改。清理 Numbers 重载等可以稍后再进行。vararg 支持 在 CLJ-440 的单独补丁中。

0投票
by

评论者:redinger

请测试补丁

0投票
by

评论者:redinger

通知:补丁在master分支上应用正常,截至4/21(2011年)所有测试通过

...