fix: for-in 与 for-of 头 var 名补编译期预声明臂

This commit is contained in:
2026-09-14 16:14:31 +00:00
parent b00147eff1
commit 99c1254fab
2 changed files with 61 additions and 0 deletions
+27
View File
@@ -442,6 +442,33 @@ impl Emitter {
}
self.predeclare_var_declarations(std::slice::from_ref(&fs.body), ctx);
}
Statement::ForInStatement(fi) => {
// var 头名提升到函数/全局作用域(与 For 臂同规则),先于提升
// 函数声明发射预声明,使函数体按既有 var 绑定解析头名;
// let/const 头是迭代级绑定,不入提升面。
if let oxide_parser::ForStatementLeft::VariableDeclaration(decl) = &fi.left {
if matches!(decl.kind, VariableDeclarationKind::Var) {
for d in &decl.declarations {
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
self.predeclare_var_name(bi.name.as_str(), ctx);
}
}
}
}
self.predeclare_var_declarations(std::slice::from_ref(&fi.body), ctx);
}
Statement::ForOfStatement(fo) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(decl) = &fo.left {
if matches!(decl.kind, VariableDeclarationKind::Var) {
for d in &decl.declarations {
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
self.predeclare_var_name(bi.name.as_str(), ctx);
}
}
}
}
self.predeclare_var_declarations(std::slice::from_ref(&fo.body), ctx);
}
Statement::SwitchStatement(sw) => {
for case in &sw.cases {
self.predeclare_var_declarations(&case.consequent, ctx);
@@ -102,3 +102,37 @@ fn for_in_var_head_fresh_name() {
"for-in var head binds iteration keys into the hoisted var slot"
);
}
// ── 提升函数引用 for-in/for-of 头 var 名:头名须编译期预声明(hoisting 面)──
#[test]
fn for_in_var_head_hoisted_fn_read() {
// 顶层提升函数读 for-in 头 var:头名预声明入全局 var 名集,函数体按
// 全局 var 绑定解析,完成值为迭代键。
assert_eq!(
eval("function f(){ return x; } for (var x in {a:1}) {} f() === \"a\""),
"true",
"hoisted function reads for-in head var through the global var binding"
);
}
#[test]
fn for_in_var_head_hoisted_fn_strict_write() {
// strict 嵌套写:头名预声明为全局 var 绑定后,写落全局属性(A 侧);
// 头名缺预声明时该写按未声明名抛 ReferenceError(本钉判别面)。
assert_eq!(
eval("'use strict'; function f(){ x = 5; } for (var x in {a:1}) { f(); } x === 5"),
"true",
"strict hoisted-function write to for-in head var hits the global binding"
);
}
#[test]
fn for_of_var_head_hoisted_fn_strict_write() {
// for-of 头同形:预声明臂覆盖 for-in 与 for-of 两臂。
assert_eq!(
eval("'use strict'; function f(){ x = 5; } for (var x of [1,2]) { f(); } x === 5"),
"true",
"strict hoisted-function write to for-of head var hits the global binding"
);
}