From e8f2a54a672c65828f5fe683b467a00a4a8a097a Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sat, 19 Sep 2026 15:41:22 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20concat=20=E7=A9=BA=E6=95=B0=E7=BB=84?= =?UTF-8?q?=E5=AE=9E=E5=8F=82=E6=8C=89=20ConcatSteps=20=E5=B1=95=E5=BC=80?= =?UTF-8?q?=E4=B8=BA=E9=9B=B6=E5=85=83=E7=B4=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/array/element.rs | 4 +-- .../tests/array_hole_semantics_tests.rs | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/crates/oxide_builtins/src/array/element.rs b/crates/oxide_builtins/src/array/element.rs index f777b263..9517b15c 100644 --- a/crates/oxide_builtins/src/array/element.rs +++ b/crates/oxide_builtins/src/array/element.rs @@ -412,8 +412,8 @@ pub fn array_concat(vm: &mut H, args: &[u8]) -> NativeResult { if !o_ptr.is_null() { let o = unsafe { &*o_ptr }; let on = o.prop_count() as usize; - // 真数组时展开元素(洞位同样留洞)。 - if o.is_array() && on > 0 { + // 真数组时展开元素(空数组展开为零元素,贡献无;洞位同样留洞)。 + if o.is_array() { let dense = o.array_elements_meta_vec().is_none(); for i in 0..on { if dense || !o.prop_meta_at(i).is_some_and(|m| m.is_hole()) { diff --git a/crates/oxide_builtins/tests/array_hole_semantics_tests.rs b/crates/oxide_builtins/tests/array_hole_semantics_tests.rs index 67e44e9a..2dbd1027 100644 --- a/crates/oxide_builtins/tests/array_hole_semantics_tests.rs +++ b/crates/oxide_builtins/tests/array_hole_semantics_tests.rs @@ -526,3 +526,28 @@ fn test_splice_reverse_primitive_this_boxed() { .unwrap(); assert_eq!(out, "true|true|0"); } + +// 引擎钉:concat 空数组实参按 ConcatSteps 展开为零元素——不贡献元素也不占位。 +#[test] +fn test_concat_empty_array_arg_expands_zero_elements() { + let out = eval_str( + "(() => { return [1].concat([]).length + '|' + [1].concat([], []).length + '|' + \ + [].concat([]).length + '|' + [1, 2].concat(new Array(0)).length; })()", + ) + .unwrap(); + assert_eq!(out, "1|1|0|2"); +} + +// 引擎钉:concat 多实参混合 present/空数组/非数组实参展开序与规范一致, +// 空数组实参中间穿插不占位;洞实参位保洞。 +#[test] +fn test_concat_mixed_args_order_and_holes() { + let out = eval_str( + "(() => { const mixed = [].concat([], 5, []).join(','); \ + const ordered = [1].concat([2, 3], 0, []).join(','); \ + const r = [].concat(new Array(1)); \ + return mixed + '|' + ordered + '|' + r.length + '|' + (0 in r); })()", + ) + .unwrap(); + assert_eq!(out, "5|1,2,3,0|1|false"); +}