feat: eval 代码块函数早期错误跳过不建绑定

This commit is contained in:
2026-10-16 19:07:31 +00:00
parent f644f08a34
commit ff4ae9aaa6
6 changed files with 72 additions and 27 deletions
+8
View File
@@ -954,6 +954,14 @@ impl CompileCtx {
NON_WRITABLE_GLOBAL_BUILTINS.contains(&name)
}
/// 早期错误跳过谓词(Annex B.3.3.3 对 EvalDeclarationInstantiation 的增补):
/// sloppy eval 代码内块函数声明的名若与同树词法声明/形参同名,替换为变量
/// 语句即产生早期错误,规范不为其建任何绑定——函数体只求值副作用,不写块
/// Let、不写外层 var、不写全局对象属性。预声明门与存储臂共用本谓词。
pub(crate) fn is_eval_early_error_suppressed(&self, name: &str) -> bool {
self.is_eval_script && !self.is_strict && self.block_fn_suppressed.contains(name)
}
/// 进入 with 语句体:记录对象寄存器与当前作用域深度,供动态标识符解析。
pub(crate) fn push_with(&mut self, obj_reg: u32) {
let depth = self.scopes.symbols.scopes.len();
+7 -1
View File
@@ -230,7 +230,13 @@ impl Emitter {
let Some(identifier) = &f.id else {
continue;
};
if if_arm && Self::if_arm_has_outer_var_carrier(ctx, identifier.name.as_str()) {
// 早期错误跳过(Annex B.3.3.3):sloppy eval 代码内支臂函数名撞
// 同树词法声明时不建块 Let 绑定,使词法预声明不撞名报重复声明
// 错(函数体只求值副作用,不写任何绑定)。
if if_arm
&& (Self::if_arm_has_outer_var_carrier(ctx, identifier.name.as_str())
|| ctx.is_eval_early_error_suppressed(identifier.name.as_str()))
{
continue;
}
let reg = ctx.alloc_reg();
@@ -40,10 +40,16 @@ impl Emitter {
// 其余 sub-pass 发的函数声明皆为块级(if/while/for/switch/try 支臂与块直接子)。
let is_block_function = !ctx.in_hoisting_subpass;
let var_reg = if is_block_function {
match ctx.block_fn_entry_mats.last().and_then(|m| m.get(&name)) {
Some(&m) if m == node => ctx.lookup(&name)?,
Some(_) => self.materialize_function_declaration_var_only(fd, &name, ctx, true)?,
None => self.materialize_function_declaration(fd, &name, ctx, true)?,
if ctx.is_eval_early_error_suppressed(&name) {
// 早期错误跳过(Annex B.3.3.3):不写入任何绑定,函数体只求值
// 副作用(CREATE_CLOSURE 照发,结果寄存器丢弃,不发 STORE_VAR)。
self.materialize_function_declaration_var_only(fd, &name, ctx, true)?
} else {
match ctx.block_fn_entry_mats.last().and_then(|m| m.get(&name)) {
Some(&m) if m == node => ctx.lookup(&name)?,
Some(_) => self.materialize_function_declaration_var_only(fd, &name, ctx, true)?,
None => self.materialize_function_declaration(fd, &name, ctx, true)?,
}
}
} else {
self.materialize_function_declaration(fd, &name, ctx, false)?