Allow overwriting read-only virtual properties in scope chains.

The previous behavior had an oversight: if you tried to set a variable with the same name as an in-scope property, it would always try to overwrite that property. This can fail silently and doesn't match with Flash Player behavior. Now, an attempt to overwrite a read-only property is instead correctly rejected so that it can be defined in local scope.
This commit is contained in:
David Wendt 2019-11-23 22:00:37 -05:00
parent bae0476113
commit b8c24890fc
2 changed files with 17 additions and 1 deletions

View File

@ -108,6 +108,15 @@ impl<'gc> Property<'gc> {
Property::Stored { attributes, .. } => !attributes.contains(DontEnum),
}
}
pub fn is_overwritable(&self) -> bool {
match self {
Property::Virtual {
attributes, set, ..
} => !attributes.contains(ReadOnly) && !set.is_none(),
Property::Stored { attributes, .. } => !attributes.contains(ReadOnly),
}
}
}
unsafe impl<'gc> gc_arena::Collect for Property<'gc> {
@ -339,6 +348,13 @@ impl<'gc> Object<'gc> {
self.values.contains_key(name)
}
pub fn is_property_overwritable(&self, name: &str) -> bool {
self.values
.get(name)
.map(|p| p.is_overwritable())
.unwrap_or(false)
}
pub fn get_keys(&self) -> Vec<String> {
self.values
.iter()

View File

@ -288,7 +288,7 @@ impl<'gc> Scope<'gc> {
context: &mut UpdateContext<'_, 'gc, '_>,
this: GcCell<'gc, Object<'gc>>,
) -> Result<Option<Value<'gc>>, Error> {
if self.locals().has_property(name) {
if self.locals().has_property(name) && self.locals().is_property_overwritable(name) {
self.locals_mut(context.gc_context)
.set(name, value, avm, context, this)?;
return Ok(None);