fix: if 支臂函数绑定收集下钻容器语句

This commit is contained in:
2026-09-17 18:29:44 +00:00
parent 36f24e1f46
commit e90edba4ec
3 changed files with 55 additions and 63 deletions
+29 -61
View File
@@ -174,127 +174,95 @@ impl Emitter {
/// # 边界与前提
/// - 只处理块内函数声明;switch 不推 scope(其 case 内函数声明随 switch
/// 作用域修复一并处理);export 声明不可能出现在块内。
/// - `if` 支臂的裸函数声明属 Annex B 隐式支臂块:名已有外层 var 绑定承载
/// (非 eval 脚本顶层、未被形参/词法同名抑制、且非脚本顶层只读三常量)时
/// 不建外层块绑定,声明点物化进该 var 槽(建外层块 Let 会遮蔽同名 var);
/// 名无外层 var 绑定(形参/词法抑制、eval 脚本顶层或只读三常量)时保留
/// 块级绑定承载支臂闭包,避免声明点覆写外层绑定。支臂为块时由该块自身的
/// 块入口流程处理。
/// - `if_arm` 标记当前递归是否位于 `if` 支臂隐式块内。Annex B 下该隐式块的
/// 函数声明名已有外层 var 绑定承载(非 eval 脚本顶层、未被形参/词法同名
/// 抑制、且非全局只读三常量)时不建当前块绑定,声明点物化进该 var 槽
/// (建当前块 Let 会遮蔽同名 var);名无外层 var 绑定(形参/词法抑制、eval
/// 脚本顶层或全局只读三常量)时保留块级绑定承载支臂闭包,避免声明点覆写
/// 外层绑定。门控只作用于 `if` 支臂下的叶子,块直接子不受影响。
/// - 支臂为容器(循环/`try`/`with`/标签/显式块)时按各自作用域规则继续下钻,
/// 使嵌套 `if` 支臂的函数声明同样到达门控。
/// - 与 lexical 预声明的顺序:本函数在前,`{ let g; function g(){} }` 时
/// lexical 的 `declare_predeclared` 命中已存在的函数绑定自然报重复声明错,
/// 避免函数预声明被 lexical 占位静默覆盖而破坏 let 的 TDZ。
/// - var 与函数同名(`{ var g; function g(){} }`):var 落函数作用域、
/// 函数落当前块,不同 scope 互不冲突。
pub(crate) fn predeclare_block_function_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
/// - 须在 `block_fn_suppressed` 已构建之后调用(函数体/程序声明实例化阶段
/// 先于任何块 emit)。
pub(crate) fn predeclare_block_function_declarations(
&self, statements: &[Statement], ctx: &mut CompileCtx, if_arm: bool,
) {
for statement in statements {
match statement {
Statement::FunctionDeclaration(f) => {
let Some(identifier) = &f.id else {
continue;
};
if if_arm && Self::if_arm_has_outer_var_carrier(ctx, identifier.name.as_str()) {
continue;
}
let reg = ctx.alloc_reg();
let _ = ctx.declare_initialized(identifier.name.as_str(), reg, VariableDeclarationKind::Let, false);
}
Statement::BlockStatement(bs) => {
ctx.push_scope();
self.predeclare_block_function_declarations(&bs.body, ctx);
self.predeclare_block_function_declarations(&bs.body, ctx, if_arm);
ctx.pop_scope();
}
Statement::IfStatement(is) => {
self.predeclare_if_arm_block_function(&is.consequent, ctx);
self.predeclare_block_function_declarations(std::slice::from_ref(&is.consequent), ctx, true);
if let Some(alt) = &is.alternate {
self.predeclare_if_arm_block_function(alt, ctx);
self.predeclare_block_function_declarations(std::slice::from_ref(alt), ctx, true);
}
}
Statement::WhileStatement(wh) => {
self.predeclare_block_function_declarations(std::slice::from_ref(&wh.body), ctx);
self.predeclare_block_function_declarations(std::slice::from_ref(&wh.body), ctx, if_arm);
}
Statement::DoWhileStatement(dw) => {
self.predeclare_block_function_declarations(std::slice::from_ref(&dw.body), ctx);
self.predeclare_block_function_declarations(std::slice::from_ref(&dw.body), ctx, if_arm);
}
Statement::ForStatement(fs) => {
// 循环推独立作用域(头声明所在),函数声明落该作用域与 emit 对齐。
ctx.push_scope();
self.predeclare_block_function_declarations(std::slice::from_ref(&fs.body), ctx);
self.predeclare_block_function_declarations(std::slice::from_ref(&fs.body), ctx, if_arm);
ctx.pop_scope();
}
Statement::ForInStatement(fi) => {
ctx.push_scope();
self.predeclare_block_function_declarations(std::slice::from_ref(&fi.body), ctx);
self.predeclare_block_function_declarations(std::slice::from_ref(&fi.body), ctx, if_arm);
ctx.pop_scope();
}
Statement::ForOfStatement(fo) => {
ctx.push_scope();
self.predeclare_block_function_declarations(std::slice::from_ref(&fo.body), ctx);
self.predeclare_block_function_declarations(std::slice::from_ref(&fo.body), ctx, if_arm);
ctx.pop_scope();
}
Statement::TryStatement(ts) => {
ctx.push_scope();
self.predeclare_block_function_declarations(&ts.block.body, ctx);
self.predeclare_block_function_declarations(&ts.block.body, ctx, if_arm);
ctx.pop_scope();
if let Some(handler) = &ts.handler {
ctx.push_scope();
self.predeclare_block_function_declarations(&handler.body.body, ctx);
self.predeclare_block_function_declarations(&handler.body.body, ctx, if_arm);
ctx.pop_scope();
}
if let Some(finalizer) = &ts.finalizer {
ctx.push_scope();
self.predeclare_block_function_declarations(&finalizer.body, ctx);
self.predeclare_block_function_declarations(&finalizer.body, ctx, if_arm);
ctx.pop_scope();
}
}
Statement::LabeledStatement(ls) => {
self.predeclare_block_function_declarations(std::slice::from_ref(&ls.body), ctx);
self.predeclare_block_function_declarations(std::slice::from_ref(&ls.body), ctx, if_arm);
}
Statement::WithStatement(ws) => {
self.predeclare_block_function_declarations(std::slice::from_ref(&ws.body), ctx);
self.predeclare_block_function_declarations(std::slice::from_ref(&ws.body), ctx, if_arm);
}
_ => {}
}
}
}
/// 预声明 `if` 支臂裸函数声明的块级绑定(展开标签链并下钻嵌套 `if` 后取
/// 函数声明):仅当该名没有外层 var 绑定承载时才在当前块建块 Let,承载支臂
/// 闭包,避免声明点覆写外层形参/词法绑定;名已有外层 var 绑定(非 eval 脚本
/// 顶层、未被形参/词法同名抑制、且非全局只读内置三常量)时不建块级绑定,
/// 声明点物化进该 var 槽。
///
/// # 边界与前提
/// - 支臂为块时返回:该块自身的块入口流程预声明其函数声明。
/// - 支臂为嵌套 `if`(含 `else if` 链)时沿 consequent/alternate 下钻至叶子,
/// 叶子按同一门控判定——嵌套支臂与单层支臂同属 Annex B 隐式支臂块。
/// - 支臂为其它语句时返回:其中的函数声明不属于 `if` 支臂隐式块。
/// - 须在 `block_fn_suppressed` 已构建之后调用(函数体/程序声明实例化阶段
/// 先于任何块 emit);`is_eval_script` 仅标记 eval 脚本顶层程序,其顶层
/// 不建块级函数外层 var 绑定;脚本顶层的只读三常量全局属性不可配置,
/// 声明实例化不建外层 var 绑定,须保留块级绑定承载支臂闭包。
fn predeclare_if_arm_block_function(&self, stmt: &Statement, ctx: &mut CompileCtx) {
let mut cur = stmt;
while let Statement::LabeledStatement(ls) = cur {
cur = &ls.body;
}
match cur {
Statement::FunctionDeclaration(f) => {
let Some(identifier) = &f.id else {
return;
};
if Self::if_arm_has_outer_var_carrier(ctx, identifier.name.as_str()) {
return;
}
let reg = ctx.alloc_reg();
let _ = ctx.declare_initialized(identifier.name.as_str(), reg, VariableDeclarationKind::Let, false);
}
Statement::IfStatement(is) => {
self.predeclare_if_arm_block_function(&is.consequent, ctx);
if let Some(alt) = &is.alternate {
self.predeclare_if_arm_block_function(alt, ctx);
}
}
_ => {}
}
}
/// `if` 支臂裸函数声明的名是否已有外层 var/函数绑定承载:非 eval 脚本顶层的
/// 非抑制名由实例化阶段建外层 var 绑定,唯一例外是脚本顶层的只读三常量
/// (全局属性不可配置,声明实例化刻意不建外层绑定),其名须退回块级绑定。