Revision control
Copy as Markdown
Other Tools
use crate::component::*;
use crate::core::{self, resolve::ResolveCoreType, ValType};
use crate::kw;
use crate::names::Namespace;
use crate::token::Span;
use crate::token::{Id, Index};
use crate::Error;
/// 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 `{}` is too large", depth),
));
}
*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::Lower(info) => {
self.component_item_ref(&mut info.func)?;
self.canon_opts(&mut info.opts)?;
}
CanonicalFuncKind::ResourceNew(info) => {
self.resolve_ns(&mut info.ty, Ns::Type)?;
}
CanonicalFuncKind::ResourceRep(info) => {
self.resolve_ns(&mut info.ty, Ns::Type)?;
}
CanonicalFuncKind::ResourceDrop(info) => {
self.resolve_ns(&mut info.ty, Ns::Type)?;
}
CanonicalFuncKind::ThreadSpawn(info) => {
self.resolve_ns(&mut info.ty, Ns::CoreType)?;
}
CanonicalFuncKind::ThreadHwConcurrency(_) => {}
}
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::Memory(r) => self.core_item_ref(r)?,
CanonOpt::Realloc(r) | CanonOpt::PostReturn(r) => self.core_item_ref(r)?,
}
}
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(l) => {
self.component_val_type(&mut l.element)?;
}
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)?;
}
}
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)?;
}
for result in f.results.iter_mut() {
self.component_val_type(&mut result.ty)?;
}
}
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: ns.into(),
},
};
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::Lower(_)
| CanonicalFuncKind::ResourceNew(_)
| CanonicalFuncKind::ResourceRep(_)
| CanonicalFuncKind::ResourceDrop(_)
| CanonicalFuncKind::ThreadSpawn(_)
| CanonicalFuncKind::ThreadHwConcurrency(_) => {
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::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 ComponentOuterAliasKind {
fn from(ns: Ns) -> Self {
match ns {
Ns::CoreModule => Self::CoreModule,
Ns::CoreType => Self::CoreType,
Ns::Type => Self::Type,
Ns::Component => Self::Component,
_ => unreachable!("not an outer alias 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,
}
}
}