分享您的想法,请参加 2024 Clojure 状态调查!

欢迎!请参阅关于页面了解有关此内容的更多信息。

+1
编译器

在短类名符号上使用 macroexpand 会触发 RuntimeException。

`
user=> (import 'java.net.URI)
java.net.URI
user=> (macroexpand '(java.net.URI "http://google.com")) ;; 这是正常的
(java.net.URI "http://google.com")
user=> (macroexpand '(URI "http://google.com")) ;; 嘿?
java.lang.RuntimeException: 期望 var,但 URI 映射到类 java.net.URI
user=> (pst *e)
RuntimeException 期望 var,但 URI 映射到类 java.net.URI

clojure.lang.Util.runtimeException (Util.java:221)
clojure.lang.Compiler.lookupVar (Compiler.java:7092)
clojure.lang.Compiler.isMacro (Compiler.java:6571)
clojure.lang.Compiler.macroexpand1 (Compiler.java:6626)
clojure.core/macroexpand-1 (core.clj:3870)
clojure.core/macroexpand (core.clj:3879)

`

这两个在宏展开期间都不应该抛出错误(基本上在展开后应该是相同的。两者在评估时应抛出相同的错误(ClassCast 将类作为 IFn 来调用)。

方法: 只有在 internNew 为 true 时,才在 lookupVar 中抛出运行时错误。在这种情况下,我们意外地发现除了 var 以外的东西,应该仍然报告。否则,只需让 lookupVar 通过并返回 null(没有找到 var)。

2 答案

0

评论由:alexmiller 提出

编译器正在尝试确定函数位置中的“东西”是否是宏 var 需要在 Compiler.isMacro() 中展开。

在 (java.net.URI "http://google.com") 的情况下,lookupVar 确定java.net.URI 是一个未映射的符号,不进行任何操作,这意味着没有必要进行展开(当然,这将失败于评估时间,抛出 "ClassCastException java.lang.Class cannot be cast to clojure.lang.IFn")。

在 (URI "http://google.com") 的情况下,lookupVar 找到一个映射到不是 var 的符号,抛出我们看到的 RuntimeException。

我预计在宏展开期间这两个都不会抛出错误(基本上与它们开始时的内容相同),并且在评估时应该抛出相同的错误。附上一个补丁,它只有在internNew(在这种情况下,你意外地发现了一些不是var的东西,你应该仍然报告——否则,只返回null——lookupVar没有找到var)时才会抛出错误。

internNew的情况如下

(import java.net.URI) (def URI "abc") ;; java.lang.RuntimeException: 期望var,但URI映射到了类java.net.URI

使用补丁

user=> (macroexpand '(java.net.URI "http://google.com")) (java.net.URI "http://google.com") user=> (macroexpand '(URI "http://google.com")) (URI "http://google.com") user=> (java.net.URI "http://google.com") ClassCastException java.lang.Class无法被转换为clojure.lang.IFn user/eval9 (NO_SOURCE_FILE:6) user=> (URI "http://google.com") ClassCastException java.lang.Class无法被转换为clojure.lang.IFn user/eval11 (NO_SOURCE_FILE:7)

0
by
参考:https://clojure.atlassian.net/browse/CLJ-1759(由venantius报告)
...