fix: 类表达式真实名 cell 按声明路径门控,不再覆盖外层同名绑定
This commit is contained in:
@@ -27,6 +27,10 @@ impl Emitter {
|
|||||||
&self, class: &Class, ctx: &mut CompileCtx, binding_reg: Option<u32>,
|
&self, class: &Class, ctx: &mut CompileCtx, binding_reg: Option<u32>,
|
||||||
) -> Result<u32, String> {
|
) -> Result<u32, String> {
|
||||||
let ctor_name = class.id.as_ref().map(|id| id.name.to_string());
|
let ctor_name = class.id.as_ref().map(|id| id.name.to_string());
|
||||||
|
// 类声明由调用方提供外层绑定槽(binding_reg=Some),类表达式无外部槽
|
||||||
|
// (None,类名是类体内独立 const 绑定)。真实名 cell 仅声明路径指向
|
||||||
|
// 本作用域绑定;表达式路径按名查 captured_bindings 会命中外层同名绑定。
|
||||||
|
let is_class_decl = binding_reg.is_some();
|
||||||
let mut pushed_scope = false;
|
let mut pushed_scope = false;
|
||||||
let binding_reg = if let Some(name) = ctor_name.as_deref() {
|
let binding_reg = if let Some(name) = ctor_name.as_deref() {
|
||||||
match binding_reg {
|
match binding_reg {
|
||||||
@@ -402,13 +406,18 @@ impl Emitter {
|
|||||||
}
|
}
|
||||||
// 类名被外层嵌套函数捕获时,真实名 cell 同样须初始化(类元素自引用走
|
// 类名被外层嵌套函数捕获时,真实名 cell 同样须初始化(类元素自引用走
|
||||||
// @@class_self_* 合成 cell,二者 cell_idx 不同则各发一次)。
|
// @@class_self_* 合成 cell,二者 cell_idx 不同则各发一次)。
|
||||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
// 仅类声明:类名是本作用域绑定,captured_bindings 按名命中的才是
|
||||||
ctx.inst(Inst::new(
|
// 它的 cell;类表达式名是类体内独立 const 绑定,按名查询只会命中
|
||||||
OpCode::MAKE_CELL,
|
// 外层同名绑定 cell,MAKE_CELL 会把类值误写进外层绑定。
|
||||||
Operand::Reg(binding_reg),
|
if is_class_decl {
|
||||||
Operand::Imm(cell_idx as u16),
|
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||||
Operand::None,
|
ctx.inst(Inst::new(
|
||||||
));
|
OpCode::MAKE_CELL,
|
||||||
|
Operand::Reg(binding_reg),
|
||||||
|
Operand::Imm(cell_idx as u16),
|
||||||
|
Operand::None,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -810,3 +810,44 @@ fn private_field_nullish_coalesce_short_circuits_on_defined() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_num(result, 10.0);
|
assert_num(result, 10.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 类表达式真实名 cell 边界:类名绑定不触碰外层同名绑定 ──
|
||||||
|
|
||||||
|
// 类表达式名是类体内独立 const 绑定:真实名 cell 初始化不得按名命中外层
|
||||||
|
// 同名绑定 cell 并覆盖之。外层 var E 被嵌套函数捕获时,读 E 应仍是原值。
|
||||||
|
#[test]
|
||||||
|
fn class_expression_inner_name_does_not_clobber_outer_binding() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"var E = 1; var h = class E { m() { return E; } }; function g() { return E; } g()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(result.as_int(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 类表达式名不得破坏外层同名 let 的 TDZ:提前调用的捕获函数读该名仍抛
|
||||||
|
// ReferenceError,而非读到被类值污染的 cell。
|
||||||
|
#[test]
|
||||||
|
fn class_expression_inner_name_preserves_outer_let_tdz() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let err = eval(
|
||||||
|
&mut vm,
|
||||||
|
"function g(){ return E; } var h = class E { m(){ return E; } }; var r = g(); let E = 5; r",
|
||||||
|
)
|
||||||
|
.unwrap_err();
|
||||||
|
assert!(err.contains("ReferenceError"), "expected ReferenceError, got: {err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 类声明路径不回归:真实名 cell 仍须初始化(嵌套函数经 cell 读类值),
|
||||||
|
// 且外层同名 var 不被类声明覆盖。
|
||||||
|
#[test]
|
||||||
|
fn class_declaration_captured_name_cell_still_initialized() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"var E = 1; function mk(){ class E { static n(){ return 5; } } return function(){ return E.n(); }; } var f = mk(); f()*10 + E",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_num(result, 51.0);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user