类似于这样的表达式结果为 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() 方法将跳过其第一个形式,如果该形式是符号 'do'。因此,如果带有“隐式 do”的特殊形式的第一个表达式是裸符号 'do',则该符号会被错误地丢弃。
附带的补丁通过在委派之前在实际的每个此类特殊形式中插入显式的 'do' 来修复此问题,这样 BodyExpr.Parser 就可以无条件地假定其第一个形式是 'do' 并跳过它。现在 BodyExpr 如果发现这种情况不是这样,将会抛出异常,因为这表明编译器存在错误 - 用户代码无法创建这种情况。
附带的补丁对编译时间的影响最小:它在每个隐式 do 表达式的分析中引入了一个额外的方法调用和一个额外的列表分配。它将对生成的代码没有影响(除了修复本票件开头指示的错误)。
包含三个测试,这些测试在补丁之前失败,之后成功。