avm2: Correctly differentiate between Any and null Multiname
This commit is contained in:
parent
6a9f4b665a
commit
ed9b250d0a
|
@ -518,7 +518,7 @@ impl<'gc> Class<'gc> {
|
|||
// A 'callable' class doesn't have a signature - let the
|
||||
// method do any needed coercions
|
||||
vec![],
|
||||
activation.avm2().multinames.any,
|
||||
None,
|
||||
true,
|
||||
activation.context.gc_context,
|
||||
);
|
||||
|
@ -1022,8 +1022,12 @@ impl<'gc> Class<'gc> {
|
|||
value: Value<'gc>,
|
||||
) {
|
||||
self.define_instance_trait(
|
||||
activation.context.gc_context,
|
||||
Trait::from_const(name, activation.avm2().multinames.function, Some(value)),
|
||||
activation.gc(),
|
||||
Trait::from_const(
|
||||
name,
|
||||
Some(activation.avm2().multinames.function),
|
||||
Some(value),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1036,10 +1040,10 @@ impl<'gc> Class<'gc> {
|
|||
) {
|
||||
for &(name, value) in items {
|
||||
self.define_class_trait(
|
||||
activation.context.gc_context,
|
||||
activation.gc(),
|
||||
Trait::from_const(
|
||||
QName::new(namespace, name),
|
||||
activation.avm2().multinames.number,
|
||||
Some(activation.avm2().multinames.number),
|
||||
Some(value.into()),
|
||||
),
|
||||
);
|
||||
|
@ -1055,10 +1059,10 @@ impl<'gc> Class<'gc> {
|
|||
) {
|
||||
for &(name, value) in items {
|
||||
self.define_class_trait(
|
||||
activation.context.gc_context,
|
||||
activation.gc(),
|
||||
Trait::from_const(
|
||||
QName::new(namespace, name),
|
||||
activation.avm2().multinames.uint,
|
||||
Some(activation.avm2().multinames.uint),
|
||||
Some(value.into()),
|
||||
),
|
||||
);
|
||||
|
@ -1077,7 +1081,7 @@ impl<'gc> Class<'gc> {
|
|||
activation.context.gc_context,
|
||||
Trait::from_const(
|
||||
QName::new(namespace, name),
|
||||
activation.avm2().multinames.int,
|
||||
Some(activation.avm2().multinames.int),
|
||||
Some(value.into()),
|
||||
),
|
||||
);
|
||||
|
@ -1111,7 +1115,7 @@ impl<'gc> Class<'gc> {
|
|||
&'static str,
|
||||
NativeMethodImpl,
|
||||
Vec<ParamConfig<'gc>>,
|
||||
Gc<'gc, Multiname<'gc>>,
|
||||
Option<Gc<'gc, Multiname<'gc>>>,
|
||||
)>,
|
||||
) {
|
||||
for (name, value, params, return_type) in items {
|
||||
|
@ -1188,7 +1192,7 @@ impl<'gc> Class<'gc> {
|
|||
activation.context.gc_context,
|
||||
Trait::from_const(
|
||||
QName::new(namespace, name),
|
||||
activation.avm2().multinames.int,
|
||||
Some(activation.avm2().multinames.int),
|
||||
Some(value.into()),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -221,7 +221,7 @@ impl<'gc> Domain<'gc> {
|
|||
|
||||
if let Some(class) = class {
|
||||
if let Some(param) = multiname.param() {
|
||||
if !param.is_any_name() {
|
||||
if let Some(param) = param {
|
||||
if let Some(resolved_param) = self.get_class(context, ¶m) {
|
||||
return Some(Class::with_type_param(context, class, Some(resolved_param)));
|
||||
}
|
||||
|
|
|
@ -118,10 +118,10 @@ impl<'gc> BoundMethod<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn return_type(&self) -> &Multiname<'gc> {
|
||||
pub fn return_type(&self) -> Option<Gc<'gc, Multiname<'gc>>> {
|
||||
match &self.method {
|
||||
Method::Native(method) => &method.return_type,
|
||||
Method::Bytecode(method) => &method.return_type,
|
||||
Method::Native(method) => method.return_type,
|
||||
Method::Bytecode(method) => method.return_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -612,7 +612,7 @@ pub fn load_player_globals<'gc>(
|
|||
// right now.
|
||||
global_traits.push(Trait::from_const(
|
||||
qname,
|
||||
activation.avm2().multinames.function,
|
||||
Some(activation.avm2().multinames.function),
|
||||
Some(Value::Null),
|
||||
));
|
||||
}
|
||||
|
|
|
@ -5,10 +5,14 @@ use crate::avm2::method::Method;
|
|||
use crate::avm2::object::{ArrayObject, TObject};
|
||||
use crate::avm2::parameters::ParametersExt;
|
||||
use crate::avm2::property::Property;
|
||||
|
||||
use crate::avm2::{Activation, Error, Multiname, Namespace, Object, Value};
|
||||
use crate::context::GcContext;
|
||||
use crate::string::AvmString;
|
||||
|
||||
use crate::avm2_stub_method;
|
||||
|
||||
use gc_arena::Gc;
|
||||
|
||||
// Implements `avmplus.describeTypeJSON`
|
||||
pub fn describe_type_json<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
|
@ -357,10 +361,8 @@ fn describe_internal_body<'gc>(
|
|||
continue;
|
||||
}
|
||||
|
||||
let return_type_name = method
|
||||
.method
|
||||
.return_type()
|
||||
.to_qualified_name_or_star(&mut activation.borrow_gc());
|
||||
let return_type_name =
|
||||
display_name(&mut activation.borrow_gc(), method.method.return_type());
|
||||
let declared_by = method.class;
|
||||
|
||||
if flags.contains(DescribeTypeFlags::HIDE_OBJECT)
|
||||
|
@ -457,8 +459,7 @@ fn describe_internal_body<'gc>(
|
|||
Some(ns.as_uri())
|
||||
};
|
||||
|
||||
let accessor_type =
|
||||
method_type.to_qualified_name_or_star(&mut activation.borrow_gc());
|
||||
let accessor_type = display_name(&mut activation.borrow_gc(), method_type);
|
||||
let declared_by = defining_class.dollar_removed_name(mc).to_qualified_name(mc);
|
||||
|
||||
let accessor_obj = activation
|
||||
|
@ -535,6 +536,17 @@ fn describe_internal_body<'gc>(
|
|||
Ok(traits)
|
||||
}
|
||||
|
||||
fn display_name<'gc>(
|
||||
context: &mut GcContext<'_, 'gc>,
|
||||
name: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
) -> AvmString<'gc> {
|
||||
if let Some(name) = name {
|
||||
name.to_qualified_name_or_star(context)
|
||||
} else {
|
||||
context.interner.get_ascii_char('*')
|
||||
}
|
||||
}
|
||||
|
||||
fn write_params<'gc>(
|
||||
method: &Method<'gc>,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
|
@ -544,9 +556,7 @@ fn write_params<'gc>(
|
|||
.as_array_storage_mut(activation.context.gc_context)
|
||||
.unwrap();
|
||||
for param in method.signature() {
|
||||
let param_type_name = param
|
||||
.param_type_name
|
||||
.to_qualified_name_or_star(&mut activation.borrow_gc());
|
||||
let param_type_name = display_name(&mut activation.borrow_gc(), param.param_type_name);
|
||||
let optional = param.default_value.is_some();
|
||||
let param_obj = activation
|
||||
.avm2()
|
||||
|
|
|
@ -227,10 +227,10 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> {
|
|||
"<int instance initializer>",
|
||||
vec![ParamConfig {
|
||||
param_name: AvmString::new_utf8(activation.context.gc_context, "value"),
|
||||
param_type_name: activation.avm2().multinames.any,
|
||||
param_type_name: None,
|
||||
default_value: Some(Value::Integer(0)),
|
||||
}],
|
||||
activation.avm2().multinames.any,
|
||||
None,
|
||||
true,
|
||||
mc,
|
||||
),
|
||||
|
|
|
@ -276,32 +276,20 @@ pub fn create_i_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> {
|
|||
(
|
||||
"hasOwnProperty",
|
||||
has_own_property,
|
||||
vec![ParamConfig::optional(
|
||||
"name",
|
||||
activation.avm2().multinames.any,
|
||||
Value::Undefined,
|
||||
)],
|
||||
activation.avm2().multinames.boolean,
|
||||
vec![ParamConfig::optional("name", None, Value::Undefined)],
|
||||
Some(activation.avm2().multinames.boolean),
|
||||
),
|
||||
(
|
||||
"isPrototypeOf",
|
||||
is_prototype_of,
|
||||
vec![ParamConfig::optional(
|
||||
"theClass",
|
||||
activation.avm2().multinames.any,
|
||||
Value::Undefined,
|
||||
)],
|
||||
activation.avm2().multinames.boolean,
|
||||
vec![ParamConfig::optional("theClass", None, Value::Undefined)],
|
||||
Some(activation.avm2().multinames.boolean),
|
||||
),
|
||||
(
|
||||
"propertyIsEnumerable",
|
||||
property_is_enumerable,
|
||||
vec![ParamConfig::optional(
|
||||
"name",
|
||||
activation.avm2().multinames.any,
|
||||
Value::Undefined,
|
||||
)],
|
||||
activation.avm2().multinames.boolean,
|
||||
vec![ParamConfig::optional("name", None, Value::Undefined)],
|
||||
Some(activation.avm2().multinames.boolean),
|
||||
),
|
||||
];
|
||||
object_i_class.define_builtin_instance_methods_with_sig(
|
||||
|
@ -336,7 +324,7 @@ pub fn create_c_class<'gc>(
|
|||
gc_context,
|
||||
Trait::from_const(
|
||||
QName::new(activation.avm2().public_namespace_base_version, "length"),
|
||||
activation.avm2().multinames.int,
|
||||
Some(activation.avm2().multinames.int),
|
||||
Some(1.into()),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -228,10 +228,10 @@ pub fn create_class<'gc>(activation: &mut Activation<'_, 'gc>) -> Class<'gc> {
|
|||
"<uint instance initializer>",
|
||||
vec![ParamConfig {
|
||||
param_name: AvmString::new_utf8(activation.context.gc_context, "value"),
|
||||
param_type_name: activation.avm2().multinames.any,
|
||||
param_type_name: None,
|
||||
default_value: Some(Value::Integer(0)),
|
||||
}],
|
||||
activation.avm2().multinames.any,
|
||||
None,
|
||||
true,
|
||||
mc,
|
||||
),
|
||||
|
|
|
@ -60,7 +60,7 @@ pub struct ParamConfig<'gc> {
|
|||
pub param_name: AvmString<'gc>,
|
||||
|
||||
/// The name of the type of the parameter.
|
||||
pub param_type_name: Gc<'gc, Multiname<'gc>>,
|
||||
pub param_type_name: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
|
||||
/// The default value for this parameter.
|
||||
pub default_value: Option<Value<'gc>>,
|
||||
|
@ -96,7 +96,7 @@ impl<'gc> ParamConfig<'gc> {
|
|||
|
||||
pub fn of_type(
|
||||
name: impl Into<AvmString<'gc>>,
|
||||
param_type_name: Gc<'gc, Multiname<'gc>>,
|
||||
param_type_name: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
param_name: name.into(),
|
||||
|
@ -107,7 +107,7 @@ impl<'gc> ParamConfig<'gc> {
|
|||
|
||||
pub fn optional(
|
||||
name: impl Into<AvmString<'gc>>,
|
||||
param_type_name: Gc<'gc, Multiname<'gc>>,
|
||||
param_type_name: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
default_value: impl Into<Value<'gc>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -140,8 +140,9 @@ pub struct BytecodeMethod<'gc> {
|
|||
/// The parameter signature of this method.
|
||||
pub signature: Vec<ParamConfig<'gc>>,
|
||||
|
||||
/// The return type of this method.
|
||||
pub return_type: Gc<'gc, Multiname<'gc>>,
|
||||
/// The return type of this method, or None if the method does not coerce
|
||||
/// its return value.
|
||||
pub return_type: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
|
||||
/// The associated activation class. Initialized lazily, and only
|
||||
/// if the method requires it.
|
||||
|
@ -164,7 +165,7 @@ impl<'gc> BytecodeMethod<'gc> {
|
|||
) -> Result<Self, Error<'gc>> {
|
||||
let abc = txunit.abc();
|
||||
let mut signature = Vec::new();
|
||||
let mut return_type = activation.avm2().multinames.any;
|
||||
let mut return_type = None;
|
||||
let mut abc_method_body = None;
|
||||
|
||||
if abc.methods.get(abc_method.0 as usize).is_some() {
|
||||
|
@ -289,7 +290,7 @@ impl<'gc> BytecodeMethod<'gc> {
|
|||
}
|
||||
|
||||
for param in self.signature() {
|
||||
if !param.param_type_name.is_any_name() || param.default_value.is_some() {
|
||||
if param.param_type_name.is_some() || param.default_value.is_some() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -336,8 +337,9 @@ pub struct NativeMethod<'gc> {
|
|||
/// The resolved parameter signature of the method.
|
||||
pub resolved_signature: GcCell<'gc, Option<Vec<ResolvedParamConfig<'gc>>>>,
|
||||
|
||||
/// The return type of this method.
|
||||
pub return_type: Gc<'gc, Multiname<'gc>>,
|
||||
/// The return type of this method, or None if the method does not coerce
|
||||
/// its return value.
|
||||
pub return_type: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
|
||||
/// Whether or not this method accepts parameters beyond those
|
||||
/// mentioned in the parameter list.
|
||||
|
@ -391,7 +393,7 @@ impl<'gc> Method<'gc> {
|
|||
method: NativeMethodImpl,
|
||||
name: &'static str,
|
||||
signature: Vec<ParamConfig<'gc>>,
|
||||
return_type: Gc<'gc, Multiname<'gc>>,
|
||||
return_type: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
is_variadic: bool,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> Self {
|
||||
|
@ -418,7 +420,7 @@ impl<'gc> Method<'gc> {
|
|||
signature: Vec::new(),
|
||||
resolved_signature: GcCell::new(mc, None),
|
||||
// FIXME - take in the real return type. This is needed for 'describeType'
|
||||
return_type: Gc::new(mc, Multiname::any()),
|
||||
return_type: None,
|
||||
is_variadic: true,
|
||||
},
|
||||
))
|
||||
|
@ -436,7 +438,7 @@ impl<'gc> Method<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn return_type(&self) -> Gc<'gc, Multiname<'gc>> {
|
||||
pub fn return_type(&self) -> Option<Gc<'gc, Multiname<'gc>>> {
|
||||
match self {
|
||||
Method::Native(nm) => nm.return_type,
|
||||
Method::Bytecode(bm) => bm.return_type,
|
||||
|
|
|
@ -96,8 +96,9 @@ pub struct Multiname<'gc> {
|
|||
name: Option<AvmString<'gc>>,
|
||||
|
||||
/// The type parameter required to satisfy this multiname. If None, then
|
||||
/// this multiname is satisfied by any type parameter or no type parameter
|
||||
param: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
/// this multiname does not have a type parameter. If Some(None), then
|
||||
/// this multiname uses the Any type parameter (`*`).
|
||||
param: Option<Option<Gc<'gc, Multiname<'gc>>>>,
|
||||
|
||||
#[collect(require_static)]
|
||||
flags: MultinameFlags,
|
||||
|
@ -287,6 +288,7 @@ impl<'gc> Multiname<'gc> {
|
|||
) {
|
||||
multiname.flags |= MultinameFlags::ATTRIBUTE;
|
||||
}
|
||||
|
||||
Ok(multiname)
|
||||
}
|
||||
|
||||
|
@ -436,7 +438,7 @@ impl<'gc> Multiname<'gc> {
|
|||
}
|
||||
|
||||
/// List the parameters that the selected class must match.
|
||||
pub fn param(&self) -> Option<Gc<'gc, Multiname<'gc>>> {
|
||||
pub fn param(&self) -> Option<Option<Gc<'gc, Multiname<'gc>>>> {
|
||||
self.param
|
||||
}
|
||||
|
||||
|
@ -461,7 +463,11 @@ impl<'gc> Multiname<'gc> {
|
|||
|
||||
if let Some(param) = self.param {
|
||||
uri.push_str(WStr::from_units(b".<"));
|
||||
if let Some(param) = param {
|
||||
uri.push_str(¶m.to_qualified_name(mc));
|
||||
} else {
|
||||
uri.push_str(WStr::from_units(b"*"));
|
||||
}
|
||||
uri.push_str(WStr::from_units(b">"));
|
||||
}
|
||||
|
||||
|
@ -529,8 +535,6 @@ impl<'gc> From<QName<'gc>> for Multiname<'gc> {
|
|||
#[derive(Collect)]
|
||||
#[collect(no_drop)]
|
||||
pub struct CommonMultinames<'gc> {
|
||||
pub any: Gc<'gc, Multiname<'gc>>,
|
||||
|
||||
pub boolean: Gc<'gc, Multiname<'gc>>,
|
||||
pub function: Gc<'gc, Multiname<'gc>>,
|
||||
pub int: Gc<'gc, Multiname<'gc>>,
|
||||
|
@ -558,7 +562,6 @@ impl<'gc> CommonMultinames<'gc> {
|
|||
};
|
||||
|
||||
Self {
|
||||
any: Gc::new(mc, Multiname::any()),
|
||||
boolean: create_pub_multiname(b"Boolean"),
|
||||
function: create_pub_multiname(b"Function"),
|
||||
int: create_pub_multiname(b"int"),
|
||||
|
|
|
@ -39,7 +39,7 @@ pub fn function_allocator<'gc>(
|
|||
name: "<Empty Function>",
|
||||
signature: vec![],
|
||||
resolved_signature: GcCell::new(mc, None),
|
||||
return_type: activation.avm2().multinames.any,
|
||||
return_type: None,
|
||||
is_variadic: true,
|
||||
},
|
||||
);
|
||||
|
|
|
@ -47,10 +47,14 @@ pub enum PropertyClass<'gc> {
|
|||
impl<'gc> PropertyClass<'gc> {
|
||||
pub fn name(
|
||||
mc: &Mutation<'gc>,
|
||||
name: Gc<'gc, Multiname<'gc>>,
|
||||
name: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
unit: Option<TranslationUnit<'gc>>,
|
||||
) -> Self {
|
||||
if let Some(name) = name {
|
||||
PropertyClass::Name(Gc::new(mc, (name, unit)))
|
||||
} else {
|
||||
PropertyClass::Any
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `value` coerced to the type of this `PropertyClass`.
|
||||
|
@ -65,27 +69,21 @@ impl<'gc> PropertyClass<'gc> {
|
|||
PropertyClass::Class(class) => (Some(*class), false),
|
||||
PropertyClass::Name(gc) => {
|
||||
let (name, unit) = &**gc;
|
||||
if name.is_any_namespace() && name.is_any_name() {
|
||||
*self = PropertyClass::Any;
|
||||
(None, true)
|
||||
} else {
|
||||
|
||||
// Note - we look up the class in the domain by name, which allows us to look up private classes.
|
||||
// This also has the advantage of letting us coerce to a class while the `ClassObject`
|
||||
// is still being constructed (since the `Class` will already exist in the domain).
|
||||
|
||||
// We should only be missing a translation unit when performing a lookup from playerglobals,
|
||||
// so use that domain if we don't have a translation unit.
|
||||
let domain =
|
||||
unit.map_or(activation.avm2().playerglobals_domain, |u| u.domain());
|
||||
let domain = unit.map_or(activation.avm2().playerglobals_domain, |u| u.domain());
|
||||
if let Some(class) = domain.get_class(activation.context, name) {
|
||||
*self = PropertyClass::Class(class);
|
||||
(Some(class), true)
|
||||
} else {
|
||||
return Err(format!(
|
||||
"Could not resolve class {name:?} for property coercion"
|
||||
)
|
||||
.into());
|
||||
}
|
||||
return Err(
|
||||
format!("Could not resolve class {name:?} for property coercion").into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
PropertyClass::Any => (None, false),
|
||||
|
@ -108,12 +106,8 @@ impl<'gc> PropertyClass<'gc> {
|
|||
PropertyClass::Class(class) => Ok(Some(*class)),
|
||||
PropertyClass::Name(gc) => {
|
||||
let (name, unit) = &**gc;
|
||||
if name.is_any_namespace() && name.is_any_name() {
|
||||
*self = PropertyClass::Any;
|
||||
Ok(None)
|
||||
} else {
|
||||
let domain =
|
||||
unit.map_or(activation.avm2().playerglobals_domain, |u| u.domain());
|
||||
|
||||
let domain = unit.map_or(activation.avm2().playerglobals_domain, |u| u.domain());
|
||||
if let Some(class) = domain.get_class(activation.context, name) {
|
||||
*self = PropertyClass::Class(class);
|
||||
Ok(Some(class))
|
||||
|
@ -124,7 +118,6 @@ impl<'gc> PropertyClass<'gc> {
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
PropertyClass::Any => Ok(None),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -386,16 +386,17 @@ impl<'gc> TranslationUnit<'gc> {
|
|||
/// Retrieve a static, or non-runtime, multiname from the current constant
|
||||
/// pool.
|
||||
///
|
||||
/// This version of the function treats index 0 as the any-type `*`.
|
||||
/// This version of the function returns None for index 0.
|
||||
pub fn pool_multiname_static_any(
|
||||
self,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
multiname_index: Index<AbcMultiname>,
|
||||
) -> Result<Gc<'gc, Multiname<'gc>>, Error<'gc>> {
|
||||
) -> Result<Option<Gc<'gc, Multiname<'gc>>>, Error<'gc>> {
|
||||
if multiname_index.0 == 0 {
|
||||
Ok(activation.avm2().multinames.any)
|
||||
Ok(None)
|
||||
} else {
|
||||
self.pool_multiname_static(activation, multiname_index)
|
||||
.map(Some)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ fn format_signature(params: &[ParamConfig], is_variadic: bool) -> Vec<ParamInfo>
|
|||
result.push(ParamInfo {
|
||||
type_info: param
|
||||
.param_type_name
|
||||
.local_name()
|
||||
.and_then(|m| m.local_name())
|
||||
.map(|n| n.to_string())
|
||||
.unwrap_or_else(|| "*".to_string()),
|
||||
value: param.default_value.and_then(|v| format_value(&v)),
|
||||
|
@ -158,7 +158,7 @@ impl FunctionInfo {
|
|||
Self {
|
||||
returns: method
|
||||
.return_type()
|
||||
.local_name()
|
||||
.and_then(|m| m.local_name())
|
||||
.map(|n| n.to_string())
|
||||
.unwrap_or_else(|| "void".to_string()),
|
||||
args: format_signature(method.signature(), method.is_variadic()),
|
||||
|
@ -170,7 +170,7 @@ impl FunctionInfo {
|
|||
Self {
|
||||
returns: executable
|
||||
.return_type()
|
||||
.local_name()
|
||||
.and_then(|m| m.local_name())
|
||||
.map(|n| n.to_string())
|
||||
.unwrap_or_else(|| "void".to_string()),
|
||||
args: format_signature(executable.signature(), executable.is_variadic()),
|
||||
|
@ -390,7 +390,9 @@ impl Definition {
|
|||
.insert(
|
||||
trait_name,
|
||||
VariableInfo {
|
||||
type_info: type_name.local_name().map(|n| n.to_string()),
|
||||
type_info: type_name
|
||||
.and_then(|m| m.local_name())
|
||||
.map(|n| n.to_string()),
|
||||
value: format_value(default_value),
|
||||
stubbed: false,
|
||||
},
|
||||
|
@ -411,7 +413,7 @@ impl Definition {
|
|||
type_info: Some(
|
||||
method
|
||||
.return_type()
|
||||
.local_name()
|
||||
.and_then(|m| m.local_name())
|
||||
.map(|n| n.to_string())
|
||||
.unwrap_or_else(|| "*".to_string()),
|
||||
),
|
||||
|
@ -429,7 +431,8 @@ impl Definition {
|
|||
method
|
||||
.signature()
|
||||
.first()
|
||||
.and_then(|p| p.param_type_name.local_name())
|
||||
.and_then(|p| p.param_type_name)
|
||||
.and_then(|m| m.local_name())
|
||||
.map(|t| t.to_string())
|
||||
.unwrap_or_else(|| "*".to_string()),
|
||||
),
|
||||
|
@ -451,7 +454,9 @@ impl Definition {
|
|||
.insert(
|
||||
trait_name,
|
||||
VariableInfo {
|
||||
type_info: type_name.local_name().map(|n| n.to_string()),
|
||||
type_info: type_name
|
||||
.and_then(|m| m.local_name())
|
||||
.map(|n| n.to_string()),
|
||||
value: format_value(default_value),
|
||||
stubbed: false,
|
||||
},
|
||||
|
|
|
@ -74,7 +74,7 @@ pub enum TraitKind<'gc> {
|
|||
/// to.
|
||||
Slot {
|
||||
slot_id: u32,
|
||||
type_name: Gc<'gc, Multiname<'gc>>,
|
||||
type_name: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
default_value: Value<'gc>,
|
||||
unit: Option<TranslationUnit<'gc>>,
|
||||
},
|
||||
|
@ -99,7 +99,7 @@ pub enum TraitKind<'gc> {
|
|||
/// be overridden.
|
||||
Const {
|
||||
slot_id: u32,
|
||||
type_name: Gc<'gc, Multiname<'gc>>,
|
||||
type_name: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
default_value: Value<'gc>,
|
||||
unit: Option<TranslationUnit<'gc>>,
|
||||
},
|
||||
|
@ -156,7 +156,7 @@ impl<'gc> Trait<'gc> {
|
|||
|
||||
pub fn from_slot(
|
||||
name: QName<'gc>,
|
||||
type_name: Gc<'gc, Multiname<'gc>>,
|
||||
type_name: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
default_value: Option<Value<'gc>>,
|
||||
) -> Self {
|
||||
Trait {
|
||||
|
@ -164,7 +164,7 @@ impl<'gc> Trait<'gc> {
|
|||
attributes: TraitAttributes::empty(),
|
||||
kind: TraitKind::Slot {
|
||||
slot_id: 0,
|
||||
default_value: default_value.unwrap_or_else(|| default_value_for_type(&type_name)),
|
||||
default_value: default_value.unwrap_or_else(|| default_value_for_type(type_name)),
|
||||
type_name,
|
||||
unit: None,
|
||||
},
|
||||
|
@ -174,7 +174,7 @@ impl<'gc> Trait<'gc> {
|
|||
|
||||
pub fn from_const(
|
||||
name: QName<'gc>,
|
||||
type_name: Gc<'gc, Multiname<'gc>>,
|
||||
type_name: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
default_value: Option<Value<'gc>>,
|
||||
) -> Self {
|
||||
Trait {
|
||||
|
@ -182,7 +182,7 @@ impl<'gc> Trait<'gc> {
|
|||
attributes: TraitAttributes::empty(),
|
||||
kind: TraitKind::Const {
|
||||
slot_id: 0,
|
||||
default_value: default_value.unwrap_or_else(|| default_value_for_type(&type_name)),
|
||||
default_value: default_value.unwrap_or_else(|| default_value_for_type(type_name)),
|
||||
type_name,
|
||||
unit: None,
|
||||
},
|
||||
|
@ -205,7 +205,7 @@ impl<'gc> Trait<'gc> {
|
|||
value,
|
||||
} => {
|
||||
let type_name = unit.pool_multiname_static_any(activation, *type_name)?;
|
||||
let default_value = slot_default_value(unit, value, &type_name, activation)?;
|
||||
let default_value = slot_default_value(unit, value, type_name, activation)?;
|
||||
Trait {
|
||||
name,
|
||||
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||
|
@ -269,7 +269,7 @@ impl<'gc> Trait<'gc> {
|
|||
value,
|
||||
} => {
|
||||
let type_name = unit.pool_multiname_static_any(activation, *type_name)?;
|
||||
let default_value = slot_default_value(unit, value, &type_name, activation)?;
|
||||
let default_value = slot_default_value(unit, value, type_name, activation)?;
|
||||
Trait {
|
||||
name,
|
||||
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||
|
@ -386,7 +386,7 @@ impl<'gc> Trait<'gc> {
|
|||
fn slot_default_value<'gc>(
|
||||
translation_unit: TranslationUnit<'gc>,
|
||||
value: &Option<AbcDefaultValue>,
|
||||
type_name: &Multiname<'gc>,
|
||||
type_name: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some(value) = value {
|
||||
|
@ -399,13 +399,12 @@ fn slot_default_value<'gc>(
|
|||
|
||||
/// Returns the default "null" value for the given type.
|
||||
/// (`0` for ints, `null` for objects, etc.)
|
||||
fn default_value_for_type<'gc>(type_name: &Multiname<'gc>) -> Value<'gc> {
|
||||
fn default_value_for_type<'gc>(type_name: Option<Gc<'gc, Multiname<'gc>>>) -> Value<'gc> {
|
||||
if let Some(type_name) = type_name {
|
||||
// TODO: It's technically possible to have a multiname in here, so this should go through something
|
||||
// like `Activation::resolve_type` to get an actual `Class` object, and then check something like `Class::built_in_type`.
|
||||
// The Multiname is guaranteed to be static by `pool.pool_multiname_static` earlier.
|
||||
if type_name.is_any_name() {
|
||||
Value::Undefined
|
||||
} else if type_name.contains_public_namespace() {
|
||||
if type_name.contains_public_namespace() {
|
||||
let name = type_name.local_name().unwrap_or_default();
|
||||
if &name == b"Boolean" {
|
||||
false.into()
|
||||
|
@ -424,4 +423,7 @@ fn default_value_for_type<'gc>(type_name: &Multiname<'gc>) -> Value<'gc> {
|
|||
// Object type
|
||||
Value::Null
|
||||
}
|
||||
} else {
|
||||
Value::Undefined
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ pub fn verify_method<'gc>(
|
|||
}
|
||||
|
||||
let resolved_param_config = resolve_param_config(activation, method.signature())?;
|
||||
let resolved_return_type = resolve_return_type(activation, &method.return_type)?;
|
||||
let resolved_return_type = resolve_return_type(activation, method.return_type)?;
|
||||
|
||||
let mut seen_exception_indices = HashSet::new();
|
||||
|
||||
|
@ -671,26 +671,24 @@ pub fn resolve_param_config<'gc>(
|
|||
let mut resolved_param_config = Vec::new();
|
||||
|
||||
for param in param_config {
|
||||
if param.param_type_name.has_lazy_component() {
|
||||
let resolved_class = if let Some(param_type_name) = param.param_type_name {
|
||||
if param_type_name.has_lazy_component() {
|
||||
return Err(make_error_1014(activation, "[]".into()));
|
||||
}
|
||||
|
||||
let resolved_class = if param.param_type_name.is_any_name() {
|
||||
None
|
||||
} else {
|
||||
let lookedup_class = activation
|
||||
Some(
|
||||
activation
|
||||
.domain()
|
||||
.get_class(activation.context, ¶m.param_type_name)
|
||||
.get_class(activation.context, ¶m_type_name)
|
||||
.ok_or_else(|| {
|
||||
make_error_1014(
|
||||
activation,
|
||||
param
|
||||
.param_type_name
|
||||
.to_qualified_name(activation.context.gc_context),
|
||||
param_type_name.to_qualified_name(activation.gc()),
|
||||
)
|
||||
})?;
|
||||
|
||||
Some(lookedup_class)
|
||||
})?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
resolved_param_config.push(ResolvedParamConfig {
|
||||
|
@ -705,27 +703,24 @@ pub fn resolve_param_config<'gc>(
|
|||
|
||||
fn resolve_return_type<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
return_type: &Multiname<'gc>,
|
||||
return_type: Option<Gc<'gc, Multiname<'gc>>>,
|
||||
) -> Result<Option<Class<'gc>>, Error<'gc>> {
|
||||
if let Some(return_type) = return_type {
|
||||
if return_type.has_lazy_component() {
|
||||
return Err(make_error_1014(activation, "[]".into()));
|
||||
}
|
||||
|
||||
if return_type.is_any_name() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(
|
||||
activation
|
||||
.domain()
|
||||
.get_class(activation.context, return_type)
|
||||
.get_class(activation.context, &return_type)
|
||||
.ok_or_else(|| {
|
||||
make_error_1014(
|
||||
activation,
|
||||
return_type.to_qualified_name(activation.context.gc_context),
|
||||
)
|
||||
make_error_1014(activation, return_type.to_qualified_name(activation.gc()))
|
||||
})?,
|
||||
))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from avmplus's opcodes.tbl
|
||||
|
|
Loading…
Reference in New Issue