像这样的表达式会导致nil,但应该编译失败
(let (link: ) do)
像这样的表达式会导致nil,但应该产生一个值
(let (link: do 1) do)
这适用于所有具有“隐式do”的特殊形式:try/catch/finally、letfn、let以及fn**/reify/deftype系列形式。
对这些特殊形式实现“隐式do”的方式是,相关的解析器会明确地将体表达式委派给BodyExpr.Parser。例如:
(let (link: x 1) (println x) x)
调用BodyExpr.Parser.parse()时使用列表 '((println x) x)。然而,BodyExpr.Parser还用于解析列表((do (println x) x)),在其他上下文中。为了处理这两种情况,它的parse()方法会跳过其第一个形式,如果这个形式是'm符号'。所以,如果一个具有“隐式do”的特殊形式的第一个表达式是裸符号'do',这个符号就会错误地被丢弃。
所附补丁通过在每个这样的特殊形式之前实际上插入一个显式的'do'来修复此问题,这样BodyExpr.Parser就可以无条件地假设其第一个形式是'do',然后跳过它。BodyExpr现在在这不是情况下会抛出异常,因为这表明编译器中存在错误 - 用户代码不能创建这种情况。
附加的补丁对编译时间的影响最小:它为每个具有隐式do的表达式的分析引入了一个额外的方法调用和一个额外的cons单元分配。它不会对生成的代码产生影响(除了修正本票项开头指出的错误)。
包含三个测试,补丁之前失败,补丁之后成功。