Replace `as_bool` with `coerce_to_bool`.

Functions that need to assert Boolness without coercion should either:

1. Ensure their function declaration requires a Boolean. (We don't enforce type errors on ES4 typehints yet, but we should.)
2. Check the value type themselves and raise their own errors if necessary.

As it stands the only users of `as_bool` either needed to check the type themselves or use `coerce_to_bool`. Notably, `setPropertyIsEnumerable` doesn't appear to coerce *or* throw an error: it instead fails silently if you hand it a non-`Boolean` value.
This commit is contained in:
David Wendt 2020-06-23 19:26:05 -04:00 committed by Mike Welsh
parent 95ca978034
commit 5bb8c1836f
3 changed files with 27 additions and 19 deletions

View File

@ -1321,7 +1321,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
) -> Result<FrameControl<'gc>, Error> {
let value = self.context.avm2.pop().as_bool()?;
let value = self.context.avm2.pop().coerce_to_boolean();
if value {
reader.seek(offset as i64)?;
@ -1335,7 +1335,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
offset: i32,
reader: &mut Reader<Cursor<&[u8]>>,
) -> Result<FrameControl<'gc>, Error> {
let value = self.context.avm2.pop().as_bool()?;
let value = self.context.avm2.pop().coerce_to_boolean();
if !value {
reader.seek(offset as i64)?;

View File

@ -124,16 +124,17 @@ pub fn set_property_is_enumerable<'gc>(
let this = this?;
let name: Result<&Value<'gc>, Error> = args.get(0).ok_or_else(|| "No name specified".into());
let name = name?.as_string()?;
let is_enum = args
.get(1)
.cloned()
.unwrap_or(Value::Bool(true))
.as_bool()?;
if let Some(Value::Bool(is_enum)) = args.get(1) {
if let Some(ns) = this.resolve_any(name)? {
if !ns.is_private() {
let qname = QName::new(ns, name);
this.set_local_property_is_enumerable(activation.context.gc_context, &qname, is_enum)?;
this.set_local_property_is_enumerable(
activation.context.gc_context,
&qname,
*is_enum,
)?;
}
}
}

View File

@ -225,18 +225,25 @@ impl<'gc> Value<'gc> {
}
}
pub fn as_bool(&self) -> Result<bool, Error> {
if let Value::Bool(b) = self {
Ok(*b)
} else {
Err(format!("Expected Boolean, found {:?}", self).into())
}
}
pub fn as_namespace(&self) -> Result<&Namespace<'gc>, Error> {
match self {
Value::Namespace(ns) => Ok(ns),
_ => Err(format!("Expected Namespace, found {:?}", self).into()),
}
}
/// Coerce the value to a boolean.
///
/// Boolean coercion happens according to the rules specified in the ES4
/// draft proposals, which appear to be identical to ECMA-262 Edition 3.
pub fn coerce_to_boolean(&self) -> bool {
match self {
Value::Undefined | Value::Null => false,
Value::Bool(b) => *b,
Value::Number(f) => !f.is_nan() && f.abs() != 0.0,
Value::String(s) => !s.is_empty(),
Value::Namespace(_) => true,
Value::Object(_) => true,
}
}
}