此补丁更改了与宏一起使用时的元数据的行为。元数据 &form 现在会与宏调用 sexpr 的元数据合并。这使得用户可以在宏调用中对内部或外部形式进行类型提示并获得更好的结果。在过去,宏展开的元数据是直接使用的。这不允许像下面这样的代码在没有反射的情况下工作
(.trim ^String (when true "hello "))
补丁: 2013-10-11_CLJ-865_Fix-With-Tests.diff
审核: Timothy Baldridge
--------- 实现细节 ----------
如http://groups.google.com/group/clojure/browse_thread/thread/2690cb6ca0e8beb8 中讨论的,当类型提示代表宏的表达式时,如 (.length ^String (doto (identity "x") prn)),存在一个"惊喜因素"。在这里,doto 宏丢弃了 &form 的元数据,导致反射查找。这使得代表函数调用的表达式可以类型提示,而代表宏的一般表达式不能。doto 宏可以重写以尊重其 &form 元数据,但为现有每个宏这样做将是繁重和易出错的。相反,我提议对编译器进行更改,以便宏展开自动保留元数据。
附加的第一个补丁为此提议的行为添加了一个测试:此测试失败。应用第二个补丁后,测试通过。
在接受我的补丁之前,有几个问题需要进一步考虑
- 我不确定我是否正确地格式化了 Java 代码。我的编辑器未正确配置为自动获取 clojure/core 样式。
- 我的解决方案是获取 &form 元数据,删除 :line/:file 键,然后将其与返回的元数据合并,其中 &form 优先。我不确定这在所有情况下是否是正确的方法,尽管它在 :tag 元数据中有效。
- 我通过更改编译器实现了这一点,这使得它相当重量级。应该有可能通过调整 defmacro 来实现,而不是更改编译器(如果不愿更改编译器)。然而,我认为这将涉及更多的工作并更难测试(例如,多arity 会使问题复杂化)。将宏展开视为黑盒然后修改结果元数据似乎更合适,而不是修改它们的实际 defmacro 代码。
- 如果宏展开为非 IObj 的内容,例如 Integer,那么我的补丁默默地丢弃了调用者的元数据。抛出异常会不会更好?