From 4911c058d820319478a187477fedbf904310a098 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sun, 16 Aug 2026 12:34:10 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20var=20=E6=8D=95=E8=8E=B7=E7=BB=91?= =?UTF-8?q?=E5=AE=9A=E5=87=BD=E6=95=B0=E4=B8=8E=E7=A8=8B=E5=BA=8F=E5=85=A5?= =?UTF-8?q?=E5=8F=A3=E7=BB=9F=E4=B8=80=E5=88=9D=E5=A7=8B=E5=8C=96=E4=B8=BA?= =?UTF-8?q?=20undefined=20=E6=B6=88=E9=99=A4=20TDZ=20=E8=AF=AF=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_emit/src/closure.rs | 81 +++++++++++++++++++++++++++++++- crates/oxide_emit/src/emit.rs | 47 ++++++++++++++++++ 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/crates/oxide_emit/src/closure.rs b/crates/oxide_emit/src/closure.rs index a6b6f76..214d70f 100644 --- a/crates/oxide_emit/src/closure.rs +++ b/crates/oxide_emit/src/closure.rs @@ -7,7 +7,7 @@ use std::collections::{BTreeMap, HashSet}; use oxide_bytecode::module::UpvalueCapture; -use oxide_parser::{ClassBody, ClassElement, Expression, Statement}; +use oxide_parser::{ClassBody, ClassElement, Expression, Statement, VariableDeclarationKind}; use crate::Emitter; @@ -63,6 +63,85 @@ impl Emitter { } } + /// 收集语句树中全部 `var` 声明名(var 提升到函数/程序作用域,递归进嵌套块)。 + /// 供函数/程序入口批量 MAKE_CELL(undefined) 使用(var 入口实例化语义)。 + pub(crate) fn collect_var_binding_names(&self, stmts: &[Statement]) -> HashSet { + let mut names = HashSet::new(); + self.collect_var_names_stmt(stmts, &mut names); + names + } + + fn collect_var_names_stmt(&self, stmts: &[Statement], out: &mut HashSet) { + for stmt in stmts { + match stmt { + Statement::VariableDeclaration(vd) => { + if matches!(vd.kind, VariableDeclarationKind::Var) { + for d in &vd.declarations { + self.collect_binding_pattern_names(&d.id, out); + } + } + } + Statement::BlockStatement(b) => self.collect_var_names_stmt(&b.body, out), + Statement::IfStatement(is) => { + self.collect_var_names_stmt(std::slice::from_ref(&is.consequent), out); + if let Some(alt) = &is.alternate { + self.collect_var_names_stmt(std::slice::from_ref(alt), out); + } + } + Statement::WhileStatement(w) => self.collect_var_names_stmt(std::slice::from_ref(&w.body), out), + Statement::DoWhileStatement(d) => self.collect_var_names_stmt(std::slice::from_ref(&d.body), out), + Statement::ForStatement(f) => { + if let Some(oxide_parser::ForStatementInit::VariableDeclaration(vd)) = &f.init { + if matches!(vd.kind, VariableDeclarationKind::Var) { + for d in &vd.declarations { + self.collect_binding_pattern_names(&d.id, out); + } + } + } + self.collect_var_names_stmt(std::slice::from_ref(&f.body), out); + } + Statement::ForInStatement(fi) => { + if let oxide_parser::ForStatementLeft::VariableDeclaration(_) = &fi.left { + self.collect_for_left_decl_names(&fi.left, out); + } + self.collect_var_names_stmt(std::slice::from_ref(&fi.body), out); + } + Statement::ForOfStatement(fo) => { + if let oxide_parser::ForStatementLeft::VariableDeclaration(_) = &fo.left { + self.collect_for_left_decl_names(&fo.left, out); + } + self.collect_var_names_stmt(std::slice::from_ref(&fo.body), out); + } + Statement::SwitchStatement(sw) => { + for case in &sw.cases { + self.collect_var_names_stmt(&case.consequent, out); + } + } + Statement::TryStatement(ts) => { + self.collect_var_names_stmt(&ts.block.body, out); + if let Some(h) = &ts.handler { + self.collect_var_names_stmt(&h.body.body, out); + } + if let Some(f) = &ts.finalizer { + self.collect_var_names_stmt(&f.body, out); + } + } + Statement::LabeledStatement(ls) => self.collect_var_names_stmt(std::slice::from_ref(&ls.body), out), + Statement::WithStatement(ws) => self.collect_var_names_stmt(std::slice::from_ref(&ws.body), out), + Statement::ExportNamedDeclaration(exp) => { + if let Some(oxide_parser::Declaration::VariableDeclaration(vd)) = &exp.declaration { + if matches!(vd.kind, VariableDeclarationKind::Var) { + for d in &vd.declarations { + self.collect_binding_pattern_names(&d.id, out); + } + } + } + } + _ => {} + } + } + } + /// 收集当前函数作用域声明的绑定名(参数 + 变量/函数声明,含嵌套 block,不含嵌套函数体)。 pub(crate) fn collect_own_binding_names(&self, param_names: &[&str], stmts: &[Statement]) -> HashSet { let mut names = HashSet::new(); diff --git a/crates/oxide_emit/src/emit.rs b/crates/oxide_emit/src/emit.rs index ee2a401..fcc7a9e 100644 --- a/crates/oxide_emit/src/emit.rs +++ b/crates/oxide_emit/src/emit.rs @@ -1329,6 +1329,31 @@ impl Emitter { )); } + // var 绑定函数入口实例化:被捕获的 var 名统一 MAKE_CELL(undefined)。 + // 规范上 var 在函数入口即初始化为 undefined(HoistDeclaration),声明语句 + // 只是赋值;否则声明语句前创建的闭包读取占位 cell → TDZ 误报。参数与 + // arguments 已在上方初始化(跳过以免覆盖参数值);let/const/class 保持 + // TDZ 语义不动。声明语句的 MAKE_CELL 按占位更新语义覆盖此初值。 + let var_names: Vec = self + .collect_var_binding_names(body_stmts) + .into_iter() + .filter(|n| !param_names.contains(&n.as_str()) && n != "arguments") + .filter(|n| ctx.captured_bindings.contains_key(n)) + .collect(); + if !var_names.is_empty() { + let undef_reg = self.emit_undefined(ctx); + for name in var_names { + if let Some(&cell_idx) = ctx.captured_bindings.get(&name) { + ctx.inst(Inst::new( + OpCode::MAKE_CELL, + Operand::Reg(undef_reg), + Operand::Imm(cell_idx as u16), + Operand::None, + )); + } + } + } + Ok(param_base) } @@ -1459,6 +1484,28 @@ impl Emitter { ctx.own_bindings = self.collect_own_binding_names(&[], &program.body); ctx.captured_bindings = self.collect_captured_bindings(&program.body, &[], &ctx.own_bindings); + // 顶层 var 入口实例化:被捕获的 var 名统一 MAKE_CELL(undefined),使 var + // 声明语句执行前创建的闭包读取到 undefined(脚本 GlobalDeclarationInstantiation + // 语义),而非占位 cell 的 TDZ 误报。声明语句的 MAKE_CELL 覆盖此初值。 + let var_names: Vec = self + .collect_var_binding_names(&program.body) + .into_iter() + .filter(|n| ctx.captured_bindings.contains_key(n)) + .collect(); + if !var_names.is_empty() { + let undef_reg = self.emit_undefined(&mut ctx); + for name in var_names { + if let Some(&cell_idx) = ctx.captured_bindings.get(&name) { + ctx.inst(Inst::new( + OpCode::MAKE_CELL, + Operand::Reg(undef_reg), + Operand::Imm(cell_idx as u16), + Operand::None, + )); + } + } + } + // 首个 sub-pass:发函数声明(hoisting),保证任何代码运行前函数对象已就绪。 for stmt in &program.body { if matches!(stmt, Statement::FunctionDeclaration(_)) {