mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-26 11:41:13 +08:00
fix: for-in var 头撞既有绑定复用槽位消除顶层编译报错,迭代键写不可写全局内置接只读拦截
This commit is contained in:
@@ -38,8 +38,25 @@ impl Emitter {
|
|||||||
let is_const = matches!(decl.kind, VariableDeclarationKind::Const);
|
let is_const = matches!(decl.kind, VariableDeclarationKind::Const);
|
||||||
let name = bi.name.as_str();
|
let name = bi.name.as_str();
|
||||||
let var_reg = ctx.alloc_reg();
|
let var_reg = ctx.alloc_reg();
|
||||||
ctx.declare(name, var_reg, decl.kind, is_const)?;
|
// var 声明:绑定已存在(顶层 var 预声明、GDI 序言预登记
|
||||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
// builtin 名、同 scope 先前声明)时复用既有槽位,不重复
|
||||||
|
// 声明;let/const 同 scope 重复声明仍报错。
|
||||||
|
let target_reg = if matches!(decl.kind, VariableDeclarationKind::Var) {
|
||||||
|
match ctx.declare(name, var_reg, decl.kind, is_const) {
|
||||||
|
Ok(()) => var_reg,
|
||||||
|
Err(_) => ctx.lookup(name).unwrap_or(var_reg),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.declare(name, var_reg, decl.kind, is_const)?;
|
||||||
|
var_reg
|
||||||
|
};
|
||||||
|
if ctx.targets_readonly_builtin(name, target_reg) {
|
||||||
|
// 声明撞全局不可写内置:声明不更新既有全局绑定——sloppy
|
||||||
|
// 静默跳过写(槽保留入口预载原值),strict 抛 TypeError。
|
||||||
|
if ctx.is_strict {
|
||||||
|
self.emit_throw_error("TypeError", "cannot assign to read-only property", ctx)?;
|
||||||
|
}
|
||||||
|
} else if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||||
let op = if fresh_cell { OpCode::MAKE_CELL_FRESH } else { OpCode::MAKE_CELL };
|
let op = if fresh_cell { OpCode::MAKE_CELL_FRESH } else { OpCode::MAKE_CELL };
|
||||||
ctx.inst(Inst::new(
|
ctx.inst(Inst::new(
|
||||||
op,
|
op,
|
||||||
@@ -50,7 +67,7 @@ impl Emitter {
|
|||||||
} else {
|
} else {
|
||||||
ctx.inst(Inst::new(
|
ctx.inst(Inst::new(
|
||||||
OpCode::STORE_VAR,
|
OpCode::STORE_VAR,
|
||||||
Operand::Reg(var_reg),
|
Operand::Reg(target_reg),
|
||||||
Operand::Reg(key_reg),
|
Operand::Reg(key_reg),
|
||||||
Operand::None,
|
Operand::None,
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -79,3 +79,24 @@ fn for_in_still_enumerates_own_keys() {
|
|||||||
"for-in still enumerates the object's own enumerable keys"
|
"for-in still enumerates the object's own enumerable keys"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_var_head_reuses_existing_var_binding() {
|
||||||
|
// var 头命中同 scope 已预声明的 var 绑定:复用既有槽位不重复声明,
|
||||||
|
// 迭代键逐迭代落入该绑定(终值 = 末键)。
|
||||||
|
assert_eq!(
|
||||||
|
eval("var x = 0; for (var x in {a:1,b:2}) {} x === \"b\""),
|
||||||
|
"true",
|
||||||
|
"for-in var head reuses the predeclared same-scope var binding"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_var_head_fresh_name() {
|
||||||
|
// var 头无其他引用:提升的 var 槽接收迭代键。
|
||||||
|
assert_eq!(
|
||||||
|
eval("for (var x in {a:1}) {} x === \"a\""),
|
||||||
|
"true",
|
||||||
|
"for-in var head binds iteration keys into the hoisted var slot"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -186,3 +186,21 @@ fn function_declaration_builtin_name() {
|
|||||||
&& d.enumerable === false && d.configurable === true",
|
&& d.enumerable === false && d.configurable === true",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_var_head_builtin_name_compiles_and_keeps_property() {
|
||||||
|
// 顶层 for-in var 头撞 builtin 名:序言预登记槽复用后可编译,
|
||||||
|
// 迭代键不触及全局属性(Math 对象保)。
|
||||||
|
run_truthy("var m = Math; for (var Math in {a:1,b:2}) {} globalThis.Math === m");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_in_var_head_readonly_builtin_not_clobbered() {
|
||||||
|
// 顶层 for-in var 头撞三常量:迭代键写命中只读内置拦截——
|
||||||
|
// sloppy 静默跳过(镜像槽与声明值均不污染),strict 迭代抛 TypeError。
|
||||||
|
run_truthy("var n = NaN; for (var NaN in {a:1,b:2}) {} Number.isNaN(NaN) && Number.isNaN(n)");
|
||||||
|
run_truthy(
|
||||||
|
"var i = Infinity; for (var Infinity in {a:1,b:2}) {} Infinity === i && Infinity === globalThis.Infinity",
|
||||||
|
);
|
||||||
|
run_truthy("\"use strict\"; try { for (var NaN in {a:1}) {} } catch (e) { e instanceof TypeError }");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user