fix: 数值长度数组构造建 n 个空洞

This commit is contained in:
2026-09-19 10:59:36 +00:00
parent a953652da8
commit 6610384d90
2 changed files with 43 additions and 0 deletions
+7
View File
@@ -26,6 +26,13 @@ pub fn array_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
Err(err) => return NativeResult::Err(err), Err(err) => return NativeResult::Err(err),
}; };
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n, vm.epoch().bump())); let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n, vm.epoch().bump()));
// 数值长度分支建 n 个空洞而非 present-undefined:`in`、for-in、
// Object.keys 按缺失处理,元素 Get 落原型链。
for i in 0..n {
unsafe {
(*arr).mark_hole_at(i);
}
}
return NativeResult::Ok(JsValue::from_js_object(arr)); return NativeResult::Ok(JsValue::from_js_object(arr));
} }
} }
@@ -227,3 +227,39 @@ fn mutators_still_work_with_writable_length() {
"3:1:3:9,8,2" "3:1:3:9,8,2"
); );
} }
#[test]
fn new_array_numeric_length_builds_holes() {
// 数值长度构造器建 n 个空洞:in / Object.keys / for-in / join /
// JSON.stringify 全部按缺失语义观察。
assert_eq!(eval_str("''+(0 in new Array(1))+':'+(1 in new Array(2))"), "false:false");
assert_eq!(eval_str("Object.keys(new Array(3)).join(',')"), "");
assert_eq!(eval_str("var k=0; for (var i in new Array(3)) {k++;} ''+k"), "0");
assert_eq!(eval_str("new Array(2).join(',')"), ",");
assert_eq!(eval_str("JSON.stringify(new Array(1))"), "[null]");
}
#[test]
fn new_array_hole_read_falls_through_to_prototype_getter() {
// 洞位读落原型链:继承的索引 getter 被触发一次并返回其值。
assert_eq!(
eval_str("var n=0; Object.defineProperty(Array.prototype,'0',{get:function(){n++;return 42;}}); var a=new Array(1); var v=a[0]; n+':'+v"),
"1:42"
);
}
#[test]
fn new_array_hole_write_clears_marker() {
// 洞位写入后恢复为 present 属性:原洞位保持缺失。
assert_eq!(
eval_str("var a=new Array(2); a[1]=5; ''+(0 in a)+':'+(1 in a)+':'+a.length"),
"false:true:2"
);
}
#[test]
fn new_array_holes_pop_shift() {
// 全洞数组 pop/shift:返回 undefined,length 归 0。
assert_eq!(eval_str("var a=new Array(1); var p=a.pop(); (p===undefined)+':'+a.length"), "true:0");
assert_eq!(eval_str("var a=new Array(1); var s=a.shift(); (s===undefined)+':'+a.length"), "true:0");
}