diff --git a/crates/oxide_emit/src/closure.rs b/crates/oxide_emit/src/closure.rs index b632b01..1076e7b 100644 --- a/crates/oxide_emit/src/closure.rs +++ b/crates/oxide_emit/src/closure.rs @@ -15,21 +15,19 @@ impl Emitter { fn collect_fn_param_names(&self, params: &oxide_parser::FormalParameters) -> HashSet { let mut names = HashSet::new(); for p in ¶ms.items { - if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &p.pattern { - names.insert(bi.name.to_string()); - } + self.collect_binding_pattern_names(&p.pattern, &mut names); } // rest 形参也是本函数作用域绑定,遮蔽外层同名变量。 if let Some(rest) = ¶ms.rest { - if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &rest.rest.argument { - names.insert(bi.name.to_string()); - } + self.collect_binding_pattern_names(&rest.rest.argument, &mut names); } names } /// 递归收集 binding pattern 内全部绑定标识符名(解构 `[a, b]` / `{x: y}` 嵌套)。 - fn collect_binding_pattern_names(&self, pattern: &oxide_parser::BindingPattern, out: &mut HashSet) { + pub(crate) fn collect_binding_pattern_names( + &self, pattern: &oxide_parser::BindingPattern, out: &mut HashSet, + ) { match pattern { oxide_parser::BindingPattern::BindingIdentifier(bi) => { out.insert(bi.name.to_string()); diff --git a/crates/oxide_emit/src/emit.rs b/crates/oxide_emit/src/emit.rs index a456fe4..498641f 100644 --- a/crates/oxide_emit/src/emit.rs +++ b/crates/oxide_emit/src/emit.rs @@ -1100,6 +1100,11 @@ impl Emitter { } } ctx.own_bindings = self.collect_own_binding_names(¶m_names, body_stmts); + for spec in param_specs { + if let ParamSpec::Pattern { pattern, .. } = spec { + self.collect_binding_pattern_names(pattern, &mut ctx.own_bindings); + } + } // 自动声明 arguments 绑定(非箭头函数,且用户未显式声明同名标识符)。 // 先登记符号并纳入 own_bindings,使嵌套箭头引用 arguments 被识别为本函数 diff --git a/crates/oxide_vm/tests/destructuring_tests.rs b/crates/oxide_vm/tests/destructuring_tests.rs index b516cdd..b8614dd 100644 --- a/crates/oxide_vm/tests/destructuring_tests.rs +++ b/crates/oxide_vm/tests/destructuring_tests.rs @@ -88,6 +88,17 @@ fn function_and_method_parameter_destructuring() { assert_num(result, 10.0); } +#[test] +fn destructured_callback_parameters_shadow_outer_bindings() { + let mut vm = Vm::new(); + let result = eval( + &mut vm, + "let expected=100, result=0; [[1,2]].forEach(([value, expected]) => { result=value+expected; }); result", + ) + .unwrap(); + assert_num(result, 3.0); +} + // 回归:赋值目标含嵌套 rest 模式(rest 元素本身是模式,如 `[...[x]]`)的 for-of // 曾无限循环 / 报错,因为计数器相对 emitter 少计了 rest 目标的指令,破坏了循环跳转 // 偏移。(对象 rest 嵌套目标按规范是语法错误,故不测。)