fix: 修复 for-in 语法原型链丢失属性问题
This commit is contained in:
+26
-16
@@ -2333,28 +2333,38 @@ impl Vm {
|
|||||||
if !obj_val.is_object() {
|
if !obj_val.is_object() {
|
||||||
return Err("TypeError: for-in right-hand side is not an object".into());
|
return Err("TypeError: for-in right-hand side is not an object".into());
|
||||||
}
|
}
|
||||||
let obj = unsafe { &*obj_val.as_js_object_ptr() };
|
|
||||||
let shape_id = obj.shape_id();
|
|
||||||
|
|
||||||
let mut keys_vec = bumpalo::collections::Vec::new_in(self.epoch.bump());
|
let mut keys_vec = bumpalo::collections::Vec::new_in(self.epoch.bump());
|
||||||
let mut cursor = Some(shape_id);
|
let mut seen = std::collections::HashSet::new();
|
||||||
while let Some(id) = cursor {
|
let mut current = obj_val;
|
||||||
if id == oxide_kernel::shape_forge::EMPTY_SHAPE_ID {
|
|
||||||
|
loop {
|
||||||
|
if !current.is_object() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if let Some(shape) = self.kernel.shape_forge().get_shape(id) {
|
let cur = unsafe { &*current.as_js_object_ptr() };
|
||||||
if shape.property_name != u32::MAX {
|
let mut cursor = Some(cur.shape_id());
|
||||||
let hash = self
|
while let Some(id) = cursor {
|
||||||
.kernel
|
if id == EMPTY_SHAPE_ID {
|
||||||
.string_forge()
|
break;
|
||||||
.get_hash(shape.property_name)
|
}
|
||||||
.unwrap_or(0);
|
if let Some(shape) = self.kernel.shape_forge().get_shape(id) {
|
||||||
keys_vec.push(JsValue::string(shape.property_name, hash));
|
if shape.property_name != u32::MAX
|
||||||
|
&& seen.insert(shape.property_name)
|
||||||
|
{
|
||||||
|
let hash = self
|
||||||
|
.kernel
|
||||||
|
.string_forge()
|
||||||
|
.get_hash(shape.property_name)
|
||||||
|
.unwrap_or(0);
|
||||||
|
keys_vec.push(JsValue::string(shape.property_name, hash));
|
||||||
|
}
|
||||||
|
cursor = shape.parent;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
cursor = shape.parent;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
current = cur.proto();
|
||||||
}
|
}
|
||||||
|
|
||||||
let iter = self.epoch.alloc(ForInIter {
|
let iter = self.epoch.alloc(ForInIter {
|
||||||
|
|||||||
@@ -64,3 +64,12 @@ fn regression_throw_statement_errors() {
|
|||||||
"compile error: throw statement not supported"
|
"compile error: throw statement not supported"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn regression_for_in_prototype_chain() {
|
||||||
|
assert_eq!(
|
||||||
|
eval("var c=0;for(var k in {a:1}){c=c+1;}c"),
|
||||||
|
"2",
|
||||||
|
"for-in should include inherited constructor from prototype"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user