此补丁更改了与宏一起使用时元数据的行为。现在元数据 &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 而不是更改编译器来实现,但这需要更多的工作并且更难以测试(例如,多参数会使事情变得复杂)。将宏展开视为黑盒并与结果进行元数据微调似乎更简单,而不是实际修改它们的 defmacro 代码。
- 如果宏展开成为一个不是 IObj 的东西,例如 Integer,那么我的补丁会静默地丢弃调用者的元数据。抛出异常是否更好?