diff --git a/Cargo.lock b/Cargo.lock index c338ea41..954e6d21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "oxide_builtins" -version = "0.16.9" +version = "0.16.10" dependencies = [ "chrono", "fast-float", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "oxide_bytecode" -version = "0.16.9" +version = "0.16.10" dependencies = [ "num-bigint", "oxide_log", @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "oxide_cfg" -version = "0.16.9" +version = "0.16.10" dependencies = [ "oxide_bytecode", "oxide_emit", @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "oxide_cli" -version = "0.16.9" +version = "0.16.10" dependencies = [ "ansi_term", "bumpalo", @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "oxide_code_cache" -version = "0.16.9" +version = "0.16.10" dependencies = [ "lru", "oxide_bytecode", @@ -1237,7 +1237,7 @@ dependencies = [ [[package]] name = "oxide_compiler" -version = "0.16.9" +version = "0.16.10" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1257,7 +1257,7 @@ dependencies = [ [[package]] name = "oxide_dce" -version = "0.16.9" +version = "0.16.10" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1271,7 +1271,7 @@ dependencies = [ [[package]] name = "oxide_emit" -version = "0.16.9" +version = "0.16.10" dependencies = [ "num-bigint", "oxc_allocator", @@ -1286,7 +1286,7 @@ dependencies = [ [[package]] name = "oxide_engine" -version = "0.16.9" +version = "0.16.10" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1298,7 +1298,7 @@ dependencies = [ [[package]] name = "oxide_ir" -version = "0.16.9" +version = "0.16.10" dependencies = [ "oxide_bytecode", "oxide_log", @@ -1307,7 +1307,7 @@ dependencies = [ [[package]] name = "oxide_kernel" -version = "0.16.9" +version = "0.16.10" dependencies = [ "bumpalo", "dashmap", @@ -1321,7 +1321,7 @@ dependencies = [ [[package]] name = "oxide_liveness" -version = "0.16.9" +version = "0.16.10" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1333,7 +1333,7 @@ dependencies = [ [[package]] name = "oxide_log" -version = "0.16.9" +version = "0.16.10" dependencies = [ "tracing", "tracing-appender", @@ -1342,11 +1342,11 @@ dependencies = [ [[package]] name = "oxide_net" -version = "0.16.9" +version = "0.16.10" [[package]] name = "oxide_parser" -version = "0.16.9" +version = "0.16.10" dependencies = [ "oxc_allocator", "oxc_ast", @@ -1361,7 +1361,7 @@ dependencies = [ [[package]] name = "oxide_regalloc" -version = "0.16.9" +version = "0.16.10" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1377,7 +1377,7 @@ dependencies = [ [[package]] name = "oxide_runtime_api" -version = "0.16.9" +version = "0.16.10" dependencies = [ "num-bigint", "num-traits", @@ -1390,7 +1390,7 @@ dependencies = [ [[package]] name = "oxide_test262" -version = "0.16.9" +version = "0.16.10" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1410,7 +1410,7 @@ dependencies = [ [[package]] name = "oxide_types" -version = "0.16.9" +version = "0.16.10" dependencies = [ "bumpalo", "dashmap", @@ -1423,7 +1423,7 @@ dependencies = [ [[package]] name = "oxide_vm" -version = "0.16.9" +version = "0.16.10" dependencies = [ "bumpalo", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 295e0599..f1cb253b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ members = [ ] [workspace.package] -version = "0.16.9" +version = "0.16.10" edition = "2021" license = "MIT" rust-version = "1.80" diff --git a/crates/oxide_emit/src/capture/mod.rs b/crates/oxide_emit/src/capture/mod.rs index 0d7bf760..a5b41425 100644 --- a/crates/oxide_emit/src/capture/mod.rs +++ b/crates/oxide_emit/src/capture/mod.rs @@ -12,24 +12,111 @@ mod names; mod scanner; mod upvalues; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; pub(crate) use names::collect_fn_scope_names; pub(crate) use names::FnScopeNames; pub(crate) use upvalues::collect_captured_bindings; pub(crate) use upvalues::collect_captures_and_upvalues; -/// 收集形参(含 rest)绑定的名字集,作为本函数作用域的遮蔽集。 -pub(crate) fn collect_fn_param_names(params: &oxide_parser::FormalParameters) -> HashSet { - let mut names = HashSet::new(); +/// 收集形参(含 rest)绑定的名字写入影子计次映射(计次加一), +/// 作为本函数作用域的遮蔽集。 +pub(crate) fn collect_fn_param_names_into(params: &oxide_parser::FormalParameters, shadow: &mut HashMap) { for p in ¶ms.items { - collect_binding_pattern_names(&p.pattern, &mut names); + collect_binding_pattern_names_into(&p.pattern, shadow); } // rest 形参也是本函数作用域绑定,遮蔽外层同名变量。 if let Some(rest) = ¶ms.rest { - collect_binding_pattern_names(&rest.rest.argument, &mut names); + collect_binding_pattern_names_into(&rest.rest.argument, shadow); + } +} + +/// 递归收集 binding pattern 内全部绑定标识符名(解构 `[a, b]` / `{x: y}` 嵌套), +/// 写入影子计次映射(计次加一),作用域进入时遮蔽外层同名绑定。 +pub(crate) fn collect_binding_pattern_names_into(pattern: &oxide_parser::BindingPattern, shadow: &mut HashMap) { + match pattern { + oxide_parser::BindingPattern::BindingIdentifier(bi) => { + *shadow.entry(bi.name.as_str().to_string()).or_insert(0) += 1; + } + oxide_parser::BindingPattern::ArrayPattern(ap) => { + for p in ap.elements.iter().flatten() { + collect_binding_pattern_names_into(p, shadow); + } + if let Some(rest) = &ap.rest { + collect_binding_pattern_names_into(&rest.argument, shadow); + } + } + oxide_parser::BindingPattern::ObjectPattern(op) => { + for prop in &op.properties { + collect_binding_pattern_names_into(&prop.value, shadow); + } + if let Some(rest) = &op.rest { + collect_binding_pattern_names_into(&rest.argument, shadow); + } + } + oxide_parser::BindingPattern::AssignmentPattern(ap) => { + collect_binding_pattern_names_into(&ap.left, shadow); + } + } +} + +/// 递归收集 binding pattern 内全部绑定标识符名并解除影子计次映射(计次减一, +/// 归零删项),作用域退出时解除遮蔽,与 `collect_binding_pattern_names_into` 配对。 +fn collect_binding_pattern_names_remove(pattern: &oxide_parser::BindingPattern, shadow: &mut HashMap) { + match pattern { + oxide_parser::BindingPattern::BindingIdentifier(bi) => { + shadow_dec(shadow, bi.name.as_str().to_string()); + } + oxide_parser::BindingPattern::ArrayPattern(ap) => { + for p in ap.elements.iter().flatten() { + collect_binding_pattern_names_remove(p, shadow); + } + if let Some(rest) = &ap.rest { + collect_binding_pattern_names_remove(&rest.argument, shadow); + } + } + oxide_parser::BindingPattern::ObjectPattern(op) => { + for prop in &op.properties { + collect_binding_pattern_names_remove(&prop.value, shadow); + } + if let Some(rest) = &op.rest { + collect_binding_pattern_names_remove(&rest.argument, shadow); + } + } + oxide_parser::BindingPattern::AssignmentPattern(ap) => { + collect_binding_pattern_names_remove(&ap.left, shadow); + } + } +} + +/// 影子计次映射中某名字计次减一,归零删项。 +pub(crate) fn shadow_dec(shadow: &mut HashMap, name: String) { + if let Some(count) = shadow.get_mut(&name) { + *count -= 1; + if *count == 0 { + shadow.remove(&name); + } + } +} + +/// 收集 for-in/for-of 头部声明(`var x` / 解构 pattern)绑定的名字写入影子计次 +/// 映射(计次加一),作用域进入时遮蔽外层同名绑定。 +pub(crate) fn collect_for_left_decl_names_into(left: &oxide_parser::ForStatementLeft, shadow: &mut HashMap) { + if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = left { + for d in &vd.declarations { + collect_binding_pattern_names_into(&d.id, shadow); + } + } +} + +/// 收集 for-in/for-of 头部声明绑定的名字并解除影子计次映射(计次减一,归零删项), +/// 作用域退出时解除遮蔽,与 `collect_for_left_decl_names_into` 配对。 +pub(crate) fn collect_for_left_decl_names_remove(left: &oxide_parser::ForStatementLeft, shadow: &mut HashMap) { + if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = left { + for d in &vd.declarations { + collect_binding_pattern_names_remove(&d.id, shadow); + } } - names } /// 递归收集 binding pattern 内全部绑定标识符名(解构 `[a, b]` / `{x: y}` 嵌套)。 diff --git a/crates/oxide_emit/src/capture/names.rs b/crates/oxide_emit/src/capture/names.rs index 9110518c..fda1bf6e 100644 --- a/crates/oxide_emit/src/capture/names.rs +++ b/crates/oxide_emit/src/capture/names.rs @@ -2,22 +2,24 @@ //! 块级声明名 / 直接子词法名 / 顶层函数名集 / 顶层函数声明序 / 块级函数名 / //! 块函数抑制集),供各入口(程序/模块/函数体)的 GDI 检查、builtin 排除、 //! 入口实例化与块函数 web-compat 各调用点共用;另保留捕获扫描器内部依赖的 -//! own 绑定名集收集(`collect_own_binding_names`)。 +//! own 绑定名集收集(`collect_own_binding_names_into`)。 -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use oxide_parser::{Statement, VariableDeclarationKind}; -use super::{collect_binding_pattern_names, collect_for_left_decl_names}; +use super::{ + collect_binding_pattern_names, collect_binding_pattern_names_into, collect_for_left_decl_names, + collect_for_left_decl_names_into, +}; -/// 收集当前函数作用域声明的绑定名(参数 + 变量/函数声明,含嵌套 block,不含嵌套函数体)。 -pub(crate) fn collect_own_binding_names(param_names: &[&str], stmts: &[Statement]) -> HashSet { - let mut names = HashSet::new(); +/// 收集当前函数作用域声明的绑定名(参数 + 变量/函数声明,含嵌套 block,不含嵌套函数体), +/// 写入影子计次映射(计次加一)。 +pub(crate) fn collect_own_binding_names_into(param_names: &[&str], stmts: &[Statement], out: &mut HashMap) { for p in param_names { - names.insert(p.to_string()); + *out.entry(p.to_string()).or_insert(0) += 1; } - collect_decl_names_stmt(stmts, &mut names); - names + collect_decl_names_into(stmts, out); } /// 函数作用域名收集结果:单趟遍历同时填八个输出,与各旧独立收集函数逐位一致。 @@ -335,25 +337,25 @@ fn collect_fn_scope_names_impl(stmts: &[Statement], out: &mut FnScopeNames, top: } /// 递归遍历语句树收集当前函数作用域声明的绑定名(变量/函数/类/import/export, -/// 含嵌套块,不进嵌套函数体)。 -pub(crate) fn collect_decl_names_stmt(stmts: &[Statement], out: &mut HashSet) { +/// 含嵌套块,不进嵌套函数体),写入影子计次映射(计次加一)。 +pub(crate) fn collect_decl_names_into(stmts: &[Statement], out: &mut HashMap) { for stmt in stmts { match stmt { Statement::VariableDeclaration(vd) => { for d in &vd.declarations { - collect_binding_pattern_names(&d.id, out); + collect_binding_pattern_names_into(&d.id, out); } } Statement::FunctionDeclaration(fd) => { if let Some(id) = &fd.id { - out.insert(id.name.to_string()); + *out.entry(id.name.to_string()).or_insert(0) += 1; } } // class 名是本作用域 const 绑定:须计入 own_bindings,否则嵌套函数 // 引用类名时捕获分析缺失 → 落符号表兜底(TDZ 误报或读父寄存器残留)。 Statement::ClassDeclaration(cd) => { if let Some(id) = &cd.id { - out.insert(id.name.to_string()); + *out.entry(id.name.to_string()).or_insert(0) += 1; } } // import 绑定是模块作用域 const 绑定,须计入 own_bindings 供 @@ -363,13 +365,13 @@ pub(crate) fn collect_decl_names_stmt(stmts: &[Statement], out: &mut HashSet { - out.insert(s.local.name.to_string()); + *out.entry(s.local.name.to_string()).or_insert(0) += 1; } oxide_parser::ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => { - out.insert(s.local.name.to_string()); + *out.entry(s.local.name.to_string()).or_insert(0) += 1; } oxide_parser::ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => { - out.insert(s.local.name.to_string()); + *out.entry(s.local.name.to_string()).or_insert(0) += 1; } } } @@ -380,17 +382,17 @@ pub(crate) fn collect_decl_names_stmt(stmts: &[Statement], out: &mut HashSet { for d in &vd.declarations { - collect_binding_pattern_names(&d.id, out); + collect_binding_pattern_names_into(&d.id, out); } } oxide_parser::Declaration::FunctionDeclaration(fd) => { if let Some(id) = &fd.id { - out.insert(id.name.to_string()); + *out.entry(id.name.to_string()).or_insert(0) += 1; } } oxide_parser::Declaration::ClassDeclaration(cd) => { if let Some(id) = &cd.id { - out.insert(id.name.to_string()); + *out.entry(id.name.to_string()).or_insert(0) += 1; } } _ => {} @@ -400,70 +402,70 @@ pub(crate) fn collect_decl_names_stmt(stmts: &[Statement], out: &mut HashSet match &exp.declaration { oxide_parser::ExportDefaultDeclarationKind::FunctionDeclaration(fd) => { if let Some(id) = &fd.id { - out.insert(id.name.to_string()); + *out.entry(id.name.to_string()).or_insert(0) += 1; } } oxide_parser::ExportDefaultDeclarationKind::ClassDeclaration(cd) => { if let Some(id) = &cd.id { - out.insert(id.name.to_string()); + *out.entry(id.name.to_string()).or_insert(0) += 1; } } _ => {} }, - Statement::BlockStatement(b) => collect_decl_names_stmt(&b.body, out), + Statement::BlockStatement(b) => collect_decl_names_into(&b.body, out), Statement::IfStatement(is) => { - collect_decl_names_stmt(std::slice::from_ref(&is.consequent), out); + collect_decl_names_into(std::slice::from_ref(&is.consequent), out); if let Some(alt) = &is.alternate { - collect_decl_names_stmt(std::slice::from_ref(alt), out); + collect_decl_names_into(std::slice::from_ref(alt), out); } } - Statement::WhileStatement(w) => collect_decl_names_stmt(std::slice::from_ref(&w.body), out), - Statement::DoWhileStatement(d) => collect_decl_names_stmt(std::slice::from_ref(&d.body), out), + Statement::WhileStatement(w) => collect_decl_names_into(std::slice::from_ref(&w.body), out), + Statement::DoWhileStatement(d) => collect_decl_names_into(std::slice::from_ref(&d.body), out), Statement::ForStatement(f) => { if let Some(oxide_parser::ForStatementInit::VariableDeclaration(vd)) = &f.init { for d in &vd.declarations { if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id { - out.insert(bi.name.to_string()); + *out.entry(bi.name.to_string()).or_insert(0) += 1; } } } - collect_decl_names_stmt(std::slice::from_ref(&f.body), out); + collect_decl_names_into(std::slice::from_ref(&f.body), out); } // for-in / for-of 头部的 var 声明是本函数局部绑定(遮蔽外层同名), // 须计入 own_bindings,否则闭包捕获分析会误判为捕获外层变量。 Statement::ForInStatement(fi) => { if let oxide_parser::ForStatementLeft::VariableDeclaration(_) = &fi.left { - collect_for_left_decl_names(&fi.left, out); + collect_for_left_decl_names_into(&fi.left, out); } - collect_decl_names_stmt(std::slice::from_ref(&fi.body), out); + collect_decl_names_into(std::slice::from_ref(&fi.body), out); } Statement::ForOfStatement(fo) => { if let oxide_parser::ForStatementLeft::VariableDeclaration(_) = &fo.left { - collect_for_left_decl_names(&fo.left, out); + collect_for_left_decl_names_into(&fo.left, out); } - collect_decl_names_stmt(std::slice::from_ref(&fo.body), out); + collect_decl_names_into(std::slice::from_ref(&fo.body), out); } Statement::SwitchStatement(sw) => { for case in &sw.cases { - collect_decl_names_stmt(&case.consequent, out); + collect_decl_names_into(&case.consequent, out); } } Statement::TryStatement(ts) => { - collect_decl_names_stmt(&ts.block.body, out); + collect_decl_names_into(&ts.block.body, out); if let Some(h) = &ts.handler { // catch 参数是本函数作用域的词法绑定:计入 own_bindings, // 嵌套函数引用它时捕获分析才会建 cell 供 upvalue 读取。 if let Some(param) = &h.param { - collect_binding_pattern_names(¶m.pattern, out); + collect_binding_pattern_names_into(¶m.pattern, out); } - collect_decl_names_stmt(&h.body.body, out); + collect_decl_names_into(&h.body.body, out); } if let Some(f) = &ts.finalizer { - collect_decl_names_stmt(&f.body, out); + collect_decl_names_into(&f.body, out); } } - Statement::LabeledStatement(ls) => collect_decl_names_stmt(std::slice::from_ref(&ls.body), out), - Statement::WithStatement(ws) => collect_decl_names_stmt(std::slice::from_ref(&ws.body), out), + Statement::LabeledStatement(ls) => collect_decl_names_into(std::slice::from_ref(&ls.body), out), + Statement::WithStatement(ws) => collect_decl_names_into(std::slice::from_ref(&ws.body), out), _ => {} } } diff --git a/crates/oxide_emit/src/capture/scanner.rs b/crates/oxide_emit/src/capture/scanner.rs index 81bfa68d..bb5a48fe 100644 --- a/crates/oxide_emit/src/capture/scanner.rs +++ b/crates/oxide_emit/src/capture/scanner.rs @@ -1,19 +1,23 @@ //! 闭包捕获分析,遮蔽感知引用收集:`CaptureEngine` 捆绑双引用集(own × -//! parent_names)× shadow(遮蔽名集)× 双输出累加器(captured_out × +//! parent_names)× shadow(遮蔽名计次映射)× 双输出累加器(captured_out × //! upvalue_out)× depth(嵌套深度),遍历语句/表达式/赋值目标/类体 AST,嵌套 //! 函数/类/for 头/catch 参数逐层遮蔽,按深度分区写两输出。 -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use oxide_parser::{ClassBody, ClassElement, Expression, Statement}; -use super::names::collect_own_binding_names; -use super::{collect_fn_param_names, collect_for_left_decl_names}; +use super::names::collect_own_binding_names_into; +use super::{ + collect_binding_pattern_names_into, collect_fn_param_names_into, collect_for_left_decl_names_into, + collect_for_left_decl_names_remove, shadow_dec, +}; /// 双引用集引擎:捆绑 own(深度 ≥ 1 引用集)、parent_names(全深度引用集)、 -/// sub_own(upvalue 显式排除集)、shadow(遮蔽名集)、depth(嵌套深度)与双输出 +/// sub_own(upvalue 显式排除集)、shadow(遮蔽名计次映射)、depth(嵌套深度)与双输出 /// 累加器,本族十五个收集函数共享单一 `&mut CaptureEngine` 参数。作用域边界(嵌套 -/// 函数/类/for 头/catch 参数)对 shadow 集做保存/恢复,逐层遮蔽外层绑定;函数/类 +/// 函数/类/for 头/catch 参数)对 shadow 计次映射做计次增减(函数边界清空重建, +/// catch 参数只增不减),逐层遮蔽外层绑定;函数/类 /// 边界对 depth 做增减,区分本函数体层与嵌套层。 pub(crate) struct CaptureEngine<'a> { /// 深度 ≥ 1 的引用集:本函数 own 绑定集(父层捕获判定)。 @@ -22,8 +26,9 @@ pub(crate) struct CaptureEngine<'a> { parent_names: &'a HashSet, /// upvalue 判定的显式排除集:本函数 own 绑定集。 sub_own: &'a HashSet, - /// 遮蔽名集:当前作用域内被遮蔽、须排除的名字;作用域边界保存/恢复。 - shadow: HashSet, + /// 遮蔽名计次映射:当前作用域内被遮蔽的名字及其计次;作用域边界计次增减, + /// 函数边界清空重建,每边界零分配。 + shadow: HashMap, /// 嵌套深度:0 = 本函数体层,≥ 1 = 嵌套函数/类内。 depth: u32, /// 输出累加器:被嵌套函数捕获的名字(父层捕获判定)。 @@ -44,7 +49,7 @@ impl<'a> CaptureEngine<'a> { own, parent_names, sub_own, - shadow: HashSet::new(), + shadow: HashMap::new(), depth: 0, captured_out, upvalue_out, @@ -55,13 +60,18 @@ impl<'a> CaptureEngine<'a> { /// 深度 ≥ 1 且名字在 own 且不在 shadow → captured_out; /// 名字在 parent_names 且不在 shadow 且不在 sub_own → upvalue_out。 fn check_identifier(&mut self, name: &str) { - if self.depth >= 1 && self.own.contains(name) && !self.shadow.contains(name) { + if self.depth >= 1 && self.own.contains(name) && !self.shadow_contains(name) { self.captured_out.insert(name.to_string()); } - if self.parent_names.contains(name) && !self.shadow.contains(name) && !self.sub_own.contains(name) { + if self.parent_names.contains(name) && !self.shadow_contains(name) && !self.sub_own.contains(name) { self.upvalue_out.insert(name.to_string()); } } + + /// 遮蔽判定:名字在计次映射中的计次大于零即被遮蔽。 + fn shadow_contains(&self, name: &str) -> bool { + self.shadow.get(name).is_some_and(|&c| c > 0) + } } /// 以引擎的 ref_set × shadow 双集驱动,收集被任意深度嵌套函数引用、且未被遮蔽的 @@ -94,10 +104,11 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi Statement::FunctionDeclaration(fd) => { let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); collect_fn_default_names(&fd.params, eng); - // 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复,深度增一。 + // 函数形参与体内声明遮蔽外层绑定:影子计次映射保存/恢复,清空重建为 + // 本函数自身名,深度增一。 let saved = std::mem::take(&mut eng.shadow); - eng.shadow.extend(collect_fn_param_names(&fd.params)); - eng.shadow.extend(collect_own_binding_names(&[], body)); + collect_fn_param_names_into(&fd.params, &mut eng.shadow); + collect_own_binding_names_into(&[], body, &mut eng.shadow); eng.depth += 1; collect_capture_names_shadowed(body, eng); eng.depth -= 1; @@ -106,14 +117,15 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi Statement::ClassDeclaration(cd) => { // 类体(构造器/方法体、字段键与值、静态块)是嵌套作用域: // 类名遮蔽外层绑定,方法形参与方法体局部进一步遮蔽。深度增一。 - let saved = std::mem::take(&mut eng.shadow); if let Some(id) = &cd.id { - eng.shadow.insert(id.name.as_str().to_string()); + *eng.shadow.entry(id.name.as_str().to_string()).or_insert(0) += 1; } eng.depth += 1; collect_class_capture_names(&cd.body, eng); eng.depth -= 1; - eng.shadow = saved; + if let Some(id) = &cd.id { + shadow_dec(&mut eng.shadow, id.name.as_str().to_string()); + } } Statement::IfStatement(is) => { collect_capture_names_expr(&is.test, eng); @@ -164,10 +176,9 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi collect_capture_names_for_left(&fi.left, eng); } // left 的 var 声明遮蔽外层同名绑定,body 内引用不视为捕获外层。 - let saved = std::mem::take(&mut eng.shadow); - collect_for_left_decl_names(&fi.left, &mut eng.shadow); + collect_for_left_decl_names_into(&fi.left, &mut eng.shadow); collect_capture_names_shadowed(std::slice::from_ref(&fi.body), eng); - eng.shadow = saved; + collect_for_left_decl_names_remove(&fi.left, &mut eng.shadow); } Statement::ForOfStatement(fo) => { collect_capture_names_expr(&fo.right, eng); @@ -178,10 +189,9 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi } else { collect_capture_names_for_left(&fo.left, eng); } - let saved = std::mem::take(&mut eng.shadow); - collect_for_left_decl_names(&fo.left, &mut eng.shadow); + collect_for_left_decl_names_into(&fo.left, &mut eng.shadow); collect_capture_names_shadowed(std::slice::from_ref(&fo.body), eng); - eng.shadow = saved; + collect_for_left_decl_names_remove(&fo.left, &mut eng.shadow); } Statement::BlockStatement(b) => collect_capture_names_shadowed(&b.body, eng), Statement::TryStatement(ts) => { @@ -190,9 +200,11 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi } if let Some(h) = &ts.handler { // catch 参数解构模式内的表达式引用(默认值等)也会被内部闭包捕获; - // 参数声明名合并进引擎影子集后遮蔽 catch 作用域。 + // 先以外层影子集扫模式内表达式,再将参数声明名合并进引擎影子计次 + // 映射遮蔽 catch 作用域(只增不减,与旧代码一致)。 if let Some(param) = &h.param { - collect_capture_names_binding_pattern(¶m.pattern, eng); + collect_binding_pattern_exprs(¶m.pattern, eng); + collect_binding_pattern_names_into(¶m.pattern, &mut eng.shadow); } for s in &h.body.body { collect_capture_names_stmt(s, eng); @@ -219,22 +231,23 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); collect_fn_default_names(&fd.params, eng); let saved = std::mem::take(&mut eng.shadow); - eng.shadow.extend(collect_fn_param_names(&fd.params)); - eng.shadow.extend(collect_own_binding_names(&[], body)); + collect_fn_param_names_into(&fd.params, &mut eng.shadow); + collect_own_binding_names_into(&[], body, &mut eng.shadow); eng.depth += 1; collect_capture_names_shadowed(body, eng); eng.depth -= 1; eng.shadow = saved; } oxide_parser::Declaration::ClassDeclaration(cd) => { - let saved = std::mem::take(&mut eng.shadow); if let Some(id) = &cd.id { - eng.shadow.insert(id.name.as_str().to_string()); + *eng.shadow.entry(id.name.as_str().to_string()).or_insert(0) += 1; } eng.depth += 1; collect_class_capture_names(&cd.body, eng); eng.depth -= 1; - eng.shadow = saved; + if let Some(id) = &cd.id { + shadow_dec(&mut eng.shadow, id.name.as_str().to_string()); + } } _ => {} } @@ -245,22 +258,23 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); collect_fn_default_names(&fd.params, eng); let saved = std::mem::take(&mut eng.shadow); - eng.shadow.extend(collect_fn_param_names(&fd.params)); - eng.shadow.extend(collect_own_binding_names(&[], body)); + collect_fn_param_names_into(&fd.params, &mut eng.shadow); + collect_own_binding_names_into(&[], body, &mut eng.shadow); eng.depth += 1; collect_capture_names_shadowed(body, eng); eng.depth -= 1; eng.shadow = saved; } oxide_parser::ExportDefaultDeclarationKind::ClassDeclaration(cd) => { - let saved = std::mem::take(&mut eng.shadow); if let Some(id) = &cd.id { - eng.shadow.insert(id.name.as_str().to_string()); + *eng.shadow.entry(id.name.as_str().to_string()).or_insert(0) += 1; } eng.depth += 1; collect_class_capture_names(&cd.body, eng); eng.depth -= 1; - eng.shadow = saved; + if let Some(id) = &cd.id { + shadow_dec(&mut eng.shadow, id.name.as_str().to_string()); + } } other => { if let Some(e) = other.as_expression() { @@ -307,11 +321,12 @@ pub(crate) fn collect_class_capture_names(class_body: &ClassBody, eng: &mut Capt match element { ClassElement::MethodDefinition(method) => { collect_fn_default_names(&method.value.params, eng); - // 方法形参与方法体局部遮蔽外层绑定:影子集保存/恢复。 + // 方法形参与方法体局部遮蔽外层绑定:影子计次映射保存/恢复, + // 清空重建为本方法自身名。 let saved = std::mem::take(&mut eng.shadow); - eng.shadow.extend(collect_fn_param_names(&method.value.params)); + collect_fn_param_names_into(&method.value.params, &mut eng.shadow); let body: &[Statement] = method.value.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); - eng.shadow.extend(collect_own_binding_names(&[], body)); + collect_own_binding_names_into(&[], body, &mut eng.shadow); collect_capture_names_shadowed(body, eng); eng.shadow = saved; } @@ -333,29 +348,20 @@ pub(crate) fn collect_class_capture_names(class_body: &ClassBody, eng: &mut Capt } } -/// 遍历 catch 参数解构模式:收集模式内表达式引用(默认值等),声明名合并进引擎 -/// 影子集遮蔽 catch 作用域。模式内表达式扫描走外层影子集,不受本模式声明名影响。 -pub(crate) fn collect_capture_names_binding_pattern(pattern: &oxide_parser::BindingPattern, eng: &mut CaptureEngine) { - let mut declared = HashSet::new(); - collect_binding_pattern_refs(pattern, eng, &mut declared); - eng.shadow.extend(declared); -} - -/// 递归遍历 catch 参数解构模式:收集模式内表达式引用(默认值等)写入引擎输出, -/// 声明名累积进 `declared` 供调用方合并进影子集。 -fn collect_binding_pattern_refs( - pattern: &oxide_parser::BindingPattern, eng: &mut CaptureEngine, declared: &mut HashSet, -) { +/// 遍历绑定 pattern 的运行时求值表达式引用:计算键(`{[k]: a}` 的键)与内嵌 +/// 默认值(`{a = x}` 的 x)都是模式内求值的表达式,嵌套函数引用外层绑定时须 +/// 纳入捕获(与赋值侧/对象字面量/类字段键遍历同口径)。模式声明名不进影子计次 +/// 映射:catch 与形参默认值边界都先以外层影子集扫完表达式、再写声明名,声明名 +/// 不参与模式内表达式扫描。 +pub(crate) fn collect_binding_pattern_exprs(pattern: &oxide_parser::BindingPattern, eng: &mut CaptureEngine) { match pattern { - oxide_parser::BindingPattern::BindingIdentifier(bi) => { - declared.insert(bi.name.as_str().to_string()); - } + oxide_parser::BindingPattern::BindingIdentifier(_) => {} oxide_parser::BindingPattern::ArrayPattern(ap) => { for p in ap.elements.iter().flatten() { - collect_binding_pattern_refs(p, eng, declared); + collect_binding_pattern_exprs(p, eng); } if let Some(rest) = &ap.rest { - collect_binding_pattern_refs(&rest.argument, eng, declared); + collect_binding_pattern_exprs(&rest.argument, eng); } } oxide_parser::BindingPattern::ObjectPattern(op) => { @@ -364,15 +370,15 @@ fn collect_binding_pattern_refs( if prop.computed { collect_capture_names_expr(prop.key.to_expression(), eng); } - collect_binding_pattern_refs(&prop.value, eng, declared); + collect_binding_pattern_exprs(&prop.value, eng); } if let Some(rest) = &op.rest { - collect_binding_pattern_refs(&rest.argument, eng, declared); + collect_binding_pattern_exprs(&rest.argument, eng); } } oxide_parser::BindingPattern::AssignmentPattern(ap) => { collect_capture_names_expr(&ap.right, eng); - collect_binding_pattern_refs(&ap.left, eng, declared); + collect_binding_pattern_exprs(&ap.left, eng); } } } @@ -576,10 +582,10 @@ pub(crate) fn collect_fn_default_names(params: &oxide_parser::FormalParameters, if let Some(init) = &p.initializer { collect_capture_names_expr(init, eng); } - // 形参模式声明名只遮蔽本形参模式,不渗入后续形参默认值扫描。 - let saved = std::mem::take(&mut eng.shadow); - collect_capture_names_binding_pattern(&p.pattern, eng); - eng.shadow = saved; + // 形参模式内表达式(计算键、嵌套默认值)在外层作用域求值,须纳入捕获 + // 判定;模式声明名不进影子计次映射(旧代码扩展后立即恢复,净效果为空, + // 保持逐位一致)。 + collect_binding_pattern_exprs(&p.pattern, eng); } eng.depth -= 1; } @@ -603,10 +609,11 @@ pub(crate) fn collect_capture_names_expr(expr: &Expression, eng: &mut CaptureEng Expression::FunctionExpression(fe) => { let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]); collect_fn_default_names(&fe.params, eng); - // 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复,深度增一。 + // 函数形参与体内声明遮蔽外层绑定:影子计次映射保存/恢复,清空重建为 + // 本函数自身名,深度增一。 let saved = std::mem::take(&mut eng.shadow); - eng.shadow.extend(collect_fn_param_names(&fe.params)); - eng.shadow.extend(collect_own_binding_names(&[], body)); + collect_fn_param_names_into(&fe.params, &mut eng.shadow); + collect_own_binding_names_into(&[], body, &mut eng.shadow); eng.depth += 1; collect_capture_names_shadowed(body, eng); eng.depth -= 1; @@ -614,10 +621,11 @@ pub(crate) fn collect_capture_names_expr(expr: &Expression, eng: &mut CaptureEng } Expression::ArrowFunctionExpression(ae) => { collect_fn_default_names(&ae.params, eng); - // 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复,深度增一。 + // 函数形参与体内声明遮蔽外层绑定:影子计次映射保存/恢复,清空重建为 + // 本函数自身名,深度增一。 let saved = std::mem::take(&mut eng.shadow); - eng.shadow.extend(collect_fn_param_names(&ae.params)); - eng.shadow.extend(collect_own_binding_names(&[], &ae.body.statements)); + collect_fn_param_names_into(&ae.params, &mut eng.shadow); + collect_own_binding_names_into(&[], &ae.body.statements, &mut eng.shadow); eng.depth += 1; collect_capture_names_shadowed(&ae.body.statements, eng); eng.depth -= 1; @@ -625,14 +633,15 @@ pub(crate) fn collect_capture_names_expr(expr: &Expression, eng: &mut CaptureEng } Expression::ClassExpression(class) => { // 类表达式:方法/构造器体与字段表达式是嵌套作用域,引用须捕获。深度增一。 - let saved = std::mem::take(&mut eng.shadow); if let Some(id) = &class.id { - eng.shadow.insert(id.name.as_str().to_string()); + *eng.shadow.entry(id.name.as_str().to_string()).or_insert(0) += 1; } eng.depth += 1; collect_class_capture_names(&class.body, eng); eng.depth -= 1; - eng.shadow = saved; + if let Some(id) = &class.id { + shadow_dec(&mut eng.shadow, id.name.as_str().to_string()); + } } Expression::BinaryExpression(be) => { collect_capture_names_expr(&be.left, eng);