avm1: Correct `base_proto` for constructions
Previously constructions had `base_proto` set to the newly-created object (`this`). However this doesn't match the `base_proto` of method calls, which is `this.__proto__` (or more precisely where the function is found on the prototype chain). This caused wrong behavior when using the `super` object from within constructors. Change `base_proto` in that case to be `this.__proto__`, which aligns with method calls. In order to keep things working, `SuperObject::call` needs to look-up one level less than before. An alternative can be changing `base_proto` for method calls instead, but that seems to be harder because this would require `search_prototype` to return the before-last visited object in the prototype chain.
This commit is contained in:
parent
1772def6e6
commit
7008f9bacc
|
@ -582,18 +582,19 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
|||
Attribute::DONT_ENUM,
|
||||
);
|
||||
}
|
||||
let base_proto = this.proto(activation).coerce_to_object(activation);
|
||||
if let Some(exec) = &self.data.read().constructor {
|
||||
let _ = exec.exec(
|
||||
"[ctor]",
|
||||
activation,
|
||||
this,
|
||||
None,
|
||||
Some(base_proto),
|
||||
args,
|
||||
ExecutionReason::FunctionCall,
|
||||
(*self).into(),
|
||||
)?;
|
||||
} else {
|
||||
let _ = self.call("[ctor]".into(), activation, this, None, args)?;
|
||||
let _ = self.call("[ctor]".into(), activation, this, Some(base_proto), args)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -629,14 +630,14 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
|
|||
"[ctor]",
|
||||
activation,
|
||||
this,
|
||||
None,
|
||||
Some(prototype),
|
||||
args,
|
||||
ExecutionReason::FunctionCall,
|
||||
(*self).into(),
|
||||
)?;
|
||||
Ok(this)
|
||||
} else {
|
||||
let _ = self.call("[ctor]".into(), activation, this, None, args)?;
|
||||
let _ = self.call("[ctor]".into(), activation, this, Some(prototype), args)?;
|
||||
Ok(this.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,15 +74,15 @@ impl<'gc> TObject<'gc> for SuperObject<'gc> {
|
|||
_base_proto: Option<Object<'gc>>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Value::Object(proto) = self.proto(activation) {
|
||||
let constructor = proto
|
||||
let constructor = self
|
||||
.0
|
||||
.read()
|
||||
.base_proto
|
||||
.get("__constructor__", activation)?
|
||||
.coerce_to_object(activation);
|
||||
let this = self.0.read().this;
|
||||
constructor.call(name, activation, this, Some(proto), args)
|
||||
} else {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
let base_proto = self.proto(activation).coerce_to_object(activation);
|
||||
constructor.call(name, activation, this, Some(base_proto), args)
|
||||
}
|
||||
|
||||
fn call_method(
|
||||
|
|
Loading…
Reference in New Issue