fix: 逻辑赋值标识符目标接入不可写全局内置拦截,目标位置内置预登记稳定槽解析

This commit is contained in:
2026-09-10 02:30:09 +08:00
parent 479238dc24
commit eabd0b3608
3 changed files with 116 additions and 18 deletions
+23 -15
View File
@@ -399,21 +399,29 @@ impl Emitter {
let is_const = ctx.lookup_const_flag(name);
let const_flag = if is_const { 1 } else { 0 };
let var_reg = ctx.lookup_or_global(name);
// 隐式全局判定以寄存器集合为准:读侧(旧值解析)已登记绑定,
// 写侧二次解析命中集合而非"新登记"。
let is_implicit = ctx.implicit_global_writes.contains(&var_reg);
if is_implicit && ctx.is_strict {
// 严格模式未声明写:抛 ReferenceError,后续 LOAD_VAR 不可达。
let _ = self.emit_strict_undeclared_write(name, ctx)?;
} else {
ctx.inst(Inst::new(
OpCode::STORE_VAR,
Operand::Reg(var_reg),
Operand::Reg(val_reg),
Operand::Imm(const_flag),
));
if is_implicit {
self.emit_implicit_global_write(name, var_reg, ctx);
// 全局不可写内置槽:strict 抛 TypeError(put 失败);sloppy 跳过槽写,
// 表达式值 = RHS(尾部结果装载取 val_reg)。短路时序与 PutValue 一致:
// 短路未通过不到达此处、不抛错,通过后才在写点拦截。
let readonly_builtin = ctx.targets_readonly_builtin(name, var_reg);
if readonly_builtin && ctx.is_strict {
let _ = self.emit_throw_error("TypeError", "cannot assign to read-only property", ctx)?;
} else if !readonly_builtin {
// 隐式全局判定以寄存器集合为准:读侧(旧值解析)已登记绑定,
// 写侧二次解析命中集合而非"新登记"。
let is_implicit = ctx.implicit_global_writes.contains(&var_reg);
if is_implicit && ctx.is_strict {
// 严格模式未声明写:抛 ReferenceError,后续 LOAD_VAR 不可达。
let _ = self.emit_strict_undeclared_write(name, ctx)?;
} else {
ctx.inst(Inst::new(
OpCode::STORE_VAR,
Operand::Reg(var_reg),
Operand::Reg(val_reg),
Operand::Imm(const_flag),
));
if is_implicit {
self.emit_implicit_global_write(name, var_reg, ctx);
}
}
}
}
+8
View File
@@ -268,6 +268,14 @@ impl Emitter {
fn pre_scan_builtin_target(&self, target: &oxide_parser::SimpleAssignmentTarget, ctx: &mut CompileCtx) {
match target {
oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(id) => {
// 标识符目标与表达式位置标识符引用同口径预登记:目标为某内置名的
// 唯一出现处(无读侧引用)时缺预登记会解析成隐式全局新槽,旧值读
// 与短路判定拿到未预载值。
if CompileCtx::is_known_builtin(id.name.as_str()) {
let _ = ctx.lookup_or_builtin(id.name.as_str());
}
}
oxide_parser::SimpleAssignmentTarget::StaticMemberExpression(member) => {
self.pre_scan_builtin_expr(&member.object, ctx);
}