Allow `is_instance_of` to inspect the prototype chains of implemented interfaces.
This makes the `extends_chain` test pass.
This commit is contained in:
parent
854526923e
commit
33c66571f5
|
@ -837,7 +837,7 @@ impl<'gc> Avm1<'gc> {
|
|||
.resolve(self, context)?
|
||||
.as_object()?;
|
||||
|
||||
if obj.is_instance_of(self, constr, prototype) {
|
||||
if obj.is_instance_of(self, context, constr, prototype)? {
|
||||
self.push(obj);
|
||||
} else {
|
||||
self.push(Value::Null);
|
||||
|
@ -1430,8 +1430,9 @@ impl<'gc> Avm1<'gc> {
|
|||
.get("prototype", self, context)?
|
||||
.resolve(self, context)?
|
||||
.as_object()?;
|
||||
let is_instance_of = obj.is_instance_of(self, context, constr, prototype)?;
|
||||
|
||||
self.push(obj.is_instance_of(self, constr, prototype));
|
||||
self.push(is_instance_of);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -197,31 +197,50 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
/// The class is provided in the form of it's constructor function and the
|
||||
/// explicit prototype of that constructor function. It is assumed that
|
||||
/// they are already linked.
|
||||
///
|
||||
/// Because ActionScript 2.0 added interfaces, this function cannot simply
|
||||
/// check the prototype chain and call it a day. Each interface represents
|
||||
/// a new, parallel prototype chain which also needs to be checked. You
|
||||
/// can't implement interfaces within interfaces (fortunately), but if you
|
||||
/// somehow could this would support that, too.
|
||||
fn is_instance_of(
|
||||
&self,
|
||||
avm: &Avm1<'gc>,
|
||||
avm: &mut Avm1<'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
constructor: Object<'gc>,
|
||||
prototype: Object<'gc>,
|
||||
) -> bool {
|
||||
let mut proto = self.proto();
|
||||
) -> Result<bool, Error> {
|
||||
let mut proto_stack = vec![];
|
||||
if let Some(p) = self.proto() {
|
||||
proto_stack.push(p);
|
||||
}
|
||||
|
||||
while let Some(this_proto) = proto {
|
||||
while let Some(this_proto) = proto_stack.pop() {
|
||||
if Object::ptr_eq(this_proto, prototype) {
|
||||
return true;
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(p) = this_proto.proto() {
|
||||
proto_stack.push(p);
|
||||
}
|
||||
|
||||
if avm.current_swf_version() >= 7 {
|
||||
for interface in this_proto.interfaces() {
|
||||
if Object::ptr_eq(interface, constructor) {
|
||||
return true;
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Value::Object(o) = interface
|
||||
.get("prototype", avm, context)?
|
||||
.resolve(avm, context)?
|
||||
{
|
||||
proto_stack.push(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proto = this_proto.proto();
|
||||
}
|
||||
|
||||
false
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Get the underlying script object, if it exists.
|
||||
|
|
Loading…
Reference in New Issue