2024 Clojure状态调查(调查)中分享您的想法!

欢迎!请查阅关于页面,了解这个功能的更多信息。

+1 投票
错误

定义不存在命名空间中的变量的定义将产生此错误

user> (def foo/bar 1) 编译错误在 def 编译时(REPL:1:1)。不能在当前命名空间之外创建定义。

原因:当合格变量中的命名空间不存在时,Compiler lookupVar() 返回 null。

建议:通过命名符号并抛出包含文件/行/列信息的 CompilerException,错误信息将被改进。这并不明显,但可能这是唯一发生此类错误的情况。如果是这样,错误信息可以更具体地说明命名空间部分不存在。

补丁:clj-1400-4.diff

审核:Alex Miller

14 个答案

0 投票

评论者:scottbale

在我看来,这似乎是相对简单易行的事情,除非我遗漏了什么;我来处理。

0 投票

评论者:scottbale

将补丁 {{clj-1400-1.diff}} 应用到 {{Compiler.java}}。

使用此补丁,示例现在将呈现为

user> (def foo/bar 1) CompilerException java.lang.RuntimeException: 合格符号 foo/bar 指向不存在的命名空间:foo,正在编译:(NO_SOURCE_PATH:1:1)

我不确定 {{if(namesStaticMember(sym))}}(链接:见下文),以及第二个分支,是否必要。仅凭观察,我怀疑它们可能是不必要的。

(链接:脚注)

`
public static boolean namesStaticMember(Symbol sym){

return sym.ns != null && namespaceFor(sym) == null;

}
`

0 投票

评论者:scottbale

补丁:代码和测试

0 投票

评论者:scottbale

我在源文件上进行了测试,异常信息含有了预期的文件/行/列信息

user=> CompilerException java.lang.RuntimeException: 有资格的符号 goo/bar 引用了不存在的命名空间:goo, 编译:(/home/scott/dev/foo.clj:3:1)

0 投票

评论人:jafingerhut

2014年6月26日创建的补丁clj-1400-1.diff在2014年8月29日Clojure提交了一些更新后,已无法干净地应用到最新master分支。在那之前它可以干净地应用。

我没有检查更新这个补丁的难易程度。请参阅本页面的“更新过时补丁”部分,以获取一些关于更新补丁的提示:http://dev.clojure.org/display/community/Developing Patches

0 投票

评论者:scottbale

附上了更新后的补丁:“clj-1400-2.diff”。我已经删除了过时的补丁。

0 投票

评论人:alexmiller

有一些评论要处理
- 编译器diff使用的是空格,而不是制表符,这使得它更难比较。我附上了-3.diff修复了这个问题。
- namesStaticMember的调用看起来很奇怪。这个方法的名称对这个用途来说很令人困惑。除此之外,我认为它做的比所需的更多。这个方法将会尝试根据当前ns来解析有资格的名称,但我认为你甚至不需要这样做。你只需要知道sym是否有ns(sym.ns != null)- 这不是足够了吗?
- 在什么情况下将发生其他错误“未找到变量”?换句话说,在什么情况下lookupVar不会在这里创建一个新的变量?如果没有这种情况,则删除此情况。如果有这种情况,则添加一个测试。

0 投票

评论者:scottbale

同意您提到的三个要点。附上了更新的补丁,clj-1400-4.diff。
我在Compiler.java中使用了制表符
在仔细检查了lookupVar(...的调用之后,我认为仅在当前这个票据的情况下才返回null(符号有一个非null的尚未加载的命名空间)。因此,我移除了条件语句和第二个分支。
*(测试未改变)

0 投票

评论者:scottbale

(正确命名的补丁)

0 投票

评论人:alexmiller

您也可以根据票据描述抛出一个带有问题位置的CompilerException。

0 投票

评论者:scottbale

抱歉,我应该提到的,因为这对我来说也不明显(事实上我直到刚才才想起来):RuntimeException已经被捕获并封装在CompilerException中。

我不确定Compiler.java中的哪个try-catch块发生了这种情况,因为有几个。但您可以在输出中看到异常是CompilerException,并且有文件|行|列信息。

在Repl...

user> (def foo/bar 1) CompilerException java.lang.RuntimeException: 合格符号 foo/bar 指向不存在的命名空间:foo,正在编译:(NO_SOURCE_PATH:1:1)

...或在源文件中

user=> CompilerException java.lang.RuntimeException: 有资格的符号 goo/bar 引用了不存在的命名空间:goo, 编译:(/home/scott/dev/foo.clj:3:1)

另外,在抛出这个补丁的RuntimeException的点,CompilerException的source、line和col参数不可用,至少在afaict中不可用。

0 投票

评论人:alexmiller

我稍后会跟进这个补丁 - Rich认为它做了太多的假设。我认为我们验证了许多假设,但需要再次检查这些假设。

0 投票

评论人:alexmiller

截至 Clojure 1.10 更新错误结果。现在它正在抛出带有文件/行/列的编译语法错误阶段异常。

0 投票
参考: https://clojure.atlassian.net/browse/CLJ-1400(由 hlewisship 报告)
...