From 0f2b77c1386334976197c3280fc5ff7bcc8e042f Mon Sep 17 00:00:00 2001 From: David Wendt Date: Fri, 11 Feb 2022 17:53:14 -0500 Subject: [PATCH] avm2: Alter basic object operations to use more descriptive error messages. --- core/src/avm2/object.rs | 38 ++++++++++++++++--------- core/src/avm2/object/script_object.rs | 40 ++++++++++++++++++++------- 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 34de068e8..6ea17f6a1 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -274,7 +274,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy let result = self .base() .get_property_local(multiname, activation)? - .coerce_to_object(activation)?; + .as_callable(activation, Some(multiname), Some(self.into()))?; + result.call(Some(self.into()), arguments, activation) } @@ -292,10 +293,12 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy ) -> Result, Error> { match self.vtable().and_then(|vtable| vtable.get_trait(multiname)) { Some(Property::Slot { slot_id }) | Some(Property::ConstSlot { slot_id }) => { - let obj = self - .base() - .get_slot(slot_id)? - .coerce_to_object(activation)?; + let obj = self.base().get_slot(slot_id)?.as_callable( + activation, + Some(multiname), + Some(self.into()), + )?; + obj.call(Some(self.into()), arguments, activation) } Some(Property::Method { disp_id }) => { @@ -328,9 +331,12 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy } } Some(Property::Virtual { get: Some(get), .. }) => { - let obj = self - .call_method(get, &[], activation)? - .coerce_to_object(activation)?; + let obj = self.call_method(get, &[], activation)?.as_callable( + activation, + Some(multiname), + Some(self.into()), + )?; + obj.call(Some(self.into()), arguments, activation) } Some(Property::Virtual { get: None, .. }) => { @@ -642,9 +648,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy args: &[Value<'gc>], activation: &mut Activation<'_, 'gc, '_>, ) -> Result, Error> { - let ctor = self - .get_property(multiname, activation)? - .coerce_to_object(activation)?; + let ctor = self.get_property(multiname, activation)?.as_callable( + activation, + Some(multiname), + Some(self.into()), + )?; ctor.construct(activation, args) } @@ -739,9 +747,13 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy ) -> Result { let type_proto = class .get_property(&QName::dynamic_name("prototype").into(), activation)? - .coerce_to_object(activation)?; + .as_object(); - self.has_prototype_in_chain(type_proto) + if let Some(type_proto) = type_proto { + self.has_prototype_in_chain(type_proto) + } else { + Ok(false) + } } /// Determine if this object has a given prototype in its prototype chain. diff --git a/core/src/avm2/object/script_object.rs b/core/src/avm2/object/script_object.rs index e5e8b05d3..135efddab 100644 --- a/core/src/avm2/object/script_object.rs +++ b/core/src/avm2/object/script_object.rs @@ -138,13 +138,21 @@ impl<'gc> ScriptObjectData<'gc> { activation: &mut Activation<'_, 'gc, '_>, ) -> Result, Error> { if !multiname.contains_public_namespace() { - return Err( - format!("Non-public property `{:?}` not found on Object", multiname).into(), - ); + return Err(format!( + "Non-public property {} not found on Object", + multiname.to_qualified_name(activation.context.gc_context) + ) + .into()); } let local_name = match multiname.local_name() { - None => return Err("Unnamed property not found on Object".into()), + None => { + return Err(format!( + "Unnamed property {} not found on Object", + multiname.to_qualified_name(activation.context.gc_context) + ) + .into()) + } Some(name) => name, }; @@ -174,24 +182,36 @@ impl<'gc> ScriptObjectData<'gc> { &mut self, multiname: &Multiname<'gc>, value: Value<'gc>, - _activation: &mut Activation<'_, 'gc, '_>, + activation: &mut Activation<'_, 'gc, '_>, ) -> Result<(), Error> { if self .instance_of() .map(|cls| cls.inner_class_definition().read().is_sealed()) .unwrap_or(false) { - return Err( - format!("Cannot set undefined property {:?}", multiname.local_name()).into(), - ); + return Err(format!( + "Cannot set undefined property {}", + multiname.to_qualified_name(activation.context.gc_context) + ) + .into()); } if !multiname.contains_public_namespace() { - return Err("Non-public property not found on Object".into()); + return Err(format!( + "Non-public property {} not found on Object", + multiname.to_qualified_name(activation.context.gc_context) + ) + .into()); } let local_name = match multiname.local_name() { - None => return Err("Unnamed property not found on Object".into()), + None => { + return Err(format!( + "Unnamed property {} not found on Object", + multiname.to_qualified_name(activation.context.gc_context) + ) + .into()) + } Some(name) => name, };