请在2024 Clojure状态调查!中分享您的想法。

欢迎!有关这些信息如何运作的详细信息,请参阅关于页面。

+1
错误

使用不存在的命名空间定义变量将导致此错误

user> (def foo/bar 1) 编译错误:在(REPL:1:1)编译def时出现语法错误。无法在当前命名空间外创建定义

原因:如果限定变量中的命名空间尚不存在,编译器的lookupVar()方法将返回null。

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

补丁:clj-1400-4.diff

审阅者:Alex Miller

14 个答案

0

评论由:scottbale

在我看来,这似乎是相对容易解决的问题,除非我遗漏了什么;自己负责。

0

评论由:scottbale

Patch {{clj-1400-1.diff}} to {{Compiler.java}}.

使用此补丁,示例现在将如下所示

user> (def foo/bar 1) CompilerException java.lang.RuntimeException: Qualified symbol foo/bar refers to nonexistent namespace: foo, compiling:(NO_SOURCE_PATH:1:1)

我不确定{{if(namesStaticMember(sym))}} (link: see below)和第2个分支是否甚至有必要。仅通过检查,我怀疑它不是。

(link: 脚注)

`
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,在Clojure在2014年8月29日进行了某些提交后,不再干净地应用到最新的master分支中。在那之前它是可以干净应用的。

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

0

评论由:scottbale

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

0

评论者:alexmiller

有几个评论要处理
- 编译器差异使用了空格而不是制表符,这使得差异比较更加困难。我附上一个-3.diff文件来修复这个问题。
- namesStaticMember的调用看起来很奇怪。这个方法的名称对于这种用途来说很晦涩。除此之外,我认为它做了你不需要的事情。这个方法将会尝试通过当前ns解析限定名,但我认为你甚至都不需要这样做。你只想要知道sym是否有ns(sym.ns != null)-这不就是足够了吗?
- 在什么情况下会发生其他错误“变量不存在”?换句话说,在什么情况下lookupVar不会在这里创建一个新的变量?如果没有这样的情况,那么就删除这个案例。如果有这样的情况,那么添加一个测试。

0

评论由:scottbale

完全同意您的三个要点。附上更新后的补丁,clj-1400-4.diff。
我在 Compiler.java 中使用了制表符
仔细检查了 lookupVar(...) 的调用后,我相信只有在 exactly this ticket 的情况下才会返回 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: Qualified symbol foo/bar refers to nonexistent namespace: foo, compiling:(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}} 参数不可用,或者至少据我所知是这样。

0

评论者:alexmiller

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

0

评论者:alexmiller

截至 Clojure 1.10,已更新错误结果。现在它在抛出错误时也会抛出带有文件/行/列的 :compile-syntax 错误阶段异常。

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