diff --git a/crates/wast/src/component/component.rs b/crates/wast/src/component/component.rs index af6f0144f5..1ba469a884 100644 --- a/crates/wast/src/component/component.rs +++ b/crates/wast/src/component/component.rs @@ -195,6 +195,12 @@ impl<'a> From> for ComponentField<'a> { } } +impl<'a> From> for ComponentField<'a> { + fn from(field: Alias<'a>) -> ComponentField<'a> { + ComponentField::Alias(field) + } +} + /// A function to call at instantiation time. #[derive(Debug)] pub struct Start<'a> { @@ -211,7 +217,7 @@ impl<'a> Parse<'a> for Start<'a> { parser.parse::()?; let func = parser.parse::>()?.0; let mut args = Vec::new(); - while !parser.peek2::() { + while !parser.is_empty() && !parser.peek2::() { args.push(parser.parse()?); } let result = if !parser.is_empty() { diff --git a/crates/wast/src/component/deftype.rs b/crates/wast/src/component/deftype.rs index 6024565724..0aaf8e3347 100644 --- a/crates/wast/src/component/deftype.rs +++ b/crates/wast/src/component/deftype.rs @@ -249,6 +249,12 @@ impl<'a> From> for ComponentTypeField<'a> { } } +impl<'a> From> for ComponentTypeField<'a> { + fn from(field: Alias<'a>) -> ComponentTypeField<'a> { + ComponentTypeField::Alias(field) + } +} + /// A type for a nested instance #[derive(Debug)] pub struct InstanceType<'a> { @@ -302,6 +308,12 @@ impl<'a> From> for InstanceTypeField<'a> { } } +impl<'a> From> for InstanceTypeField<'a> { + fn from(field: Alias<'a>) -> InstanceTypeField<'a> { + InstanceTypeField::Alias(field) + } +} + /// A value type. #[derive(Debug, Clone)] pub struct ValueType<'a> { diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index d7abf51509..ba9e673491 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -4,7 +4,6 @@ use crate::kw; use crate::names::Namespace; use crate::token::{Id, Index}; use crate::Error; -use std::mem::replace; /// Resolve the fields of a component and everything nested within it, changing /// `Index::Id` to `Index::Num` and expanding alias syntax sugar. @@ -13,714 +12,594 @@ pub fn resolve(component: &mut Component<'_>) -> Result<(), Error> { ComponentKind::Text(fields) => fields, ComponentKind::Binary(_) => return Ok(()), }; - let mut resolve_stack = Vec::new(); - resolve_fields(component.id, fields, &mut resolve_stack) + let mut resolver = Resolver::default(); + resolver.fields(component.id, fields) } -fn resolve_fields<'a, 'b>( - id: Option>, - fields: &mut Vec>, - resolve_stack: &'b mut Vec>, -) -> Result<(), Error> { - resolve_stack.push(ComponentResolver::new(id)); - - // Iterate through the fields of the component. We use an index - // instead of an iterator because we'll be inserting aliases - // as we go. - let mut i = 0; - while i < fields.len() { - // Resolve names within the field. - resolve_field(&mut fields[i], resolve_stack)?; - - // Name resolution may have emitted some aliases. Insert them before - // the current definition. - let resolver = resolve_stack.last_mut().unwrap(); - let aliases_to_insert = replace(&mut resolver.aliases_to_insert, Vec::new()); - for alias in aliases_to_insert { - fields.insert(i, ComponentField::Alias(alias)); - i += 1; - } +#[derive(Default)] +struct Resolver<'a> { + stack: Vec>, - // Definitions can't refer to themselves or to definitions that appear - // later in the format. Now that we're done resolving this field, - // assign it an index for later defintions to refer to. - register(&mut fields[i], resolver)?; + // When a name refers to a definition in an outer scope, we'll need to + // insert an outer alias before it. This collects the aliases to be + // inserted during resolution. + aliases_to_insert: Vec>, +} - i += 1; - } +/// Context structure used to perform name resolution. +#[derive(Default)] +struct ComponentState<'a> { + id: Option>, - resolve_stack.pop(); - Ok(()) + // Namespaces within each component. Note that each namespace carries + // with it information about the signature of the item in that namespace. + // The signature is later used to synthesize the type of a component and + // inject type annotations if necessary. + funcs: Namespace<'a>, + globals: Namespace<'a>, + tables: Namespace<'a>, + memories: Namespace<'a>, + types: Namespace<'a>, + tags: Namespace<'a>, + instances: Namespace<'a>, + modules: Namespace<'a>, + components: Namespace<'a>, + values: Namespace<'a>, } -/// Assign an index to the given field. -fn register<'a, 'b>( - item: &ComponentField<'a>, - resolver: &'b mut ComponentResolver<'a>, -) -> Result<(), Error> { - match item { - ComponentField::Import(i) => match &i.item.kind { - ItemKind::Module(_) => resolver.modules.register(i.item.id, "module")?, - ItemKind::Component(_) => resolver.components.register(i.item.id, "component")?, - ItemKind::Instance(_) => resolver.instances.register(i.item.id, "instance")?, - ItemKind::Value(_) => resolver.values.register(i.item.id, "value")?, - ItemKind::Func(_) => resolver.funcs.register(i.item.id, "func")?, - }, - - ComponentField::Func(i) => resolver.funcs.register(i.id, "func")?, - ComponentField::Type(i) => resolver.types.register(i.id, "type")?, - ComponentField::Instance(i) => resolver.instances.register(i.id, "instance")?, - ComponentField::Module(m) => resolver.modules.register(m.id, "nested module")?, - ComponentField::Component(c) => resolver.components.register(c.id, "nested component")?, - ComponentField::Alias(a) => register_alias(a, resolver)?, - ComponentField::Start(s) => resolver.values.register(s.result, "value")?, - - // These fields don't define any items in any index space. - ComponentField::Export(_) => return Ok(()), - }; - - Ok(()) +impl<'a> ComponentState<'a> { + fn new(id: Option>) -> ComponentState<'a> { + ComponentState { + id, + ..ComponentState::default() + } + } } -fn resolve_field<'a, 'b>( - field: &mut ComponentField<'a>, - resolve_stack: &'b mut Vec>, -) -> Result<(), Error> { - match field { - ComponentField::Import(i) => resolve_item_sig(&mut i.item, resolve_stack), +impl<'a> Resolver<'a> { + fn current(&mut self) -> &mut ComponentState<'a> { + self.stack + .last_mut() + .expect("should have at least one component state") + } - ComponentField::Type(t) => resolve_type_field(t, resolve_stack), + fn fields( + &mut self, + id: Option>, + fields: &mut Vec>, + ) -> Result<(), Error> { + self.stack.push(ComponentState::new(id)); + self.resolve_prepending_aliases(fields, Resolver::field, ComponentState::register)?; + self.stack.pop(); + Ok(()) + } - ComponentField::Func(f) => { - let body = match &mut f.kind { - ComponentFuncKind::Import { .. } => return Ok(()), - ComponentFuncKind::Inline { body } => body, - }; - let opts = match body { - ComponentFuncBody::CanonLift(lift) => { - resolve_type_use(&mut lift.type_, resolve_stack)?; - resolve_item_ref(&mut lift.func, resolve_stack)?; - &mut lift.opts - } - ComponentFuncBody::CanonLower(lower) => { - resolve_item_ref(&mut lower.func, resolve_stack)?; - &mut lower.opts - } - }; - for opt in opts { - match opt { - CanonOpt::StringUtf8 | CanonOpt::StringUtf16 | CanonOpt::StringLatin1Utf16 => {} - CanonOpt::Into(instance) => { - resolve_item_ref(instance, resolve_stack)?; - } - } - } - Ok(()) + fn resolve_prepending_aliases( + &mut self, + fields: &mut Vec, + resolve: fn(&mut Self, &mut T) -> Result<(), Error>, + register: fn(&mut ComponentState<'a>, &T) -> Result<(), Error>, + ) -> Result<(), Error> + where + T: From>, + { + assert!(self.aliases_to_insert.is_empty()); + + // Iterate through the fields of the component. We use an index + // instead of an iterator because we'll be inserting aliases + // as we go. + let mut i = 0; + while i < fields.len() { + // Resolve names within the field. + resolve(self, &mut fields[i])?; + + // Name resolution may have emitted some aliases. Insert them before + // the current definition. + let amt = self.aliases_to_insert.len(); + fields.splice(i..i, self.aliases_to_insert.drain(..).map(T::from)); + i += amt; + + // Definitions can't refer to themselves or to definitions that appear + // later in the format. Now that we're done resolving this field, + // assign it an index for later defintions to refer to. + register(self.current(), &fields[i])?; + + i += 1; } - ComponentField::Instance(i) => match &mut i.kind { - InstanceKind::Module { module, args } => { - resolve_item_ref(module, resolve_stack)?; - for arg in args { - match &mut arg.arg { - ModuleArg::Def(def) => { - resolve_item_ref(def, resolve_stack)?; - } - ModuleArg::BundleOfExports(..) => { - unreachable!("should be expanded already"); + Ok(()) + } + + fn field(&mut self, field: &mut ComponentField<'a>) -> Result<(), Error> { + match field { + ComponentField::Import(i) => self.item_sig(&mut i.item), + + ComponentField::Type(t) => self.type_field(t), + + ComponentField::Func(f) => { + let body = match &mut f.kind { + ComponentFuncKind::Import { .. } => return Ok(()), + ComponentFuncKind::Inline { body } => body, + }; + let opts = match body { + ComponentFuncBody::CanonLift(lift) => { + self.type_use(&mut lift.type_)?; + self.item_ref(&mut lift.func)?; + &mut lift.opts + } + ComponentFuncBody::CanonLower(lower) => { + self.item_ref(&mut lower.func)?; + &mut lower.opts + } + }; + for opt in opts { + match opt { + CanonOpt::StringUtf8 + | CanonOpt::StringUtf16 + | CanonOpt::StringLatin1Utf16 => {} + CanonOpt::Into(instance) => { + self.item_ref(instance)?; } } } Ok(()) } - InstanceKind::Component { component, args } => { - resolve_item_ref(component, resolve_stack)?; - for arg in args { - match &mut arg.arg { - ComponentArg::Def(def) => { - resolve_item_ref(def, resolve_stack)?; + + ComponentField::Instance(i) => match &mut i.kind { + InstanceKind::Module { module, args } => { + self.item_ref(module)?; + for arg in args { + match &mut arg.arg { + ModuleArg::Def(def) => { + self.item_ref(def)?; + } + ModuleArg::BundleOfExports(..) => { + unreachable!("should be expanded already"); + } } - ComponentArg::BundleOfExports(..) => { - unreachable!("should be expanded already") + } + Ok(()) + } + InstanceKind::Component { component, args } => { + self.item_ref(component)?; + for arg in args { + match &mut arg.arg { + ComponentArg::Def(def) => { + self.item_ref(def)?; + } + ComponentArg::BundleOfExports(..) => { + unreachable!("should be expanded already") + } } } + Ok(()) } - Ok(()) - } - InstanceKind::BundleOfExports { args } => { - for arg in args { - resolve_item_ref(&mut arg.index, resolve_stack)?; + InstanceKind::BundleOfExports { args } => { + for arg in args { + self.item_ref(&mut arg.index)?; + } + Ok(()) } - Ok(()) - } - InstanceKind::BundleOfComponentExports { args } => { - for arg in args { - resolve_arg(&mut arg.arg, resolve_stack)?; + InstanceKind::BundleOfComponentExports { args } => { + for arg in args { + self.arg(&mut arg.arg)?; + } + Ok(()) } + InstanceKind::Import { .. } => { + unreachable!("should be removed by expansion") + } + }, + ComponentField::Module(m) => { + match &mut m.kind { + ModuleKind::Inline { fields } => { + crate::core::resolve::resolve(fields)?; + } + + ModuleKind::Import { .. } => { + unreachable!("should be expanded already") + } + } + Ok(()) } - InstanceKind::Import { .. } => { - unreachable!("should be removed by expansion") - } - }, - ComponentField::Module(m) => { - match &mut m.kind { - ModuleKind::Inline { fields } => { - crate::core::resolve::resolve(fields)?; + ComponentField::Component(c) => match &mut c.kind { + NestedComponentKind::Import { .. } => { + unreachable!("should be expanded already") } + NestedComponentKind::Inline(fields) => self.fields(c.id, fields), + }, + ComponentField::Alias(a) => self.alias(a), - ModuleKind::Import { .. } => { - unreachable!("should be expanded already") + ComponentField::Start(s) => { + self.item_ref(&mut s.func)?; + for arg in s.args.iter_mut() { + self.item_ref(arg)?; } + Ok(()) } - Ok(()) - } - ComponentField::Component(c) => match &mut c.kind { - NestedComponentKind::Import { .. } => { - unreachable!("should be expanded already") - } - NestedComponentKind::Inline(fields) => resolve_fields(c.id, fields, resolve_stack), - }, - ComponentField::Alias(a) => resolve_alias(a, resolve_stack), - - ComponentField::Start(s) => { - resolve_item_ref(&mut s.func, resolve_stack)?; - for arg in s.args.iter_mut() { - resolve_item_ref(arg, resolve_stack)?; + ComponentField::Export(e) => { + self.arg(&mut e.arg)?; + Ok(()) } - Ok(()) } + } - ComponentField::Export(e) => { - resolve_arg(&mut e.arg, resolve_stack)?; - Ok(()) + fn item_sig(&mut self, sig: &mut ItemSig<'a>) -> Result<(), Error> { + match &mut sig.kind { + ItemKind::Component(t) => self.type_use(t), + ItemKind::Module(t) => self.type_use(t), + ItemKind::Instance(t) => self.type_use(t), + ItemKind::Func(t) => self.type_use(t), + ItemKind::Value(t) => self.type_use(t), } } -} -fn resolve_item_sig<'a>( - sig: &mut ItemSig<'a>, - resolve_stack: &mut Vec>, -) -> Result<(), Error> { - match &mut sig.kind { - ItemKind::Component(t) => resolve_type_use(t, resolve_stack), - ItemKind::Module(t) => resolve_type_use(t, resolve_stack), - ItemKind::Instance(t) => resolve_type_use(t, resolve_stack), - ItemKind::Func(t) => resolve_type_use(t, resolve_stack), - ItemKind::Value(t) => resolve_type_use(t, resolve_stack), - } -} - -fn resolve_alias<'a, 'b>( - alias: &'b mut Alias<'a>, - resolve_stack: &'b mut Vec>, -) -> Result<(), Error> { - match &mut alias.target { - AliasTarget::Export { - instance, - export: _, - } => resolve_ns(instance, Ns::Instance, resolve_stack), - AliasTarget::Outer { outer, index } => { - // Short-circuit when both indices are already resolved as this - // helps to write tests for invalid modules where wasmparser should - // be the one returning the error. - if let Index::Num(..) = outer { - if let Index::Num(..) = index { - return Ok(()); + fn alias(&mut self, alias: &mut Alias<'a>) -> Result<(), Error> { + match &mut alias.target { + AliasTarget::Export { + instance, + export: _, + } => self.resolve_ns(instance, Ns::Instance), + AliasTarget::Outer { outer, index } => { + // Short-circuit when both indices are already resolved as this + // helps to write tests for invalid modules where wasmparser should + // be the one returning the error. + if let Index::Num(..) = outer { + if let Index::Num(..) = index { + return Ok(()); + } } - } - // Resolve `outer`, and compute the depth at which to look up - // `index`. - let depth = match outer { - Index::Id(id) => { - let mut depth = 0; - for resolver in resolve_stack.iter_mut().rev() { - if resolver.id == Some(*id) { - break; + // Resolve `outer`, and compute the depth at which to look up + // `index`. + let depth = match outer { + Index::Id(id) => { + let mut depth = 0; + for resolver in self.stack.iter_mut().rev() { + if resolver.id == Some(*id) { + break; + } + depth += 1; } - depth += 1; - } - if depth as usize == resolve_stack.len() { - return Err(Error::new( - alias.span, - format!("outer component `{}` not found", id.name()), - )); + if depth as usize == self.stack.len() { + return Err(Error::new( + alias.span, + format!("outer component `{}` not found", id.name()), + )); + } + depth } - depth + Index::Num(n, _span) => *n, + }; + *outer = Index::Num(depth, alias.span); + if depth as usize >= self.stack.len() { + return Err(Error::new( + alias.span, + format!("component depth of `{}` is too large", depth), + )); } - Index::Num(n, _span) => *n, - }; - *outer = Index::Num(depth, alias.span); - if depth as usize >= resolve_stack.len() { - return Err(Error::new( - alias.span, - format!("component depth of `{}` is too large", depth), - )); - } - // Resolve `index` within the computed scope depth. - let ns = match alias.kind { - AliasKind::Module => Ns::Module, - AliasKind::Component => Ns::Component, - AliasKind::Instance => Ns::Instance, - AliasKind::Value => Ns::Value, - AliasKind::ExportKind(kind) => kind.into(), - }; - let computed = resolve_stack.len() - 1 - depth as usize; - resolve_stack[computed].resolve(ns, index)?; + // Resolve `index` within the computed scope depth. + let ns = match alias.kind { + AliasKind::Module => Ns::Module, + AliasKind::Component => Ns::Component, + AliasKind::Instance => Ns::Instance, + AliasKind::Value => Ns::Value, + AliasKind::ExportKind(kind) => kind.into(), + }; + let computed = self.stack.len() - 1 - depth as usize; + self.stack[computed].resolve(ns, index)?; - Ok(()) + Ok(()) + } } } -} -fn resolve_arg<'a, 'b>( - arg: &'b mut ComponentArg<'a>, - resolve_stack: &'b mut Vec>, -) -> Result<(), Error> { - match arg { - ComponentArg::Def(item_ref) => { - resolve_item_ref(item_ref, resolve_stack)?; - } - ComponentArg::BundleOfExports(..) => unreachable!("should be expanded already"), - } - Ok(()) -} - -fn resolve_type_use<'a, T>( - ty: &mut ComponentTypeUse<'a, T>, - resolve_stack: &mut Vec>, -) -> Result<(), Error> { - let item = match ty { - ComponentTypeUse::Ref(r) => r, - ComponentTypeUse::Inline(_) => unreachable!("inline type-use should be expanded by now"), - }; - resolve_item_ref(item, resolve_stack) -} - -fn resolve_intertype<'a, 'b>( - ty: &'b mut InterType<'a>, - resolve_stack: &'b mut Vec>, -) -> Result<(), Error> { - match ty { - InterType::Primitive(_) => {} - InterType::Flags(_) => {} - InterType::Enum(_) => {} - InterType::Record(r) => { - for field in r.fields.iter_mut() { - resolve_intertype_ref(&mut field.type_, resolve_stack)?; + fn arg(&mut self, arg: &mut ComponentArg<'a>) -> Result<(), Error> { + match arg { + ComponentArg::Def(item_ref) => { + self.item_ref(item_ref)?; } + ComponentArg::BundleOfExports(..) => unreachable!("should be expanded already"), } - InterType::Variant(v) => { - for case in v.cases.iter_mut() { - resolve_intertype_ref(&mut case.type_, resolve_stack)?; - } - } - InterType::List(l) => { - resolve_intertype_ref(&mut *l.element, resolve_stack)?; - } - InterType::Tuple(t) => { - for field in t.fields.iter_mut() { - resolve_intertype_ref(field, resolve_stack)?; - } - } - InterType::Union(t) => { - for arm in t.arms.iter_mut() { - resolve_intertype_ref(arm, resolve_stack)?; - } - } - InterType::Option(o) => { - resolve_intertype_ref(&mut *o.element, resolve_stack)?; - } - InterType::Expected(r) => { - resolve_intertype_ref(&mut *r.ok, resolve_stack)?; - resolve_intertype_ref(&mut *r.err, resolve_stack)?; - } - } - Ok(()) -} - -fn resolve_intertype_ref<'a, 'b>( - ty: &'b mut InterTypeRef<'a>, - resolve_stack: &'b mut Vec>, -) -> Result<(), Error> { - match ty { - InterTypeRef::Primitive(_) => Ok(()), - InterTypeRef::Ref(idx) => resolve_ns(idx, Ns::Type, resolve_stack), - InterTypeRef::Inline(_) => unreachable!("should be expanded by now"), + Ok(()) } -} -fn resolve_type_field<'a>( - field: &mut TypeField<'a>, - resolve_stack: &mut Vec>, -) -> Result<(), Error> { - match &mut field.def { - ComponentTypeDef::DefType(DefType::Func(f)) => { - for param in f.params.iter_mut() { - resolve_intertype_ref(&mut param.type_, resolve_stack)?; + fn type_use(&mut self, ty: &mut ComponentTypeUse<'a, T>) -> Result<(), Error> { + let item = match ty { + ComponentTypeUse::Ref(r) => r, + ComponentTypeUse::Inline(_) => { + unreachable!("inline type-use should be expanded by now") } - resolve_intertype_ref(&mut f.result, resolve_stack)?; - } - ComponentTypeDef::DefType(DefType::Module(m)) => { - resolve_stack.push(ComponentResolver::new(field.id)); - resolve_moduletype(m)?; - resolve_stack.pop(); - } - ComponentTypeDef::DefType(DefType::Component(c)) => { - resolve_stack.push(ComponentResolver::new(field.id)); - resolve_nested_component_type(c, resolve_stack)?; - resolve_stack.pop(); - } - ComponentTypeDef::DefType(DefType::Instance(i)) => { - resolve_stack.push(ComponentResolver::new(field.id)); - resolve_instance_type(i, resolve_stack)?; - resolve_stack.pop(); - } - ComponentTypeDef::DefType(DefType::Value(v)) => { - resolve_intertype_ref(&mut v.value_type, resolve_stack)? - } - ComponentTypeDef::InterType(i) => resolve_intertype(i, resolve_stack)?, + }; + self.item_ref(item) } - Ok(()) -} -fn resolve_nested_component_type<'a, 'b>( - c: &'b mut ComponentType<'a>, - resolve_stack: &'b mut Vec>, -) -> Result<(), Error> { - // Iterate through the fields of the component type. We use an index - // instead of an iterator because we'll be inserting aliases - // as we go. - let mut i = 0; - while i < c.fields.len() { - // Resolve names within the field. - match &mut c.fields[i] { - ComponentTypeField::Alias(alias) => { - resolve_alias(alias, resolve_stack)?; + fn intertype(&mut self, ty: &mut InterType<'a>) -> Result<(), Error> { + match ty { + InterType::Primitive(_) => {} + InterType::Flags(_) => {} + InterType::Enum(_) => {} + InterType::Record(r) => { + for field in r.fields.iter_mut() { + self.intertype_ref(&mut field.type_)?; + } } - ComponentTypeField::Type(ty) => { - resolve_type_field(ty, resolve_stack)?; + InterType::Variant(v) => { + for case in v.cases.iter_mut() { + self.intertype_ref(&mut case.type_)?; + } } - ComponentTypeField::Import(import) => { - resolve_item_sig(&mut import.item, resolve_stack)?; + InterType::List(l) => { + self.intertype_ref(&mut *l.element)?; } - ComponentTypeField::Export(export) => { - resolve_item_sig(&mut export.item, resolve_stack)?; + InterType::Tuple(t) => { + for field in t.fields.iter_mut() { + self.intertype_ref(field)?; + } } - } - - // Name resolution may have emitted some aliases. Insert them before - // the current definition. - let resolver = resolve_stack.last_mut().unwrap(); - let aliases_to_insert = replace(&mut resolver.aliases_to_insert, Vec::new()); - for alias in aliases_to_insert { - c.fields.insert(i, ComponentTypeField::Alias(alias)); - i += 1; - } - - // Definitions can't refer to themselves or to definitions that appear - // later in the format. Now that we're done resolving this field, - // assign it an index for later defintions to refer to. - match &mut c.fields[i] { - ComponentTypeField::Alias(alias) => { - register_alias(alias, resolver)?; + InterType::Union(t) => { + for arm in t.arms.iter_mut() { + self.intertype_ref(arm)?; + } + } + InterType::Option(o) => { + self.intertype_ref(&mut *o.element)?; } - ComponentTypeField::Type(ty) => { - resolver.types.register(ty.id, "type")?; + InterType::Expected(r) => { + self.intertype_ref(&mut *r.ok)?; + self.intertype_ref(&mut *r.err)?; } + } + Ok(()) + } - // Only the type namespace is populated within the component type - // namespace so these are ignored here. - ComponentTypeField::Import(_) | ComponentTypeField::Export(_) => {} + fn intertype_ref(&mut self, ty: &mut InterTypeRef<'a>) -> Result<(), Error> { + match ty { + InterTypeRef::Primitive(_) => Ok(()), + InterTypeRef::Ref(idx) => self.resolve_ns(idx, Ns::Type), + InterTypeRef::Inline(_) => unreachable!("should be expanded by now"), } - i += 1; } - Ok(()) -} -fn resolve_instance_type<'a, 'b>( - c: &'b mut InstanceType<'a>, - resolve_stack: &'b mut Vec>, -) -> Result<(), Error> { - // Iterate through the fields of the component type. We use an index - // instead of an iterator because we'll be inserting aliases - // as we go. - let mut i = 0; - while i < c.fields.len() { - // Resolve names within the field. - match &mut c.fields[i] { - InstanceTypeField::Alias(alias) => { - resolve_alias(alias, resolve_stack)?; + fn type_field(&mut self, field: &mut TypeField<'a>) -> Result<(), Error> { + match &mut field.def { + ComponentTypeDef::DefType(DefType::Func(f)) => { + for param in f.params.iter_mut() { + self.intertype_ref(&mut param.type_)?; + } + self.intertype_ref(&mut f.result)?; } - InstanceTypeField::Type(ty) => { - resolve_type_field(ty, resolve_stack)?; + ComponentTypeDef::DefType(DefType::Module(m)) => { + self.stack.push(ComponentState::new(field.id)); + self.moduletype(m)?; + self.stack.pop(); } - InstanceTypeField::Export(export) => { - resolve_item_sig(&mut export.item, resolve_stack)?; + ComponentTypeDef::DefType(DefType::Component(c)) => { + self.stack.push(ComponentState::new(field.id)); + self.nested_component_type(c)?; + self.stack.pop(); } - } - - // Name resolution may have emitted some aliases. Insert them before - // the current definition. - let resolver = resolve_stack.last_mut().unwrap(); - let aliases_to_insert = replace(&mut resolver.aliases_to_insert, Vec::new()); - for alias in aliases_to_insert { - c.fields.insert(i, InstanceTypeField::Alias(alias)); - i += 1; - } - - // Definitions can't refer to themselves or to definitions that appear - // later in the format. Now that we're done resolving this field, - // assign it an index for later defintions to refer to. - match &mut c.fields[i] { - InstanceTypeField::Alias(alias) => { - register_alias(alias, resolver)?; + ComponentTypeDef::DefType(DefType::Instance(i)) => { + self.stack.push(ComponentState::new(field.id)); + self.instance_type(i)?; + self.stack.pop(); } - InstanceTypeField::Type(ty) => { - resolver.types.register(ty.id, "type")?; + ComponentTypeDef::DefType(DefType::Value(v)) => { + self.intertype_ref(&mut v.value_type)? } - InstanceTypeField::Export(_export) => {} - } - i += 1; - } - - Ok(()) -} - -fn register_alias<'a, 'b>( - alias: &'b Alias<'a>, - resolver: &'b mut ComponentResolver<'a>, -) -> Result { - match alias.kind { - AliasKind::Module => resolver.modules.register(alias.id, "module"), - AliasKind::Component => resolver.components.register(alias.id, "component"), - AliasKind::Instance => resolver.instances.register(alias.id, "instance"), - AliasKind::Value => resolver.values.register(alias.id, "value"), - AliasKind::ExportKind(core::ExportKind::Func) => resolver.funcs.register(alias.id, "func"), - AliasKind::ExportKind(core::ExportKind::Table) => { - resolver.tables.register(alias.id, "table") - } - AliasKind::ExportKind(core::ExportKind::Memory) => { - resolver.memories.register(alias.id, "memory") + ComponentTypeDef::InterType(i) => self.intertype(i)?, } - AliasKind::ExportKind(core::ExportKind::Global) => { - resolver.globals.register(alias.id, "global") - } - AliasKind::ExportKind(core::ExportKind::Tag) => resolver.tags.register(alias.id, "tag"), - AliasKind::ExportKind(core::ExportKind::Type) => resolver.types.register(alias.id, "type"), + Ok(()) } -} -fn resolve_item_ref<'a, 'b, K>( - item: &'b mut ItemRef<'a, K>, - resolve_stack: &'b mut Vec>, -) -> Result<(), Error> -where - K: Into + Copy, -{ - let last_ns = item.kind.into(); - - // If there are no extra `export_names` listed then this is a reference to - // something defined within this component's index space, so resolve as - // necessary. - if item.export_names.is_empty() { - resolve_ns(&mut item.idx, last_ns, resolve_stack)?; - return Ok(()); + fn nested_component_type(&mut self, c: &mut ComponentType<'a>) -> Result<(), Error> { + self.resolve_prepending_aliases( + &mut c.fields, + |resolver, field| match field { + ComponentTypeField::Alias(alias) => resolver.alias(alias), + ComponentTypeField::Type(ty) => resolver.type_field(ty), + ComponentTypeField::Import(import) => resolver.item_sig(&mut import.item), + ComponentTypeField::Export(export) => resolver.item_sig(&mut export.item), + }, + |state, field| { + match field { + ComponentTypeField::Alias(alias) => { + state.register_alias(alias)?; + } + ComponentTypeField::Type(ty) => { + state.types.register(ty.id, "type")?; + } + // Only the type namespace is populated within the component type + // namespace so these are ignored here. + ComponentTypeField::Import(_) | ComponentTypeField::Export(_) => {} + } + Ok(()) + }, + ) } - // ... otherwise the `index` of `item` refers to an intance and the - // `export_names` refer to recursive exports from this item. Resolve the - // instance locally and then process the export names one at a time, - // injecting aliases as necessary. - let mut index = item.idx.clone(); - resolve_ns(&mut index, Ns::Instance, resolve_stack)?; - let span = item.idx.span(); - for (pos, export_name) in item.export_names.iter().enumerate() { - // The last name is in the namespace of the reference. All others are - // instances. - let ns = if pos == item.export_names.len() - 1 { - last_ns - } else { - Ns::Instance - }; - - // Record an outer alias to be inserted in front of the current - // definition. - let mut alias = Alias { - span, - id: None, - name: None, - target: AliasTarget::Export { - instance: index, - export: export_name, + fn instance_type(&mut self, c: &mut InstanceType<'a>) -> Result<(), Error> { + self.resolve_prepending_aliases( + &mut c.fields, + |resolver, field| match field { + InstanceTypeField::Alias(alias) => resolver.alias(alias), + InstanceTypeField::Type(ty) => resolver.type_field(ty), + InstanceTypeField::Export(export) => resolver.item_sig(&mut export.item), }, - kind: match ns { - Ns::Module => AliasKind::Module, - Ns::Component => AliasKind::Component, - Ns::Instance => AliasKind::Instance, - Ns::Value => AliasKind::Value, - Ns::Func => AliasKind::ExportKind(core::ExportKind::Func), - Ns::Table => AliasKind::ExportKind(core::ExportKind::Table), - Ns::Global => AliasKind::ExportKind(core::ExportKind::Global), - Ns::Memory => AliasKind::ExportKind(core::ExportKind::Memory), - Ns::Tag => AliasKind::ExportKind(core::ExportKind::Tag), - Ns::Type => AliasKind::ExportKind(core::ExportKind::Type), + |state, field| { + match field { + InstanceTypeField::Alias(alias) => { + state.register_alias(alias)?; + } + InstanceTypeField::Type(ty) => { + state.types.register(ty.id, "type")?; + } + InstanceTypeField::Export(_export) => {} + } + Ok(()) }, - }; - - let resolver = resolve_stack.last_mut().unwrap(); - index = Index::Num(register_alias(&mut alias, resolver)?, span); - resolver.aliases_to_insert.push(alias); + ) } - item.idx = index; - item.export_names = Vec::new(); - Ok(()) -} + fn item_ref(&mut self, item: &mut ItemRef<'a, K>) -> Result<(), Error> + where + K: Into + Copy, + { + let last_ns = item.kind.into(); + + // If there are no extra `export_names` listed then this is a reference to + // something defined within this component's index space, so resolve as + // necessary. + if item.export_names.is_empty() { + self.resolve_ns(&mut item.idx, last_ns)?; + return Ok(()); + } -fn resolve_ns<'a, 'b>( - idx: &mut Index<'a>, - ns: Ns, - resolve_stack: &'b mut Vec>, -) -> Result<(), Error> { - // Perform resolution on a local clone walking up the stack of components - // that we have. Note that a local clone is used since we don't want to use - // the parent's resolved index if a parent matches, instead we want to use - // the index of the alias that we will automatically insert. - let mut idx_clone = idx.clone(); - for (depth, resolver) in resolve_stack.iter_mut().rev().enumerate() { - let depth = depth as u32; - let found = match resolver.resolve(ns, &mut idx_clone) { - Ok(idx) => idx, - // Try the next parent - Err(_) => continue, - }; + // ... otherwise the `index` of `item` refers to an intance and the + // `export_names` refer to recursive exports from this item. Resolve the + // instance locally and then process the export names one at a time, + // injecting aliases as necessary. + let mut index = item.idx.clone(); + self.resolve_ns(&mut index, Ns::Instance)?; + let span = item.idx.span(); + for (pos, export_name) in item.export_names.iter().enumerate() { + // The last name is in the namespace of the reference. All others are + // instances. + let ns = if pos == item.export_names.len() - 1 { + last_ns + } else { + Ns::Instance + }; - // If this is the current component then no extra alias is necessary, so - // return success. - if depth == 0 { - *idx = idx_clone; - return Ok(()); + // Record an outer alias to be inserted in front of the current + // definition. + let mut alias = Alias { + span, + id: None, + name: None, + target: AliasTarget::Export { + instance: index, + export: export_name, + }, + kind: match ns { + Ns::Module => AliasKind::Module, + Ns::Component => AliasKind::Component, + Ns::Instance => AliasKind::Instance, + Ns::Value => AliasKind::Value, + Ns::Func => AliasKind::ExportKind(core::ExportKind::Func), + Ns::Table => AliasKind::ExportKind(core::ExportKind::Table), + Ns::Global => AliasKind::ExportKind(core::ExportKind::Global), + Ns::Memory => AliasKind::ExportKind(core::ExportKind::Memory), + Ns::Tag => AliasKind::ExportKind(core::ExportKind::Tag), + Ns::Type => AliasKind::ExportKind(core::ExportKind::Type), + }, + }; + + index = Index::Num(self.current().register_alias(&mut alias)?, span); + self.aliases_to_insert.push(alias); } - let id = match idx { - Index::Id(id) => id.clone(), - Index::Num(..) => unreachable!(), - }; + item.idx = index; + item.export_names = Vec::new(); - // When resolution succeeds in a parent then an outer alias is - // automatically inserted here in this component. - let span = idx.span(); - let mut alias = Alias { - span, - id: Some(id), - name: None, - target: AliasTarget::Outer { - outer: Index::Num(depth, span), - index: Index::Num(found, span), - }, - kind: match ns { - Ns::Module => AliasKind::Module, - Ns::Component => AliasKind::Component, - Ns::Instance => AliasKind::Instance, - Ns::Value => AliasKind::Value, - Ns::Func => AliasKind::ExportKind(core::ExportKind::Func), - Ns::Table => AliasKind::ExportKind(core::ExportKind::Table), - Ns::Global => AliasKind::ExportKind(core::ExportKind::Global), - Ns::Memory => AliasKind::ExportKind(core::ExportKind::Memory), - Ns::Tag => AliasKind::ExportKind(core::ExportKind::Tag), - Ns::Type => AliasKind::ExportKind(core::ExportKind::Type), - }, - }; - let resolver = resolve_stack.last_mut().unwrap(); - let local_index = register_alias(&mut alias, resolver)?; - resolver.aliases_to_insert.push(alias); - *idx = Index::Num(local_index, span); - return Ok(()); + Ok(()) } - // If resolution in any parent failed then simply return the error from our - // local namespace - resolve_stack.last_mut().unwrap().resolve(ns, idx)?; - unreachable!() -} + fn resolve_ns(&mut self, idx: &mut Index<'a>, ns: Ns) -> Result<(), Error> { + // Perform resolution on a local clone walking up the stack of components + // that we have. Note that a local clone is used since we don't want to use + // the parent's resolved index if a parent matches, instead we want to use + // the index of the alias that we will automatically insert. + let mut idx_clone = idx.clone(); + for (depth, resolver) in self.stack.iter_mut().rev().enumerate() { + let depth = depth as u32; + let found = match resolver.resolve(ns, &mut idx_clone) { + Ok(idx) => idx, + // Try the next parent + Err(_) => continue, + }; -fn resolve_moduletype(ty: &mut ModuleType<'_>) -> Result<(), Error> { - let mut types = Namespace::default(); - for def in ty.defs.iter_mut() { - match def { - ModuleTypeDef::Type(t) => { - types.register(t.id, "type")?; + // If this is the current component then no extra alias is necessary, so + // return success. + if depth == 0 { + *idx = idx_clone; + return Ok(()); } - ModuleTypeDef::Import(t) => resolve_item_sig(&mut t.item, &types)?, - ModuleTypeDef::Export(_, t) => resolve_item_sig(t, &types)?, + let id = match idx { + Index::Id(id) => id.clone(), + Index::Num(..) => unreachable!(), + }; + + // When resolution succeeds in a parent then an outer alias is + // automatically inserted here in this component. + let span = idx.span(); + let mut alias = Alias { + span, + id: Some(id), + name: None, + target: AliasTarget::Outer { + outer: Index::Num(depth, span), + index: Index::Num(found, span), + }, + kind: match ns { + Ns::Module => AliasKind::Module, + Ns::Component => AliasKind::Component, + Ns::Instance => AliasKind::Instance, + Ns::Value => AliasKind::Value, + Ns::Func => AliasKind::ExportKind(core::ExportKind::Func), + Ns::Table => AliasKind::ExportKind(core::ExportKind::Table), + Ns::Global => AliasKind::ExportKind(core::ExportKind::Global), + Ns::Memory => AliasKind::ExportKind(core::ExportKind::Memory), + Ns::Tag => AliasKind::ExportKind(core::ExportKind::Tag), + Ns::Type => AliasKind::ExportKind(core::ExportKind::Type), + }, + }; + let local_index = self.current().register_alias(&mut alias)?; + self.aliases_to_insert.push(alias); + *idx = Index::Num(local_index, span); + return Ok(()); } + + // If resolution in any parent failed then simply return the error from our + // local namespace + self.current().resolve(ns, idx)?; + unreachable!() } - return Ok(()); - fn resolve_item_sig<'a>( - sig: &mut core::ItemSig<'a>, - names: &Namespace<'a>, - ) -> Result<(), Error> { - match &mut sig.kind { - core::ItemKind::Func(ty) | core::ItemKind::Tag(core::TagType::Exception(ty)) => { - let idx = ty.index.as_mut().expect("index should be filled in"); - names.resolve(idx, "type")?; + fn moduletype(&mut self, ty: &mut ModuleType<'_>) -> Result<(), Error> { + let mut types = Namespace::default(); + for def in ty.defs.iter_mut() { + match def { + ModuleTypeDef::Type(t) => { + types.register(t.id, "type")?; + } + ModuleTypeDef::Import(t) => resolve_item_sig(&mut t.item, &types)?, + ModuleTypeDef::Export(_, t) => resolve_item_sig(t, &types)?, } - core::ItemKind::Memory(_) | core::ItemKind::Global(_) | core::ItemKind::Table(_) => {} } - Ok(()) - } -} - -/// Context structure used to perform name resolution. -#[derive(Default)] -struct ComponentResolver<'a> { - id: Option>, - - // Namespaces within each componnet. Note that each namespace carries - // with it information about the signature of the item in that namespace. - // The signature is later used to synthesize the type of a component and - // inject type annotations if necessary. - funcs: Namespace<'a>, - globals: Namespace<'a>, - tables: Namespace<'a>, - memories: Namespace<'a>, - types: Namespace<'a>, - tags: Namespace<'a>, - instances: Namespace<'a>, - modules: Namespace<'a>, - components: Namespace<'a>, - values: Namespace<'a>, - - // When a name refers to a definition in an outer scope, we'll need to - // insert an outer alias before it. This collects the aliases to be - // inserted during resolution. - aliases_to_insert: Vec>, -} + return Ok(()); -impl<'a> ComponentResolver<'a> { - fn new(id: Option>) -> Self { - Self { - id, - funcs: Default::default(), - globals: Default::default(), - tables: Default::default(), - memories: Default::default(), - types: Default::default(), - tags: Default::default(), - instances: Default::default(), - modules: Default::default(), - components: Default::default(), - values: Default::default(), - aliases_to_insert: Vec::new(), + fn resolve_item_sig<'a>( + sig: &mut core::ItemSig<'a>, + names: &Namespace<'a>, + ) -> Result<(), Error> { + match &mut sig.kind { + core::ItemKind::Func(ty) | core::ItemKind::Tag(core::TagType::Exception(ty)) => { + let idx = ty.index.as_mut().expect("index should be filled in"); + names.resolve(idx, "type")?; + } + core::ItemKind::Memory(_) + | core::ItemKind::Global(_) + | core::ItemKind::Table(_) => {} + } + Ok(()) } } } -impl<'a> ComponentResolver<'a> { +impl<'a> ComponentState<'a> { fn resolve(&mut self, ns: Ns, idx: &mut Index<'a>) -> Result { match ns { Ns::Func => self.funcs.resolve(idx, "func"), @@ -735,6 +614,53 @@ impl<'a> ComponentResolver<'a> { Ns::Value => self.values.resolve(idx, "instance"), } } + + /// Assign an index to the given field. + fn register(&mut self, item: &ComponentField<'a>) -> Result<(), Error> { + match item { + ComponentField::Import(i) => match &i.item.kind { + ItemKind::Module(_) => self.modules.register(i.item.id, "module")?, + ItemKind::Component(_) => self.components.register(i.item.id, "component")?, + ItemKind::Instance(_) => self.instances.register(i.item.id, "instance")?, + ItemKind::Value(_) => self.values.register(i.item.id, "value")?, + ItemKind::Func(_) => self.funcs.register(i.item.id, "func")?, + }, + + ComponentField::Func(i) => self.funcs.register(i.id, "func")?, + ComponentField::Type(i) => self.types.register(i.id, "type")?, + ComponentField::Instance(i) => self.instances.register(i.id, "instance")?, + ComponentField::Module(m) => self.modules.register(m.id, "nested module")?, + ComponentField::Component(c) => self.components.register(c.id, "nested component")?, + ComponentField::Alias(a) => self.register_alias(a)?, + ComponentField::Start(s) => self.values.register(s.result, "value")?, + + // These fields don't define any items in any index space. + ComponentField::Export(_) => return Ok(()), + }; + + Ok(()) + } + + fn register_alias(&mut self, alias: &Alias<'a>) -> Result { + match alias.kind { + AliasKind::Module => self.modules.register(alias.id, "module"), + AliasKind::Component => self.components.register(alias.id, "component"), + AliasKind::Instance => self.instances.register(alias.id, "instance"), + AliasKind::Value => self.values.register(alias.id, "value"), + AliasKind::ExportKind(core::ExportKind::Func) => self.funcs.register(alias.id, "func"), + AliasKind::ExportKind(core::ExportKind::Table) => { + self.tables.register(alias.id, "table") + } + AliasKind::ExportKind(core::ExportKind::Memory) => { + self.memories.register(alias.id, "memory") + } + AliasKind::ExportKind(core::ExportKind::Global) => { + self.globals.register(alias.id, "global") + } + AliasKind::ExportKind(core::ExportKind::Tag) => self.tags.register(alias.id, "tag"), + AliasKind::ExportKind(core::ExportKind::Type) => self.types.register(alias.id, "type"), + } + } } #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]