Browse Source

Fix class inherit from `null` (#3312)

pull/3313/head
Haled Odat 1 year ago committed by GitHub
parent
commit
60c9583c98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      boa_engine/src/vm/opcode/mod.rs
  2. 75
      boa_engine/src/vm/opcode/push/class/mod.rs
  3. 1
      boa_engine/src/vm/opcode/set/class_prototype.rs

2
boa_engine/src/vm/opcode/mod.rs

@ -605,6 +605,8 @@ generate_opcodes! {
/// Get the prototype of a superclass and push it on the stack. /// Get the prototype of a superclass and push it on the stack.
/// ///
/// Additionally this sets the `[[prototype]]` of the class and the `DERIVED` flag.
///
/// Operands: /// Operands:
/// ///
/// Stack: class, superclass **=>** class, superclass.prototype /// Stack: class, superclass **=>** class, superclass.prototype

75
boa_engine/src/vm/opcode/push/class/mod.rs

@ -25,42 +25,67 @@ impl Operation for PushClassPrototype {
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> { fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let superclass = context.vm.pop(); let superclass = context.vm.pop();
let class = context.vm.pop();
if let Some(superclass) = superclass.as_constructor() { // // Taken from `15.7.14 Runtime Semantics: ClassDefinitionEvaluation`:
// <https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation>
//
// 8. Else
// f. If superclass is null, then
let (proto_parent, constructor_parent) = if superclass.is_null() {
// i. Let protoParent be null.
// ii. Let constructorParent be %Function.prototype%.
//
// NOTE(HalidOdat): We set constructorParent to None, it is resolved in `SetClassPrototype` opcode.
(JsValue::null(), None)
// h. Else,
} else if let Some(superclass) = superclass.as_constructor() {
// i. Let protoParent be ? Get(superclass, "prototype").
let proto = superclass.get(PROTOTYPE, context)?; let proto = superclass.get(PROTOTYPE, context)?;
// ii. If protoParent is not an Object and protoParent is not null, throw a TypeError exception.
if !proto.is_object() && !proto.is_null() { if !proto.is_object() && !proto.is_null() {
return Err(JsNativeError::typ() return Err(JsNativeError::typ()
.with_message("superclass prototype must be an object or null") .with_message("superclass prototype must be an object or null")
.into()); .into());
} }
let class = context.vm.pop(); // iii. Let constructorParent be superclass.
{ (proto, Some(superclass.clone()))
let class_object = class.as_object().expect("class must be object");
class_object.set_prototype(Some(superclass.clone()));
let mut class_object_mut = class_object.borrow_mut();
let class_function = class_object_mut
.as_function_mut()
.expect("class must be function object");
if let FunctionKind::Ordinary {
constructor_kind, ..
} = class_function.kind_mut()
{
*constructor_kind = ConstructorKind::Derived;
}
}
context.vm.push(class); // g. Else if IsConstructor(superclass) is false, then
context.vm.push(proto);
Ok(CompletionType::Normal)
} else if superclass.is_null() {
context.vm.push(JsValue::Null);
Ok(CompletionType::Normal)
} else { } else {
Err(JsNativeError::typ() // i. Throw a TypeError exception.
return Err(JsNativeError::typ()
.with_message("superclass must be a constructor") .with_message("superclass must be a constructor")
.into()) .into());
};
let class_object = class.as_object().expect("class must be object");
if let Some(constructor_parent) = constructor_parent {
class_object.set_prototype(Some(constructor_parent));
} }
let mut class_object_mut = class_object.borrow_mut();
let class_function = class_object_mut
.as_function_mut()
.expect("class must be function object");
// 17. If ClassHeritageopt is present, set F.[[ConstructorKind]] to derived.
if let FunctionKind::Ordinary {
constructor_kind, ..
} = class_function.kind_mut()
{
*constructor_kind = ConstructorKind::Derived;
}
drop(class_object_mut);
context.vm.push(class);
context.vm.push(proto_parent);
Ok(CompletionType::Normal)
} }
} }

1
boa_engine/src/vm/opcode/set/class_prototype.rs

@ -25,6 +25,7 @@ impl Operation for SetClassPrototype {
_ => unreachable!(), _ => unreachable!(),
}; };
// 9.Let proto be OrdinaryObjectCreate(protoParent).
let proto = JsObject::from_proto_and_data_with_shared_shape( let proto = JsObject::from_proto_and_data_with_shared_shape(
context.root_shape(), context.root_shape(),
prototype, prototype,

Loading…
Cancel
Save