Skip to content

avm2: fix coercion to function error for Vector.some and Array.some #21002

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
10 changes: 10 additions & 0 deletions core/src/avm2/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,16 @@ pub fn make_error_1003<'gc>(activation: &mut Activation<'_, 'gc>, radix: i32) ->
}
}

#[inline(never)]
#[cold]
pub fn make_error_1006<'gc>(activation: &mut Activation<'_, 'gc>) -> Error<'gc> {
let err = type_error(activation, "Error #1006: value is not a function.", 1006);
match err {
Ok(err) => Error::avm_error(err),
Err(err) => err,
}
}

#[inline(never)]
#[cold]
pub fn make_error_1010<'gc>(
Expand Down
36 changes: 12 additions & 24 deletions core/src/avm2/filters.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::avm2::error::{make_error_2008, type_error};
use crate::avm2::error::make_error_2008;
use crate::avm2::globals::flash::display::shader_job::get_shader_args;
use crate::avm2::globals::slots::flash_filters_bevel_filter as bevel_filter_slots;
use crate::avm2::globals::slots::flash_filters_blur_filter as blur_filter_slots;
Expand Down Expand Up @@ -168,13 +168,7 @@ impl FilterAvm2Ext for Filter {
)?));
}

Err(Error::avm_error(type_error(
activation,
&format!(
"Error #1034: Type Coercion failed: cannot convert {object:?} to flash.filters.BitmapFilter."
),
1034,
)?))
unreachable!("{object:?} must be of type BitmapFilter")
}

fn as_avm2_object<'gc>(
Expand Down Expand Up @@ -498,23 +492,17 @@ fn avm2_to_displacement_map_filter<'gc>(
let scale_y = object
.get_slot(displacement_map_filter_slots::SCALE_Y)
.coerce_to_number(activation)?;
let map_bitmap = if let Value::Object(bitmap) =
object.get_slot(displacement_map_filter_slots::MAP_BITMAP)
{
if let Some(bitmap) = bitmap.as_bitmap_data() {
Some(bitmap.bitmap_handle(activation.gc(), activation.context.renderer))
let map_bitmap =
if let Value::Object(bitmap) = object.get_slot(displacement_map_filter_slots::MAP_BITMAP) {
Some(
bitmap
.as_bitmap_data()
.unwrap()
.bitmap_handle(activation.gc(), activation.context.renderer),
)
} else {
return Err(Error::avm_error(type_error(
activation,
&format!(
"Error #1034: Type Coercion failed: cannot convert {bitmap:?} to flash.display.BitmapData."
),
1034,
)?));
}
} else {
None
};
None
};
Ok(Filter::DisplacementMapFilter(DisplacementMapFilter {
color: Color::from_rgb(color, (alpha * 255.0) as u8),
component_x: component_x as u8,
Expand Down
6 changes: 5 additions & 1 deletion core/src/avm2/globals/Array.as
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,11 @@ package {

AS3 native function slice(start:* = 0, end:* = 4294967295):Array;

AS3 native function some(callback:Function, receiver:* = null):Boolean;
AS3 function some(callback:*, receiver:Object = null):Boolean {
return _some(callback, receiver);
}

private native function _some(callback:Function, receiver:Object):Boolean;

AS3 native function sort(... rest):*;

Expand Down
6 changes: 5 additions & 1 deletion core/src/avm2/globals/VectorDouble.as
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,11 @@ package __AS3__.vec {

AS3 native function slice(start:Number = 0, end:Number = 2147483647):Vector$double;

AS3 native function some(callback:*, receiver:Object = null):Boolean;
AS3 function some(callback:*, receiver:Object = null):Boolean {
return _some(callback, receiver);
}

private native function _some(callback:Function, receiver:Object):Boolean;

AS3 native function sort(func:*):Vector$double;

Expand Down
6 changes: 5 additions & 1 deletion core/src/avm2/globals/VectorInt.as
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,11 @@ package __AS3__.vec {

AS3 native function slice(start:Number = 0, end:Number = 2147483647):Vector$int;

AS3 native function some(callback:*, receiver:Object = null):Boolean;
AS3 function some(callback:*, receiver:Object = null):Boolean {
return _some(callback, receiver);
}

private native function _some(callback:Function, receiver:Object):Boolean;

AS3 native function sort(func:*):Vector$int;

Expand Down
6 changes: 5 additions & 1 deletion core/src/avm2/globals/VectorObject.as
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,11 @@ package __AS3__.vec {

AS3 native function slice(start:Number = 0, end:Number = 2147483647):Vector$object;

AS3 native function some(callback:*, receiver:Object = null):Boolean;
AS3 function some(callback:*, receiver:Object = null):Boolean {
return _some(callback, receiver);
}

private native function _some(callback:Function, receiver:Object):Boolean;

AS3 native function sort(func:*):Vector$object;

Expand Down
6 changes: 5 additions & 1 deletion core/src/avm2/globals/VectorUint.as
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,11 @@ package __AS3__.vec {

AS3 native function slice(start:Number = 0, end:Number = 2147483647):Vector$uint;

AS3 native function some(callback:*, receiver:Object = null):Boolean;
AS3 function some(callback:*, receiver:Object = null):Boolean {
return _some(callback, receiver);
}

private native function _some(callback:Function, receiver:Object):Boolean;

AS3 native function sort(func:*):Vector$uint;

Expand Down
23 changes: 17 additions & 6 deletions core/src/avm2/globals/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,10 @@ pub fn for_each<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

let callback = args.get_value(0);
let callback = match args.get_value(0) {
Value::Null => return Ok(Value::Undefined),
value => value,
};
let receiver = args.get_value(1);
let mut iter = ArrayIter::new(activation, this)?;

Expand Down Expand Up @@ -351,7 +354,10 @@ pub fn filter<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

let callback = args.get_value(0);
let callback = match args.get_value(0) {
Value::Null => return Ok(ArrayObject::empty(activation).into()),
value => value,
};
let receiver = args.get_value(1);
let mut new_array = ArrayStorage::new(0);
let mut iter = ArrayIter::new(activation, this)?;
Expand All @@ -377,7 +383,10 @@ pub fn every<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

let callback = args.get_value(0);
let callback = match args.get_value(0) {
Value::Null => return Ok(true.into()),
value => value,
};
let receiver = args.get_value(1);
let mut iter = ArrayIter::new(activation, this)?;

Expand All @@ -394,15 +403,17 @@ pub fn every<'gc>(
Ok(true.into())
}

/// Implements `Array.some`
pub fn some<'gc>(
pub fn _some<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

let callback = args.get_value(0);
let callback = match args.get_value(0) {
Value::Null => return Ok(false.into()),
value => value,
};
let receiver = args.get_value(1);
let mut iter = ArrayIter::new(activation, this)?;

Expand Down
88 changes: 20 additions & 68 deletions core/src/avm2/globals/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,55 +262,21 @@ pub fn join<'gc>(
Ok(Value::Undefined)
}

/// Implements `Vector.every`
pub fn every<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

let callback = args.get_value(0);
let receiver = args.get_value(1);
let mut iter = ArrayIter::new(activation, this)?;

while let Some((i, item)) = iter.next(activation)? {
let result = callback
.call(activation, receiver, &[item, i.into(), this.into()])?
.coerce_to_boolean();

if !result {
return Ok(false.into());
macro_rules! delegate_method_to_array {
($method:ident) => {
pub fn $method<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
super::array::$method(activation, this, args)
}
}

Ok(true.into())
};
}

/// Implements `Vector.some`
pub fn some<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

let callback = args.get_value(0);
let receiver = args.get_value(1);
let mut iter = ArrayIter::new(activation, this)?;

while let Some((i, item)) = iter.next(activation)? {
let result = callback
.call(activation, receiver, &[item, i.into(), this.into()])?
.coerce_to_boolean();

if result {
return Ok(true.into());
}
}

Ok(false.into())
}
delegate_method_to_array!(every);
delegate_method_to_array!(_some);
delegate_method_to_array!(for_each);

/// Implements `Vector.filter`
pub fn filter<'gc>(
Expand All @@ -320,14 +286,19 @@ pub fn filter<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

let callback = args.get_value(0);
let receiver = args.get_value(1);

let value_type = this
.instance_class()
.param()
.expect("Receiver is parametrized vector"); // technically unreachable

let mut new_storage = VectorStorage::new(0, false, value_type, activation);

let callback = match args.get_value(0) {
Value::Null => return Ok(VectorObject::from_vector(new_storage, activation)?.into()),
value => value,
};
let receiver = args.get_value(1);

let mut iter = ArrayIter::new(activation, this)?;

while let Some((i, item)) = iter.next(activation)? {
Expand All @@ -343,25 +314,6 @@ pub fn filter<'gc>(
Ok(VectorObject::from_vector(new_storage, activation)?.into())
}

/// Implements `Vector.forEach`
pub fn for_each<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Value<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let this = this.as_object().unwrap();

let callback = args.get_value(0);
let receiver = args.get_value(1);
let mut iter = ArrayIter::new(activation, this)?;

while let Some((i, item)) = iter.next(activation)? {
callback.call(activation, receiver, &[item, i.into(), this.into()])?;
}

Ok(Value::Undefined)
}

/// Implements `Vector.indexOf`
pub fn index_of<'gc>(
activation: &mut Activation<'_, 'gc>,
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm2/globals/vector_double.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use crate::avm2::globals::vector::{
reverse,
shift,
slice,
some,
_some,
sort,
splice,
unshift,
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm2/globals/vector_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use crate::avm2::globals::vector::{
reverse,
shift,
slice,
some,
_some,
sort,
splice,
unshift,
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm2/globals/vector_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use crate::avm2::globals::vector::{
reverse,
shift,
slice,
some,
_some,
sort,
splice,
unshift,
Expand Down
2 changes: 1 addition & 1 deletion core/src/avm2/globals/vector_uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use crate::avm2::globals::vector::{
reverse,
shift,
slice,
some,
_some,
sort,
splice,
unshift,
Expand Down
16 changes: 4 additions & 12 deletions core/src/avm2/value.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! AVM2 values

use crate::avm2::activation::Activation;
use crate::avm2::error;
use crate::avm2::error::type_error;
use crate::avm2::error::{self};
use crate::avm2::error::{make_error_1006, type_error};
use crate::avm2::function::{exec, FunctionArgs};
use crate::avm2::object::{NamespaceObject, Object, TObject};
use crate::avm2::property::Property;
Expand Down Expand Up @@ -1175,11 +1175,7 @@ impl<'gc> Value<'gc> {
if let Some(value) = dynamic_lookup {
value.call(activation, *self, arguments)
} else {
Err(Error::avm_error(type_error(
activation,
"Error #1006: value is not a function.",
1006,
)?))
Err(make_error_1006(activation))
}
}
}
Expand Down Expand Up @@ -1364,11 +1360,7 @@ impl<'gc> Value<'gc> {
Some(Object::FunctionObject(function_object)) => {
function_object.call(activation, receiver, args)
}
_ => Err(Error::avm_error(type_error(
activation,
"Error #1006: value is not a function.",
1006,
)?)),
_ => Err(make_error_1006(activation)),
}
}

Expand Down
1 change: 0 additions & 1 deletion tests/tests/swfs/from_avmplus/as3/Vector/some/test.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
num_ticks = 1
known_failure = true # https://github.com/ruffle-rs/ruffle/issues/12321
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
num_ticks = 1
known_failure = true # https://github.com/ruffle-rs/ruffle/issues/12321
Loading