fix: 被捕获词法绑定入口建 TDZ 占位 cell 并跳过陈旧静态守卫

This commit is contained in:
2026-09-20 09:08:44 +00:00
parent 9a502e634a
commit 1433d47329
7 changed files with 438 additions and 4 deletions
+27 -2
View File
@@ -17,8 +17,8 @@ use oxide_ir::IRFunction;
use oxide_parser::Statement;
use crate::capture::{
collect_captured_bindings, collect_own_binding_names, collect_top_level_function_names,
collect_top_level_function_names_ordered, collect_var_binding_names,
collect_captured_bindings, collect_direct_lexical_names, collect_own_binding_names,
collect_top_level_function_names, collect_top_level_function_names_ordered, collect_var_binding_names,
};
use crate::compile_ctx::CompileCtx;
use crate::Emitter;
@@ -377,6 +377,31 @@ impl Emitter {
}
}
// 被捕获顶层词法(let/const/class)入口 TDZ 占位 cell:声明语句执行前
// 创建的闭包指向此未初始化 cell,声明前读写经运行时抛真 TDZ;声明语句
// 的 MAKE_CELL 按占位更新语义原位翻转为已初始化。名集取捕获集交集
// (直接子级词法名,块级名不提升到顶层),排序保证发射序跨进程稳定。
let mut lex_names: Vec<String> = collect_direct_lexical_names(&program.body)
.into_iter()
.filter(|n| ctx.captured_bindings.contains_key(n))
.collect();
lex_names.sort();
if !lex_names.is_empty() {
let undef_reg = self.emit_undefined(&mut ctx);
for name in lex_names {
if let Some(&cell_idx) = ctx.captured_bindings.get(&name) {
// 未初始化标志折入 16 位立即数高字节(0x0100),dispatch 侧
// 按字节拆回两字段。
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(undef_reg),
Operand::Imm(cell_idx as u16 | 0x0100),
Operand::None,
));
}
}
}
// 全局声明实例化序言:脚本求值前为顶层 var 名创建全局对象属性(值 undefined),
// 使声明语句执行前的读取(typeof、反射、自引用)可经全局对象见绑定。
// 顶层函数声明名不进序言:函数值是编译闭包,编译期不可得,其全局对象属性值