| use crate::Error; |
| use crate::component::*; |
| use crate::core::{self, ValType, resolve::ResolveCoreType}; |
| use crate::kw; |
| use crate::names::Namespace; |
| use crate::token::Span; |
| use crate::token::{Id, Index}; |
| |
| /// Resolve the fields of a component and everything nested within it, changing |
| /// `Index::Id` to `Index::Num` and expanding alias syntax sugar. |
| pub fn resolve(component: &mut Component<'_>) -> Result<(), Error> { |
| let fields = match &mut component.kind { |
| ComponentKind::Text(fields) => fields, |
| ComponentKind::Binary(_) => return Ok(()), |
| }; |
| let mut resolver = Resolver::default(); |
| resolver.fields(component.id, fields) |
| } |
| |
| impl<'a> From<Alias<'a>> for ComponentField<'a> { |
| fn from(a: Alias<'a>) -> Self { |
| Self::Alias(a) |
| } |
| } |
| |
| impl<'a> From<Alias<'a>> for ModuleTypeDecl<'a> { |
| fn from(a: Alias<'a>) -> Self { |
| Self::Alias(a) |
| } |
| } |
| |
| impl<'a> From<Alias<'a>> for ComponentTypeDecl<'a> { |
| fn from(a: Alias<'a>) -> Self { |
| Self::Alias(a) |
| } |
| } |
| |
| impl<'a> From<Alias<'a>> for InstanceTypeDecl<'a> { |
| fn from(a: Alias<'a>) -> Self { |
| Self::Alias(a) |
| } |
| } |
| |
| #[derive(Default)] |
| struct Resolver<'a> { |
| stack: Vec<ComponentState<'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<Alias<'a>>, |
| } |
| |
| /// Context structure used to perform name resolution. |
| #[derive(Default)] |
| struct ComponentState<'a> { |
| id: Option<Id<'a>>, |
| |
| // 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. |
| core_funcs: Namespace<'a>, |
| core_globals: Namespace<'a>, |
| core_tables: Namespace<'a>, |
| core_memories: Namespace<'a>, |
| core_types: Namespace<'a>, |
| core_tags: Namespace<'a>, |
| core_instances: Namespace<'a>, |
| core_modules: Namespace<'a>, |
| |
| funcs: Namespace<'a>, |
| types: Namespace<'a>, |
| instances: Namespace<'a>, |
| components: Namespace<'a>, |
| values: Namespace<'a>, |
| } |
| |
| impl<'a> ComponentState<'a> { |
| fn new(id: Option<Id<'a>>) -> ComponentState<'a> { |
| ComponentState { |
| id, |
| ..ComponentState::default() |
| } |
| } |
| |
| fn register_item_sig(&mut self, sig: &ItemSig<'a>) -> Result<u32, Error> { |
| match &sig.kind { |
| ItemSigKind::CoreModule(_) => self.core_modules.register(sig.id, "core module"), |
| ItemSigKind::Func(_) => self.funcs.register(sig.id, "func"), |
| ItemSigKind::Component(_) => self.components.register(sig.id, "component"), |
| ItemSigKind::Instance(_) => self.instances.register(sig.id, "instance"), |
| ItemSigKind::Value(_) => self.values.register(sig.id, "value"), |
| ItemSigKind::Type(_) => self.types.register(sig.id, "type"), |
| } |
| } |
| } |
| |
| impl<'a> Resolver<'a> { |
| fn current(&mut self) -> &mut ComponentState<'a> { |
| self.stack |
| .last_mut() |
| .expect("should have at least one component state") |
| } |
| |
| fn fields( |
| &mut self, |
| id: Option<Id<'a>>, |
| fields: &mut Vec<ComponentField<'a>>, |
| ) -> Result<(), Error> { |
| self.stack.push(ComponentState::new(id)); |
| self.resolve_prepending_aliases(fields, Resolver::field, ComponentState::register)?; |
| self.stack.pop(); |
| Ok(()) |
| } |
| |
| fn resolve_prepending_aliases<T>( |
| &mut self, |
| fields: &mut Vec<T>, |
| resolve: fn(&mut Self, &mut T) -> Result<(), Error>, |
| register: fn(&mut ComponentState<'a>, &T) -> Result<(), Error>, |
| ) -> Result<(), Error> |
| where |
| T: From<Alias<'a>>, |
| { |
| 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 definitions to refer to. |
| register(self.current(), &fields[i])?; |
| |
| i += 1; |
| } |
| |
| Ok(()) |
| } |
| |
| fn field(&mut self, field: &mut ComponentField<'a>) -> Result<(), Error> { |
| match field { |
| ComponentField::CoreModule(m) => self.core_module(m), |
| ComponentField::CoreInstance(i) => self.core_instance(i), |
| ComponentField::CoreType(t) => self.core_ty(t), |
| ComponentField::CoreRec(t) => self.core_rec(t), |
| ComponentField::Component(c) => self.component(c), |
| ComponentField::Instance(i) => self.instance(i), |
| ComponentField::Alias(a) => self.alias(a), |
| ComponentField::Type(t) => self.ty(t), |
| ComponentField::CanonicalFunc(f) => self.canonical_func(f), |
| ComponentField::CoreFunc(_) => unreachable!("should be expanded already"), |
| ComponentField::Func(_) => unreachable!("should be expanded already"), |
| ComponentField::Start(s) => self.start(s), |
| ComponentField::Import(i) => self.item_sig(&mut i.item), |
| ComponentField::Export(e) => { |
| if let Some(ty) = &mut e.ty { |
| self.item_sig(&mut ty.0)?; |
| } |
| self.export(&mut e.kind) |
| } |
| ComponentField::Custom(_) | ComponentField::Producers(_) => Ok(()), |
| } |
| } |
| |
| fn core_module(&mut self, module: &mut CoreModule) -> Result<(), Error> { |
| match &mut module.kind { |
| CoreModuleKind::Inline { fields } => { |
| crate::core::resolve::resolve(fields)?; |
| } |
| |
| CoreModuleKind::Import { .. } => { |
| unreachable!("should be expanded already") |
| } |
| } |
| |
| Ok(()) |
| } |
| |
| fn component(&mut self, component: &mut NestedComponent<'a>) -> Result<(), Error> { |
| match &mut component.kind { |
| NestedComponentKind::Import { .. } => unreachable!("should be expanded already"), |
| NestedComponentKind::Inline(fields) => self.fields(component.id, fields), |
| } |
| } |
| |
| fn core_instance(&mut self, instance: &mut CoreInstance<'a>) -> Result<(), Error> { |
| match &mut instance.kind { |
| CoreInstanceKind::Instantiate { module, args } => { |
| self.component_item_ref(module)?; |
| for arg in args { |
| match &mut arg.kind { |
| CoreInstantiationArgKind::Instance(i) => { |
| self.core_item_ref(i)?; |
| } |
| CoreInstantiationArgKind::BundleOfExports(..) => { |
| unreachable!("should be expanded already"); |
| } |
| } |
| } |
| } |
| CoreInstanceKind::BundleOfExports(exports) => { |
| for export in exports { |
| self.core_item_ref(&mut export.item)?; |
| } |
| } |
| } |
| Ok(()) |
| } |
| |
| fn instance(&mut self, instance: &mut Instance<'a>) -> Result<(), Error> { |
| match &mut instance.kind { |
| InstanceKind::Instantiate { component, args } => { |
| self.component_item_ref(component)?; |
| for arg in args { |
| match &mut arg.kind { |
| InstantiationArgKind::Item(e) => { |
| self.export(e)?; |
| } |
| InstantiationArgKind::BundleOfExports(..) => { |
| unreachable!("should be expanded already") |
| } |
| } |
| } |
| } |
| InstanceKind::BundleOfExports(exports) => { |
| for export in exports { |
| self.export(&mut export.kind)?; |
| } |
| } |
| InstanceKind::Import { .. } => { |
| unreachable!("should be expanded already") |
| } |
| } |
| Ok(()) |
| } |
| |
| fn item_sig(&mut self, item: &mut ItemSig<'a>) -> Result<(), Error> { |
| match &mut item.kind { |
| // Here we must be explicit otherwise the module type reference will |
| // be assumed to be in the component type namespace |
| ItemSigKind::CoreModule(t) => self.core_type_use(t), |
| ItemSigKind::Func(t) => self.component_type_use(t), |
| ItemSigKind::Component(t) => self.component_type_use(t), |
| ItemSigKind::Instance(t) => self.component_type_use(t), |
| ItemSigKind::Value(t) => self.component_val_type(&mut t.0), |
| ItemSigKind::Type(b) => match b { |
| TypeBounds::Eq(i) => { |
| self.resolve_ns(i, Ns::Type)?; |
| Ok(()) |
| } |
| TypeBounds::SubResource => Ok(()), |
| }, |
| } |
| } |
| |
| fn export(&mut self, kind: &mut ComponentExportKind<'a>) -> Result<(), Error> { |
| match kind { |
| // Here we do *not* have to be explicit as the item ref is to a core module |
| ComponentExportKind::CoreModule(r) => self.component_item_ref(r), |
| ComponentExportKind::Func(r) => self.component_item_ref(r), |
| ComponentExportKind::Value(r) => self.component_item_ref(r), |
| ComponentExportKind::Type(r) => self.component_item_ref(r), |
| ComponentExportKind::Component(r) => self.component_item_ref(r), |
| ComponentExportKind::Instance(r) => self.component_item_ref(r), |
| } |
| } |
| |
| fn start(&mut self, start: &mut Start<'a>) -> Result<(), Error> { |
| self.resolve_ns(&mut start.func, Ns::Func)?; |
| for arg in start.args.iter_mut() { |
| self.component_item_ref(arg)?; |
| } |
| Ok(()) |
| } |
| |
| fn outer_alias<T: Into<Ns>>( |
| &mut self, |
| outer: &mut Index<'a>, |
| index: &mut Index<'a>, |
| kind: T, |
| span: Span, |
| ) -> Result<(), Error> { |
| // 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 self.stack.iter().rev() { |
| if resolver.id == Some(*id) { |
| break; |
| } |
| depth += 1; |
| } |
| if depth as usize == self.stack.len() { |
| return Err(Error::new( |
| span, |
| format!("outer component `{}` not found", id.name()), |
| )); |
| } |
| depth |
| } |
| Index::Num(n, _span) => *n, |
| }; |
| |
| if depth as usize >= self.stack.len() { |
| return Err(Error::new( |
| span, |
| format!("outer count of `{depth}` is too large"), |
| )); |
| } |
| |
| *outer = Index::Num(depth, span); |
| |
| // Resolve `index` within the computed scope depth. |
| let computed = self.stack.len() - 1 - depth as usize; |
| self.stack[computed].resolve(kind.into(), index)?; |
| |
| Ok(()) |
| } |
| |
| fn alias(&mut self, alias: &mut Alias<'a>) -> Result<(), Error> { |
| match &mut alias.target { |
| AliasTarget::Export { |
| instance, |
| name: _, |
| kind: _, |
| } => { |
| self.resolve_ns(instance, Ns::Instance)?; |
| } |
| AliasTarget::CoreExport { |
| instance, |
| name: _, |
| kind: _, |
| } => { |
| self.resolve_ns(instance, Ns::CoreInstance)?; |
| } |
| AliasTarget::Outer { outer, index, kind } => { |
| self.outer_alias(outer, index, *kind, alias.span)?; |
| } |
| } |
| Ok(()) |
| } |
| |
| fn canonical_func(&mut self, func: &mut CanonicalFunc<'a>) -> Result<(), Error> { |
| match &mut func.kind { |
| CanonicalFuncKind::Lift { ty, info } => { |
| self.component_type_use(ty)?; |
| self.core_item_ref(&mut info.func)?; |
| self.canon_opts(&mut info.opts)?; |
| } |
| CanonicalFuncKind::Core(core) => match core { |
| CoreFuncKind::Alias(_) => { |
| panic!("should have been removed during expansion") |
| } |
| CoreFuncKind::Lower(info) => { |
| self.component_item_ref(&mut info.func)?; |
| self.canon_opts(&mut info.opts)?; |
| } |
| CoreFuncKind::ResourceNew(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::ResourceRep(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::ResourceDrop(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::ThreadSpawnRef(info) => { |
| self.resolve_ns(&mut info.ty, Ns::CoreType)?; |
| } |
| CoreFuncKind::ThreadSpawnIndirect(info) => { |
| self.resolve_ns(&mut info.ty, Ns::CoreType)?; |
| self.core_item_ref(&mut info.table)?; |
| } |
| CoreFuncKind::ThreadAvailableParallelism(_) |
| | CoreFuncKind::BackpressureSet |
| | CoreFuncKind::BackpressureInc |
| | CoreFuncKind::BackpressureDec |
| | CoreFuncKind::TaskCancel |
| | CoreFuncKind::ThreadYield(_) |
| | CoreFuncKind::SubtaskDrop |
| | CoreFuncKind::SubtaskCancel(_) |
| | CoreFuncKind::ErrorContextDrop => {} |
| CoreFuncKind::TaskReturn(info) => { |
| if let Some(ty) = &mut info.result { |
| self.component_val_type(ty)?; |
| } |
| self.canon_opts(&mut info.opts)?; |
| } |
| CoreFuncKind::ContextGet(_) | CoreFuncKind::ContextSet(_) => {} |
| CoreFuncKind::StreamNew(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::StreamRead(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| self.canon_opts(&mut info.opts)?; |
| } |
| CoreFuncKind::StreamWrite(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| self.canon_opts(&mut info.opts)?; |
| } |
| CoreFuncKind::StreamCancelRead(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::StreamCancelWrite(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::StreamDropReadable(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::StreamDropWritable(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::FutureNew(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::FutureRead(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| self.canon_opts(&mut info.opts)?; |
| } |
| CoreFuncKind::FutureWrite(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| self.canon_opts(&mut info.opts)?; |
| } |
| CoreFuncKind::FutureCancelRead(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::FutureCancelWrite(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::FutureDropReadable(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::FutureDropWritable(info) => { |
| self.resolve_ns(&mut info.ty, Ns::Type)?; |
| } |
| CoreFuncKind::ErrorContextNew(info) => { |
| self.canon_opts(&mut info.opts)?; |
| } |
| CoreFuncKind::ErrorContextDebugMessage(info) => { |
| self.canon_opts(&mut info.opts)?; |
| } |
| CoreFuncKind::WaitableSetNew => {} |
| CoreFuncKind::WaitableSetWait(info) => { |
| self.core_item_ref(&mut info.memory)?; |
| } |
| CoreFuncKind::WaitableSetPoll(info) => { |
| self.core_item_ref(&mut info.memory)?; |
| } |
| CoreFuncKind::WaitableSetDrop => {} |
| CoreFuncKind::WaitableJoin => {} |
| CoreFuncKind::ThreadIndex => {} |
| CoreFuncKind::ThreadNewIndirect(info) => { |
| self.resolve_ns(&mut info.ty, Ns::CoreType)?; |
| self.core_item_ref(&mut info.table)?; |
| } |
| CoreFuncKind::ThreadSwitchTo(_) => {} |
| CoreFuncKind::ThreadSuspend(_) => {} |
| CoreFuncKind::ThreadResumeLater => {} |
| CoreFuncKind::ThreadYieldTo(_) => {} |
| }, |
| } |
| |
| Ok(()) |
| } |
| |
| fn canon_opts(&mut self, opts: &mut [CanonOpt<'a>]) -> Result<(), Error> { |
| for opt in opts { |
| match opt { |
| CanonOpt::StringUtf8 |
| | CanonOpt::StringUtf16 |
| | CanonOpt::StringLatin1Utf16 |
| | CanonOpt::Async |
| | CanonOpt::Gc => {} |
| CanonOpt::Memory(r) => self.core_item_ref(r)?, |
| CanonOpt::Realloc(r) | CanonOpt::PostReturn(r) | CanonOpt::Callback(r) => { |
| self.core_item_ref(r)? |
| } |
| CanonOpt::CoreType(t) => self.core_item_ref(t)?, |
| } |
| } |
| |
| Ok(()) |
| } |
| |
| fn core_type_use<T>(&mut self, ty: &mut CoreTypeUse<'a, T>) -> Result<(), Error> { |
| let item = match ty { |
| CoreTypeUse::Ref(r) => r, |
| CoreTypeUse::Inline(_) => { |
| unreachable!("inline type-use should be expanded by now") |
| } |
| }; |
| self.core_item_ref(item) |
| } |
| |
| fn component_type_use<T>(&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") |
| } |
| }; |
| self.component_item_ref(item) |
| } |
| |
| fn defined_type(&mut self, ty: &mut ComponentDefinedType<'a>) -> Result<(), Error> { |
| match ty { |
| ComponentDefinedType::Primitive(_) => {} |
| ComponentDefinedType::Flags(_) => {} |
| ComponentDefinedType::Enum(_) => {} |
| ComponentDefinedType::Record(r) => { |
| for field in r.fields.iter_mut() { |
| self.component_val_type(&mut field.ty)?; |
| } |
| } |
| ComponentDefinedType::Variant(v) => { |
| // Namespace for case identifier resolution |
| let mut ns = Namespace::default(); |
| for case in v.cases.iter_mut() { |
| let index = ns.register(case.id, "variant case")?; |
| |
| if let Some(ty) = &mut case.ty { |
| self.component_val_type(ty)?; |
| } |
| |
| if let Some(refines) = &mut case.refines { |
| if let Refinement::Index(span, idx) = refines { |
| let resolved = ns.resolve(idx, "variant case")?; |
| if resolved == index { |
| return Err(Error::new( |
| *span, |
| "variant case cannot refine itself".to_string(), |
| )); |
| } |
| |
| *refines = Refinement::Resolved(resolved); |
| } |
| } |
| } |
| } |
| ComponentDefinedType::List(List { element: t }) |
| | ComponentDefinedType::FixedSizeList(FixedSizeList { |
| element: t, |
| elements: _, |
| }) => { |
| self.component_val_type(t)?; |
| } |
| ComponentDefinedType::Tuple(t) => { |
| for field in t.fields.iter_mut() { |
| self.component_val_type(field)?; |
| } |
| } |
| ComponentDefinedType::Option(o) => { |
| self.component_val_type(&mut o.element)?; |
| } |
| ComponentDefinedType::Result(r) => { |
| if let Some(ty) = &mut r.ok { |
| self.component_val_type(ty)?; |
| } |
| |
| if let Some(ty) = &mut r.err { |
| self.component_val_type(ty)?; |
| } |
| } |
| ComponentDefinedType::Own(t) | ComponentDefinedType::Borrow(t) => { |
| self.resolve_ns(t, Ns::Type)?; |
| } |
| ComponentDefinedType::Stream(s) => { |
| if let Some(ty) = &mut s.element { |
| self.component_val_type(ty)?; |
| } |
| } |
| ComponentDefinedType::Future(f) => { |
| if let Some(ty) = &mut f.element { |
| self.component_val_type(ty)?; |
| } |
| } |
| } |
| Ok(()) |
| } |
| |
| fn component_val_type(&mut self, ty: &mut ComponentValType<'a>) -> Result<(), Error> { |
| match ty { |
| ComponentValType::Ref(idx) => { |
| self.resolve_ns(idx, Ns::Type)?; |
| Ok(()) |
| } |
| ComponentValType::Inline(ComponentDefinedType::Primitive(_)) => Ok(()), |
| ComponentValType::Inline(_) => unreachable!("should be expanded by now"), |
| } |
| } |
| |
| fn core_ty(&mut self, field: &mut CoreType<'a>) -> Result<(), Error> { |
| match &mut field.def { |
| CoreTypeDef::Def(ty) => { |
| // See comments in `module_type` for why registration of ids happens |
| // here for core types early. |
| self.current().core_types.register(field.id, "core type")?; |
| self.current().resolve_type_def(ty)?; |
| assert!(self.aliases_to_insert.is_empty()); |
| } |
| CoreTypeDef::Module(t) => { |
| self.stack.push(ComponentState::new(field.id)); |
| self.module_type(t)?; |
| self.stack.pop(); |
| } |
| } |
| Ok(()) |
| } |
| |
| fn core_rec(&mut self, rec: &mut core::Rec<'a>) -> Result<(), Error> { |
| // See comments in `module_type` for why registration of ids happens |
| // here for core types early. |
| for ty in rec.types.iter() { |
| self.current().core_types.register(ty.id, "core type")?; |
| } |
| for ty in rec.types.iter_mut() { |
| self.current().resolve_type(ty)?; |
| } |
| assert!(self.aliases_to_insert.is_empty()); |
| Ok(()) |
| } |
| |
| fn ty(&mut self, field: &mut Type<'a>) -> Result<(), Error> { |
| match &mut field.def { |
| TypeDef::Defined(t) => { |
| self.defined_type(t)?; |
| } |
| TypeDef::Func(f) => { |
| for param in f.params.iter_mut() { |
| self.component_val_type(&mut param.ty)?; |
| } |
| |
| if let Some(result) = &mut f.result { |
| self.component_val_type(result)?; |
| } |
| } |
| TypeDef::Component(c) => { |
| self.stack.push(ComponentState::new(field.id)); |
| self.component_type(c)?; |
| self.stack.pop(); |
| } |
| TypeDef::Instance(i) => { |
| self.stack.push(ComponentState::new(field.id)); |
| self.instance_type(i)?; |
| self.stack.pop(); |
| } |
| TypeDef::Resource(r) => { |
| match &mut r.rep { |
| ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {} |
| ValType::Ref(r) => match &mut r.heap { |
| core::HeapType::Abstract { .. } => {} |
| core::HeapType::Concrete(id) => { |
| self.resolve_ns(id, Ns::Type)?; |
| } |
| }, |
| } |
| if let Some(dtor) = &mut r.dtor { |
| self.core_item_ref(dtor)?; |
| } |
| } |
| } |
| Ok(()) |
| } |
| |
| fn component_type(&mut self, c: &mut ComponentType<'a>) -> Result<(), Error> { |
| self.resolve_prepending_aliases( |
| &mut c.decls, |
| |resolver, decl| match decl { |
| ComponentTypeDecl::Alias(alias) => resolver.alias(alias), |
| ComponentTypeDecl::CoreType(ty) => resolver.core_ty(ty), |
| ComponentTypeDecl::Type(ty) => resolver.ty(ty), |
| ComponentTypeDecl::Import(import) => resolver.item_sig(&mut import.item), |
| ComponentTypeDecl::Export(export) => resolver.item_sig(&mut export.item), |
| }, |
| |state, decl| { |
| match decl { |
| ComponentTypeDecl::Alias(alias) => { |
| state.register_alias(alias)?; |
| } |
| ComponentTypeDecl::CoreType(ty) => { |
| state.core_types.register(ty.id, "core type")?; |
| } |
| ComponentTypeDecl::Type(ty) => { |
| state.types.register(ty.id, "type")?; |
| } |
| ComponentTypeDecl::Export(e) => { |
| state.register_item_sig(&e.item)?; |
| } |
| ComponentTypeDecl::Import(i) => { |
| state.register_item_sig(&i.item)?; |
| } |
| } |
| Ok(()) |
| }, |
| ) |
| } |
| |
| fn instance_type(&mut self, c: &mut InstanceType<'a>) -> Result<(), Error> { |
| self.resolve_prepending_aliases( |
| &mut c.decls, |
| |resolver, decl| match decl { |
| InstanceTypeDecl::Alias(alias) => resolver.alias(alias), |
| InstanceTypeDecl::CoreType(ty) => resolver.core_ty(ty), |
| InstanceTypeDecl::Type(ty) => resolver.ty(ty), |
| InstanceTypeDecl::Export(export) => resolver.item_sig(&mut export.item), |
| }, |
| |state, decl| { |
| match decl { |
| InstanceTypeDecl::Alias(alias) => { |
| state.register_alias(alias)?; |
| } |
| InstanceTypeDecl::CoreType(ty) => { |
| state.core_types.register(ty.id, "core type")?; |
| } |
| InstanceTypeDecl::Type(ty) => { |
| state.types.register(ty.id, "type")?; |
| } |
| InstanceTypeDecl::Export(export) => { |
| state.register_item_sig(&export.item)?; |
| } |
| } |
| Ok(()) |
| }, |
| ) |
| } |
| |
| fn core_item_ref<K>(&mut self, item: &mut CoreItemRef<'a, K>) -> Result<(), Error> |
| where |
| K: CoreItem + Copy, |
| { |
| // Check for not being an instance export reference |
| if item.export_name.is_none() { |
| self.resolve_ns(&mut item.idx, item.kind.ns())?; |
| return Ok(()); |
| } |
| |
| // This is a reference to a core instance export |
| let mut index = item.idx; |
| self.resolve_ns(&mut index, Ns::CoreInstance)?; |
| |
| // Record an alias to reference the export |
| let span = item.idx.span(); |
| let alias = Alias { |
| span, |
| id: None, |
| name: None, |
| target: AliasTarget::CoreExport { |
| instance: index, |
| name: item.export_name.unwrap(), |
| kind: item.kind.ns().into(), |
| }, |
| }; |
| |
| index = Index::Num(self.current().register_alias(&alias)?, span); |
| self.aliases_to_insert.push(alias); |
| |
| item.idx = index; |
| item.export_name = None; |
| |
| Ok(()) |
| } |
| |
| fn component_item_ref<K>(&mut self, item: &mut ItemRef<'a, K>) -> Result<(), Error> |
| where |
| K: ComponentItem + Copy, |
| { |
| // Check for not being an instance export reference |
| if item.export_names.is_empty() { |
| self.resolve_ns(&mut item.idx, item.kind.ns())?; |
| return Ok(()); |
| } |
| |
| // This is a reference to an instance export |
| let mut index = item.idx; |
| self.resolve_ns(&mut index, Ns::Instance)?; |
| |
| let span = item.idx.span(); |
| for (pos, export_name) in item.export_names.iter().enumerate() { |
| // Record an alias to reference the export |
| let alias = Alias { |
| span, |
| id: None, |
| name: None, |
| target: AliasTarget::Export { |
| instance: index, |
| name: export_name, |
| kind: if pos == item.export_names.len() - 1 { |
| item.kind.ns().into() |
| } else { |
| ComponentExportAliasKind::Instance |
| }, |
| }, |
| }; |
| |
| index = Index::Num(self.current().register_alias(&alias)?, span); |
| self.aliases_to_insert.push(alias); |
| } |
| |
| item.idx = index; |
| item.export_names = Vec::new(); |
| |
| Ok(()) |
| } |
| |
| fn resolve_ns(&mut self, idx: &mut Index<'a>, ns: Ns) -> Result<u32, 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; |
| 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, |
| }; |
| |
| // If this is the current component then no extra alias is necessary, so |
| // return success. |
| if depth == 0 { |
| *idx = idx_clone; |
| return Ok(found); |
| } |
| let id = match idx { |
| Index::Id(id) => *id, |
| 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 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::CoreModule => ComponentOuterAliasKind::CoreModule, |
| Ns::CoreType => ComponentOuterAliasKind::CoreType, |
| Ns::Type => ComponentOuterAliasKind::Type, |
| Ns::Component => ComponentOuterAliasKind::Component, |
| _ => { |
| return Err(Error::new( |
| span, |
| format!( |
| "outer item `{}` is not a module, type, or component", |
| id.name(), |
| ), |
| )); |
| } |
| }, |
| }, |
| }; |
| let local_index = self.current().register_alias(&alias)?; |
| self.aliases_to_insert.push(alias); |
| *idx = Index::Num(local_index, span); |
| return Ok(local_index); |
| } |
| |
| // If resolution in any parent failed then simply return the error from our |
| // local namespace |
| self.current().resolve(ns, idx)?; |
| unreachable!() |
| } |
| |
| fn module_type(&mut self, ty: &mut ModuleType<'a>) -> Result<(), Error> { |
| return self.resolve_prepending_aliases( |
| &mut ty.decls, |
| |resolver, decl| match decl { |
| ModuleTypeDecl::Alias(alias) => resolver.alias(alias), |
| |
| // For types since the GC proposal to core wasm they're allowed |
| // to both refer to themselves and additionally a recursion |
| // group can define a set of types that all refer to one |
| // another. That means that the type names must be registered |
| // first before the type is resolved so the type's own name is |
| // in scope for itself. |
| // |
| // Note though that this means that aliases cannot be injected |
| // automatically for references to outer types. We don't know |
| // how many aliases are going to be created so we otherwise |
| // don't know the type index to register. |
| // |
| // As a compromise for now core types don't support |
| // auto-injection of aliases from outer scopes. They must be |
| // explicitly aliased in. Also note that the error message isn't |
| // great either. This may be something we want to improve in the |
| // future with a better error message or a pass that goes over |
| // everything first to inject aliases and then afterwards all |
| // other names are registered. |
| ModuleTypeDecl::Type(t) => { |
| resolver.current().core_types.register(t.id, "type")?; |
| resolver.current().resolve_type(t) |
| } |
| ModuleTypeDecl::Rec(t) => { |
| for t in t.types.iter_mut() { |
| resolver.current().core_types.register(t.id, "type")?; |
| } |
| for t in t.types.iter_mut() { |
| resolver.current().resolve_type(t)?; |
| } |
| Ok(()) |
| } |
| |
| ModuleTypeDecl::Import(import) => resolve_item_sig(resolver, &mut import.item), |
| ModuleTypeDecl::Export(_, item) => resolve_item_sig(resolver, item), |
| }, |
| |state, decl| { |
| match decl { |
| ModuleTypeDecl::Alias(alias) => { |
| state.register_alias(alias)?; |
| } |
| // These were registered above already |
| ModuleTypeDecl::Type(_) | ModuleTypeDecl::Rec(_) => {} |
| // Only the type namespace is populated within the module type |
| // namespace so these are ignored here. |
| ModuleTypeDecl::Import(_) | ModuleTypeDecl::Export(..) => {} |
| } |
| Ok(()) |
| }, |
| ); |
| |
| fn resolve_item_sig<'a>( |
| resolver: &Resolver<'a>, |
| sig: &mut core::ItemSig<'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"); |
| resolver |
| .stack |
| .last() |
| .unwrap() |
| .core_types |
| .resolve(idx, "type")?; |
| } |
| core::ItemKind::Memory(_) |
| | core::ItemKind::Global(_) |
| | core::ItemKind::Table(_) => {} |
| } |
| Ok(()) |
| } |
| } |
| } |
| |
| impl<'a> ComponentState<'a> { |
| fn resolve(&self, ns: Ns, idx: &mut Index<'a>) -> Result<u32, Error> { |
| match ns { |
| Ns::CoreFunc => self.core_funcs.resolve(idx, "core func"), |
| Ns::CoreGlobal => self.core_globals.resolve(idx, "core global"), |
| Ns::CoreTable => self.core_tables.resolve(idx, "core table"), |
| Ns::CoreMemory => self.core_memories.resolve(idx, "core memory"), |
| Ns::CoreType => self.core_types.resolve(idx, "core type"), |
| Ns::CoreTag => self.core_tags.resolve(idx, "core tag"), |
| Ns::CoreInstance => self.core_instances.resolve(idx, "core instance"), |
| Ns::CoreModule => self.core_modules.resolve(idx, "core module"), |
| Ns::Func => self.funcs.resolve(idx, "func"), |
| Ns::Type => self.types.resolve(idx, "type"), |
| Ns::Instance => self.instances.resolve(idx, "instance"), |
| Ns::Component => self.components.resolve(idx, "component"), |
| Ns::Value => self.values.resolve(idx, "value"), |
| } |
| } |
| |
| /// Assign an index to the given field. |
| fn register(&mut self, item: &ComponentField<'a>) -> Result<(), Error> { |
| match item { |
| ComponentField::CoreModule(m) => self.core_modules.register(m.id, "core module")?, |
| ComponentField::CoreInstance(i) => { |
| self.core_instances.register(i.id, "core instance")? |
| } |
| ComponentField::CoreType(ty) => match &ty.def { |
| CoreTypeDef::Def(_) => 0, // done above in `core_rec` |
| CoreTypeDef::Module(_) => self.core_types.register(ty.id, "core type")?, |
| }, |
| ComponentField::CoreRec(_) => 0, // done above in `core_rec` |
| ComponentField::Component(c) => self.components.register(c.id, "component")?, |
| ComponentField::Instance(i) => self.instances.register(i.id, "instance")?, |
| ComponentField::Alias(a) => self.register_alias(a)?, |
| ComponentField::Type(t) => self.types.register(t.id, "type")?, |
| ComponentField::CanonicalFunc(f) => match &f.kind { |
| CanonicalFuncKind::Lift { .. } => self.funcs.register(f.id, "func")?, |
| CanonicalFuncKind::Core(_) => self.core_funcs.register(f.id, "core func")?, |
| }, |
| ComponentField::CoreFunc(_) | ComponentField::Func(_) => { |
| unreachable!("should be expanded already") |
| } |
| ComponentField::Start(s) => { |
| for r in &s.results { |
| self.values.register(*r, "value")?; |
| } |
| return Ok(()); |
| } |
| ComponentField::Import(i) => self.register_item_sig(&i.item)?, |
| ComponentField::Export(e) => match &e.kind { |
| ComponentExportKind::CoreModule(_) => { |
| self.core_modules.register(e.id, "core module")? |
| } |
| ComponentExportKind::Func(_) => self.funcs.register(e.id, "func")?, |
| ComponentExportKind::Instance(_) => self.instances.register(e.id, "instance")?, |
| ComponentExportKind::Value(_) => self.values.register(e.id, "value")?, |
| ComponentExportKind::Component(_) => self.components.register(e.id, "component")?, |
| ComponentExportKind::Type(_) => self.types.register(e.id, "type")?, |
| }, |
| ComponentField::Custom(_) | ComponentField::Producers(_) => return Ok(()), |
| }; |
| |
| Ok(()) |
| } |
| |
| fn register_alias(&mut self, alias: &Alias<'a>) -> Result<u32, Error> { |
| match alias.target { |
| AliasTarget::Export { kind, .. } => match kind { |
| ComponentExportAliasKind::CoreModule => { |
| self.core_modules.register(alias.id, "core module") |
| } |
| ComponentExportAliasKind::Func => self.funcs.register(alias.id, "func"), |
| ComponentExportAliasKind::Value => self.values.register(alias.id, "value"), |
| ComponentExportAliasKind::Type => self.types.register(alias.id, "type"), |
| ComponentExportAliasKind::Component => { |
| self.components.register(alias.id, "component") |
| } |
| ComponentExportAliasKind::Instance => self.instances.register(alias.id, "instance"), |
| }, |
| AliasTarget::CoreExport { kind, .. } => match kind { |
| core::ExportKind::Func => self.core_funcs.register(alias.id, "core func"), |
| core::ExportKind::Table => self.core_tables.register(alias.id, "core table"), |
| core::ExportKind::Memory => self.core_memories.register(alias.id, "core memory"), |
| core::ExportKind::Global => self.core_globals.register(alias.id, "core global"), |
| core::ExportKind::Tag => self.core_tags.register(alias.id, "core tag"), |
| }, |
| AliasTarget::Outer { kind, .. } => match kind { |
| ComponentOuterAliasKind::CoreModule => { |
| self.core_modules.register(alias.id, "core module") |
| } |
| ComponentOuterAliasKind::CoreType => { |
| self.core_types.register(alias.id, "core type") |
| } |
| ComponentOuterAliasKind::Type => self.types.register(alias.id, "type"), |
| ComponentOuterAliasKind::Component => { |
| self.components.register(alias.id, "component") |
| } |
| }, |
| } |
| } |
| } |
| |
| impl<'a> ResolveCoreType<'a> for ComponentState<'a> { |
| fn resolve_type_name(&mut self, name: &mut Index<'a>) -> Result<u32, Error> { |
| self.resolve(Ns::CoreType, name) |
| } |
| } |
| |
| #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] |
| enum Ns { |
| CoreFunc, |
| CoreGlobal, |
| CoreTable, |
| CoreMemory, |
| CoreType, |
| CoreTag, |
| CoreInstance, |
| CoreModule, |
| Func, |
| Type, |
| Instance, |
| Component, |
| Value, |
| } |
| |
| trait ComponentItem { |
| fn ns(&self) -> Ns; |
| } |
| |
| trait CoreItem { |
| fn ns(&self) -> Ns; |
| } |
| |
| macro_rules! component_item { |
| ($kw:path, $kind:ident) => { |
| impl ComponentItem for $kw { |
| fn ns(&self) -> Ns { |
| Ns::$kind |
| } |
| } |
| }; |
| } |
| |
| macro_rules! core_item { |
| ($kw:path, $kind:ident) => { |
| impl CoreItem for $kw { |
| fn ns(&self) -> Ns { |
| Ns::$kind |
| } |
| } |
| }; |
| } |
| |
| component_item!(kw::func, Func); |
| component_item!(kw::r#type, Type); |
| component_item!(kw::r#instance, Instance); |
| component_item!(kw::component, Component); |
| component_item!(kw::value, Value); |
| component_item!(kw::module, CoreModule); |
| |
| core_item!(kw::func, CoreFunc); |
| core_item!(kw::memory, CoreMemory); |
| core_item!(kw::table, CoreTable); |
| core_item!(kw::r#type, CoreType); |
| core_item!(kw::r#instance, CoreInstance); |
| |
| impl From<Ns> for ComponentExportAliasKind { |
| fn from(ns: Ns) -> Self { |
| match ns { |
| Ns::CoreModule => Self::CoreModule, |
| Ns::Func => Self::Func, |
| Ns::Type => Self::Type, |
| Ns::Instance => Self::Instance, |
| Ns::Component => Self::Component, |
| Ns::Value => Self::Value, |
| _ => unreachable!("not a component exportable namespace"), |
| } |
| } |
| } |
| |
| impl From<Ns> for core::ExportKind { |
| fn from(ns: Ns) -> Self { |
| match ns { |
| Ns::CoreFunc => Self::Func, |
| Ns::CoreTable => Self::Table, |
| Ns::CoreGlobal => Self::Global, |
| Ns::CoreMemory => Self::Memory, |
| Ns::CoreTag => Self::Tag, |
| _ => unreachable!("not a core exportable namespace"), |
| } |
| } |
| } |
| |
| impl From<ComponentOuterAliasKind> for Ns { |
| fn from(kind: ComponentOuterAliasKind) -> Self { |
| match kind { |
| ComponentOuterAliasKind::CoreModule => Self::CoreModule, |
| ComponentOuterAliasKind::CoreType => Self::CoreType, |
| ComponentOuterAliasKind::Type => Self::Type, |
| ComponentOuterAliasKind::Component => Self::Component, |
| } |
| } |
| } |
| |
| impl CoreItem for core::ExportKind { |
| fn ns(&self) -> Ns { |
| match self { |
| Self::Func => Ns::CoreFunc, |
| Self::Table => Ns::CoreTable, |
| Self::Global => Ns::CoreGlobal, |
| Self::Memory => Ns::CoreMemory, |
| Self::Tag => Ns::CoreTag, |
| } |
| } |
| } |