Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/wasmparser/src/validator/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 127 kB image not shown  

Quelle  component.rs   Sprache: unbekannt

 
Spracherkennung für: .rs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

//! State relating to validating a WebAssembly component.

use super::{
    check_max,
    component_types::{
        AliasableResourceId, ComponentAnyTypeId, ComponentCoreInstanceTypeId,
        ComponentCoreModuleTypeId, ComponentCoreTypeId, ComponentDefinedType,
        ComponentDefinedTypeId, ComponentEntityType, ComponentFuncType, ComponentFuncTypeId,
        ComponentInstanceType, ComponentInstanceTypeId, ComponentType, ComponentTypeId,
        ComponentValType, Context, CoreInstanceTypeKind, InstanceType, LoweringInfo, ModuleType,
        RecordType, Remap, Remapping, ResourceId, SubtypeCx, TupleType, VariantCase, VariantType,
    },
    core::{InternRecGroup, Module},
    types::{CoreTypeId, EntityType, TypeAlloc, TypeInfo, TypeList},
};
use crate::collections::index_map::Entry;
use crate::limits::*;
use crate::prelude::*;
use crate::validator::names::{ComponentName, ComponentNameKind, KebabStr, KebabString};
use crate::{
    BinaryReaderError, CanonicalOption, ComponentExportName, ComponentExternalKind,
    ComponentOuterAliasKind, ComponentTypeRef, CompositeInnerType, ExternalKind, FuncType,
    GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType, Result, SubType, TableType,
    TypeBounds, ValType, WasmFeatures,
};
use core::mem;

fn to_kebab_str<'a>(s: &'a str, desc: &str, offset: usize) -> Result<&'a KebabStr> {
    match KebabStr::new(s) {
        Some(s) => Ok(s),
        None => {
            if s.is_empty() {
                bail!(offset, "{desc} name cannot be empty");
            }

            bail!(offset, "{desc} name `{s}` is not in kebab case");
        }
    }
}

pub(crate) struct ComponentState {
    /// Whether this state is a concrete component, an instance type, or a
    /// component type.
    kind: ComponentKind,

    // Core index spaces
    pub core_types: Vec<ComponentCoreTypeId>,
    pub core_funcs: Vec<CoreTypeId>,
    pub core_tags: Vec<CoreTypeId>,
    pub core_modules: Vec<ComponentCoreModuleTypeId>,
    pub core_instances: Vec<ComponentCoreInstanceTypeId>,
    pub core_memories: Vec<MemoryType>,
    pub core_tables: Vec<TableType>,
    pub core_globals: Vec<GlobalType>,

    // Component index spaces
    pub types: Vec<ComponentAnyTypeId>,
    pub funcs: Vec<ComponentFuncTypeId>,
    pub values: Vec<(ComponentValType, bool)>,
    pub instances: Vec<ComponentInstanceTypeId>,
    pub components: Vec<ComponentTypeId>,

    pub imports: IndexMap<String, ComponentEntityType>,
    pub import_names: IndexSet<ComponentName>,
    pub exports: IndexMap<String, ComponentEntityType>,
    pub export_names: IndexSet<ComponentName>,

    has_start: bool,
    type_info: TypeInfo,

    /// A mapping of imported resources in this component.
    ///
    /// This mapping represents all "type variables" imported into the
    /// component, or resources. This could be resources imported directly as
    /// a top-level type import or additionally transitively through other
    /// imported instances.
    ///
    /// The mapping element here is a "path" which is a list of indexes into
    /// the import map that will be generated for this component. Each index
    /// is an index into an `IndexMap`, and each list is guaranteed to have at
    /// least one element.
    ///
    /// An example of this map is:
    ///
    /// ```wasm
    /// (component
    ///     ;; [0] - the first import
    ///     (import "r" (type (sub resource)))
    ///
    ///     ;; [1] - the second import
    ///     (import "r2" (type (sub resource)))
    ///
    ///     (import "i" (instance
    ///         ;; [2, 0] - the third import, and the first export the instance
    ///         (export "r3" (type (sub resource)))
    ///         ;; [2, 1] - the third import, and the second export the instance
    ///         (export "r4" (type (sub resource)))
    ///     ))
    ///
    ///     ;; ...
    /// )
    /// ```
    ///
    /// The `Vec<usize>` here can be thought of as `Vec<String>` but a
    /// (hopefully) more efficient representation.
    ///
    /// Finally note that this map is listed as an "append only" map because all
    /// insertions into it should always succeed. Any insertion which overlaps
    /// with a previous entry indicates a bug in the validator which needs to be
    /// corrected via other means.
    //
    // TODO: make these `SkolemResourceId` and then go fix all the compile
    // errors, don't add skolem things into the type area
    imported_resources: IndexMapAppendOnly<ResourceId, Vec<usize>>,

    /// A mapping of "defined" resources in this component, or those which
    /// are defined within the instantiation of this component.
    ///
    /// Defined resources, as the name implies, can sort of be thought of as
    /// "these are defined within the component". Note though that the means by
    /// which a local definition can occur are not simply those defined in the
    /// component but also in its transitively instantiated components
    /// internally. This means that this set closes over many transitive
    /// internal items in addition to those defined immediately in the component
    /// itself.
    ///
    /// The `Option<ValType>` in this mapping is whether or not the underlying
    /// representation of the resource is known to this component. Immediately
    /// defined resources, for example, will have `Some(I32)` here. Resources
    /// that come from transitively defined components, for example, will have
    /// `None`. In the type context all entries here are `None`.
    ///
    /// Note that like `imported_resources` all insertions into this map are
    /// expected to succeed to it's declared as append-only.
    defined_resources: IndexMapAppendOnly<ResourceId, Option<ValType>>,

    /// A mapping of explicitly exported resources from this component in
    /// addition to the path that they're exported at.
    ///
    /// For more information on the path here see the documentation for
    /// `imported_resources`. Note that the indexes here index into the
    /// list of exports of this component.
    explicit_resources: IndexMap<ResourceId, Vec<usize>>,

    /// The set of types which are considered "exported" from this component.
    ///
    /// This is added to whenever a type export is found, or an instance export
    /// which itself contains a type export. This additionally includes all
    /// imported types since those are suitable for export as well.
    ///
    /// This set is consulted whenever an exported item is added since all
    /// referenced types must be members of this set.
    exported_types: Set<ComponentAnyTypeId>,

    /// Same as `exported_types`, but for imports.
    imported_types: Set<ComponentAnyTypeId>,

    /// The set of top-level resource exports and their names.
    ///
    /// This context is used to validate method names such as `[method]foo.bar`
    /// to ensure that `foo` is an exported resource and that the type mentioned
    /// in a function type is actually named `foo`.
    ///
    /// Note that imports/exports have disjoint contexts to ensure that they're
    /// validated correctly. Namely you can't retroactively attach methods to an
    /// import, for example.
    toplevel_exported_resources: ComponentNameContext,

    /// Same as `toplevel_exported_resources`, but for imports.
    toplevel_imported_resources: ComponentNameContext,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ComponentKind {
    Component,
    InstanceType,
    ComponentType,
}

/// Helper context used to track information about resource names for method
/// name validation.
#[derive(Default)]
struct ComponentNameContext {
    /// A map from a resource type id to an index in the `all_resource_names`
    /// set for the name of that resource.
    resource_name_map: Map<AliasableResourceId, usize>,

    /// All known resource names in this context, used to validate static method
    /// names to by ensuring that static methods' resource names are somewhere
    /// in this set.
    all_resource_names: IndexSet<String>,
}

#[derive(Debug, Copy, Clone)]
pub enum ExternKind {
    Import,
    Export,
}

impl ExternKind {
    pub fn desc(&self) -> &'static str {
        match self {
            ExternKind::Import => "import",
            ExternKind::Export => "export",
        }
    }
}

impl ComponentState {
    pub fn new(kind: ComponentKind) -> Self {
        Self {
            kind,
            core_types: Default::default(),
            core_modules: Default::default(),
            core_instances: Default::default(),
            core_funcs: Default::default(),
            core_memories: Default::default(),
            core_tables: Default::default(),
            core_globals: Default::default(),
            core_tags: Default::default(),
            types: Default::default(),
            funcs: Default::default(),
            values: Default::default(),
            instances: Default::default(),
            components: Default::default(),
            imports: Default::default(),
            exports: Default::default(),
            import_names: Default::default(),
            export_names: Default::default(),
            has_start: Default::default(),
            type_info: TypeInfo::new(),
            imported_resources: Default::default(),
            defined_resources: Default::default(),
            explicit_resources: Default::default(),
            exported_types: Default::default(),
            imported_types: Default::default(),
            toplevel_exported_resources: Default::default(),
            toplevel_imported_resources: Default::default(),
        }
    }

    pub fn type_count(&self) -> usize {
        self.core_types.len() + self.types.len()
    }

    pub fn instance_count(&self) -> usize {
        self.core_instances.len() + self.instances.len()
    }

    pub fn function_count(&self) -> usize {
        self.core_funcs.len() + self.funcs.len()
    }

    pub fn add_core_type(
        components: &mut [Self],
        ty: crate::CoreType,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
        check_limit: bool,
    ) -> Result<()> {
        let current = components.last_mut().unwrap();
        if check_limit {
            check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
        }
        match ty {
            crate::CoreType::Rec(rec) => {
                current.canonicalize_and_intern_rec_group(features, types, rec, offset)?;
            }
            crate::CoreType::Module(decls) => {
                let mod_ty = Self::create_module_type(
                    components,
                    decls.into_vec(),
                    features,
                    types,
                    offset,
                )?;
                let id = ComponentCoreTypeId::Module(types.push_ty(mod_ty));
                components.last_mut().unwrap().core_types.push(id);
            }
        }

        Ok(())
    }

    pub fn add_core_module(
        &mut self,
        module: &Module,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<()> {
        let imports = module.imports_for_module_type(offset)?;

        // We have to clone the module's imports and exports here
        // because we cannot take the data out of the `MaybeOwned`
        // as it might be shared with a function validator.
        let mod_ty = ModuleType {
            info: TypeInfo::core(module.type_size),
            imports,
            exports: module.exports.clone(),
        };

        let mod_id = types.push_ty(mod_ty);
        self.core_modules.push(mod_id);

        Ok(())
    }

    pub fn add_core_instance(
        &mut self,
        instance: crate::Instance,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<()> {
        let instance = match instance {
            crate::Instance::Instantiate { module_index, args } => {
                self.instantiate_core_module(module_index, args.into_vec(), types, offset)?
            }
            crate::Instance::FromExports(exports) => {
                self.instantiate_core_exports(exports.into_vec(), types, offset)?
            }
        };

        self.core_instances.push(instance);

        Ok(())
    }

    pub fn add_type(
        components: &mut Vec<Self>,
        ty: crate::ComponentType,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
        check_limit: bool,
    ) -> Result<()> {
        assert!(!components.is_empty());

        fn current(components: &mut Vec<ComponentState>) -> &mut ComponentState {
            components.last_mut().unwrap()
        }

        let id = match ty {
            crate::ComponentType::Defined(ty) => {
                let ty = current(components).create_defined_type(ty, types, features, offset)?;
                types.push(ty).into()
            }
            crate::ComponentType::Func(ty) => {
                let ty = current(components).create_function_type(ty, types, features, offset)?;
                types.push(ty).into()
            }
            crate::ComponentType::Component(decls) => {
                let ty = Self::create_component_type(
                    components,
                    decls.into_vec(),
                    features,
                    types,
                    offset,
                )?;
                types.push(ty).into()
            }
            crate::ComponentType::Instance(decls) => {
                let ty = Self::create_instance_type(
                    components,
                    decls.into_vec(),
                    features,
                    types,
                    offset,
                )?;
                types.push(ty).into()
            }
            crate::ComponentType::Resource { rep, dtor } => {
                let component = current(components);

                // Resource types cannot be declared in a type context, only
                // within a component context.
                if component.kind != ComponentKind::Component {
                    bail!(
                        offset,
                        "resources can only be defined within a concrete component"
                    );
                }

                // Current MVP restriction of the component model.
                if rep != ValType::I32 {
                    bail!(offset, "resources can only be represented by `i32`");
                }

                // If specified validate that the destructor is both a valid
                // function and has the correct signature.
                if let Some(dtor) = dtor {
                    let ty = component.core_function_at(dtor, offset)?;
                    let ty = types[ty].composite_type.unwrap_func();
                    if ty.params() != [rep] || ty.results() != [] {
                        bail!(
                            offset,
                            "core function {dtor} has wrong signature for a destructor"
                        );
                    }
                }

                // As this is the introduction of a resource create a fresh new
                // identifier for the resource. This is then added into the
                // list of defined resources for this component, notably with a
                // rep listed to enable getting access to various intrinsics
                // such as `resource.rep`.
                let id = types.alloc_resource_id();
                component.defined_resources.insert(id.resource(), Some(rep));
                id.into()
            }
        };

        let current = current(components);
        if check_limit {
            check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
        }
        current.types.push(id);

        Ok(())
    }

    pub fn add_import(
        &mut self,
        import: crate::ComponentImport,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<()> {
        let mut entity = self.check_type_ref(&import.ty, features, types, offset)?;
        self.add_entity(
            &mut entity,
            Some((import.name.0, ExternKind::Import)),
            features,
            types,
            offset,
        )?;
        self.toplevel_imported_resources.validate_extern(
            import.name.0,
            ExternKind::Import,
            &entity,
            types,
            offset,
            &mut self.import_names,
            &mut self.imports,
            &mut self.type_info,
            features,
        )?;
        Ok(())
    }

    fn add_entity(
        &mut self,
        ty: &mut ComponentEntityType,
        name_and_kind: Option<(&str, ExternKind)>,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<()> {
        let kind = name_and_kind.map(|(_, k)| k);
        let (len, max, desc) = match ty {
            ComponentEntityType::Module(id) => {
                self.core_modules.push(*id);
                (self.core_modules.len(), MAX_WASM_MODULES, "modules")
            }
            ComponentEntityType::Component(id) => {
                self.components.push(*id);
                (self.components.len(), MAX_WASM_COMPONENTS, "components")
            }
            ComponentEntityType::Instance(id) => {
                match kind {
                    Some(ExternKind::Import) => self.prepare_instance_import(id, types),
                    Some(ExternKind::Export) => self.prepare_instance_export(id, types),
                    None => {}
                }
                self.instances.push(*id);
                (self.instance_count(), MAX_WASM_INSTANCES, "instances")
            }
            ComponentEntityType::Func(id) => {
                self.funcs.push(*id);
                (self.function_count(), MAX_WASM_FUNCTIONS, "functions")
            }
            ComponentEntityType::Value(ty) => {
                self.check_value_support(features, offset)?;
                let value_used = match kind {
                    Some(ExternKind::Import) | None => false,
                    Some(ExternKind::Export) => true,
                };
                self.values.push((*ty, value_used));
                (self.values.len(), MAX_WASM_VALUES, "values")
            }
            ComponentEntityType::Type {
                created,
                referenced,
            } => {
                self.types.push(*created);

                // Extra logic here for resources being imported and exported.
                // Note that if `created` is the same as `referenced` then this
                // is the original introduction of the resource which is where
                // `self.{imported,defined}_resources` are updated.
                if let ComponentAnyTypeId::Resource(id) = *created {
                    match kind {
                        Some(ExternKind::Import) => {
                            // A fresh new resource is being imported into a
                            // component. This arises from the import section of
                            // a component or from the import declaration in a
                            // component type. In both cases a new imported
                            // resource is injected with a fresh new identifier
                            // into our state.
                            if created == referenced {
                                self.imported_resources
                                    .insert(id.resource(), vec![self.imports.len()]);
                            }
                        }

                        Some(ExternKind::Export) => {
                            // A fresh resource is being exported from this
                            // component. This arises as part of the
                            // declaration of a component type, for example. In
                            // this situation brand new resource identifier is
                            // allocated and a definition is added, unlike the
                            // import case where an imported resource is added.
                            // Notably the representation of this new resource
                            // is unknown so it's listed as `None`.
                            if created == referenced {
                                self.defined_resources.insert(id.resource(), None);
                            }

                            // If this is a type export of a resource type then
                            // update the `explicit_resources` list. A new
                            // export path is about to be created for this
                            // resource and this keeps track of that.
                            self.explicit_resources
                                .insert(id.resource(), vec![self.exports.len()]);
                        }

                        None => {}
                    }
                }
                (self.types.len(), MAX_WASM_TYPES, "types")
            }
        };

        check_max(len, 0, max, desc, offset)?;

        // Before returning perform the final validation of the type of the item
        // being imported/exported. This will ensure that everything is
        // appropriately named with respect to type definitions, resources, etc.
        if let Some((name, kind)) = name_and_kind {
            if !self.validate_and_register_named_types(Some(name), kind, ty, types) {
                bail!(
                    offset,
                    "{} not valid to be used as {}",
                    ty.desc(),
                    kind.desc()
                );
            }
        }
        Ok(())
    }

    /// Validates that the `ty` referenced only refers to named types internally
    /// and then inserts anything necessary, if applicable, to the defined sets
    /// within this component.
    ///
    /// This function will validate that `ty` only refers to named types. For
    /// example if it's a record then all of its fields must refer to named
    /// types. This consults either `self.imported_types` or
    /// `self.exported_types` as specified by `kind`. Note that this is not
    /// inherently recursive itself but it ends up being recursive since if
    /// recursive members were named then all their components must also be
    /// named. Consequently this check stops at the "one layer deep" position,
    /// or more accurately the position where types must be named (e.g. tuples
    /// aren't required to be named).
    fn validate_and_register_named_types(
        &mut self,
        toplevel_name: Option<&str>,
        kind: ExternKind,
        ty: &ComponentEntityType,
        types: &TypeAlloc,
    ) -> bool {
        if let ComponentEntityType::Type { created, .. } = ty {
            // If this is a top-level resource then register it in the
            // appropriate context so later validation of method-like-names
            // works out.
            if let Some(name) = toplevel_name {
                if let ComponentAnyTypeId::Resource(id) = *created {
                    let cx = match kind {
                        ExternKind::Import => &mut self.toplevel_imported_resources,
                        ExternKind::Export => &mut self.toplevel_exported_resources,
                    };
                    cx.register(name, id);
                }
            }
        }

        match self.kind {
            ComponentKind::Component | ComponentKind::ComponentType => {}
            ComponentKind::InstanceType => return true,
        }
        let set = match kind {
            ExternKind::Import => &self.imported_types,
            ExternKind::Export => &self.exported_types,
        };
        match ty {
            // When a type is imported or exported than any recursive type
            // referred to by that import/export must additionally be exported
            // or imported. Here this walks the "first layer" of the type which
            // delegates to `TypeAlloc::type_named_type_id` to determine whether
            // the components of the type being named here are indeed all they
            // themselves named.
            ComponentEntityType::Type {
                created,
                referenced,
            } => {
                if !self.all_valtypes_named(types, *referenced, set) {
                    return false;
                }
                match kind {
                    // Imported types are both valid for import and valid for
                    // export.
                    ExternKind::Import => {
                        self.imported_types.insert(*created);
                        self.exported_types.insert(*created);
                    }
                    ExternKind::Export => {
                        self.exported_types.insert(*created);
                    }
                }

                true
            }

            // Instances are slightly nuanced here. The general idea is that if
            // an instance is imported, then any type exported by the instance
            // is then also exported. Additionally for exports. To get this to
            // work out this arm will recursively call
            // `validate_and_register_named_types` which means that types are
            // inserted into `self.{imported,exported}_types` as-we-go rather
            // than all at once.
            //
            // This then recursively validates that all items in the instance
            // itself are valid to import/export, recursive instances are
            // captured, and everything is appropriately added to the right
            // imported/exported set.
            ComponentEntityType::Instance(i) => types[*i]
                .exports
                .iter()
                .all(|(_name, ty)| self.validate_and_register_named_types(None, kind, ty, types)),

            // All types referred to by a function must be named.
            ComponentEntityType::Func(id) => self.all_valtypes_named_in_func(types, *id, set),

            ComponentEntityType::Value(ty) => types.type_named_valtype(ty, set),

            // Components/modules are always "closed" or "standalone" and don't
            // need validation with respect to their named types.
            ComponentEntityType::Component(_) | ComponentEntityType::Module(_) => true,
        }
    }

    fn all_valtypes_named(
        &self,
        types: &TypeAlloc,
        id: ComponentAnyTypeId,
        set: &Set<ComponentAnyTypeId>,
    ) -> bool {
        match id {
            // Resource types, in isolation, are always valid to import or
            // export since they're either attached to an import or being
            // exported.
            //
            // Note that further validation of this happens in `finish`, too.
            ComponentAnyTypeId::Resource(_) => true,

            // Component types are validated as they are constructed,
            // so all component types are valid to export if they've
            // already been constructed.
            ComponentAnyTypeId::Component(_) => true,

            ComponentAnyTypeId::Defined(id) => self.all_valtypes_named_in_defined(types, id, set),
            ComponentAnyTypeId::Func(id) => self.all_valtypes_named_in_func(types, id, set),
            ComponentAnyTypeId::Instance(id) => self.all_valtypes_named_in_instance(types, id, set),
        }
    }

    fn all_valtypes_named_in_instance(
        &self,
        types: &TypeAlloc,
        id: ComponentInstanceTypeId,
        set: &Set<ComponentAnyTypeId>,
    ) -> bool {
        // Instances must recursively have all referenced types named.
        let ty = &types[id];
        ty.exports.values().all(|ty| match ty {
            ComponentEntityType::Module(_) => true,
            ComponentEntityType::Func(id) => self.all_valtypes_named_in_func(types, *id, set),
            ComponentEntityType::Type { created: id, .. } => {
                self.all_valtypes_named(types, *id, set)
            }
            ComponentEntityType::Value(ComponentValType::Type(id)) => {
                self.all_valtypes_named_in_defined(types, *id, set)
            }
            ComponentEntityType::Instance(id) => {
                self.all_valtypes_named_in_instance(types, *id, set)
            }
            ComponentEntityType::Component(_)
            | ComponentEntityType::Value(ComponentValType::Primitive(_)) => return true,
        })
    }

    fn all_valtypes_named_in_defined(
        &self,
        types: &TypeAlloc,
        id: ComponentDefinedTypeId,
        set: &Set<ComponentAnyTypeId>,
    ) -> bool {
        let ty = &types[id];
        match ty {
            // These types do not contain anything which must be
            // named.
            ComponentDefinedType::Primitive(_)
            | ComponentDefinedType::Flags(_)
            | ComponentDefinedType::Enum(_) => true,

            // Referenced types of all these aggregates must all be
            // named.
            ComponentDefinedType::Record(r) => {
                r.fields.values().all(|t| types.type_named_valtype(t, set))
            }
            ComponentDefinedType::Tuple(r) => {
                r.types.iter().all(|t| types.type_named_valtype(t, set))
            }
            ComponentDefinedType::Variant(r) => r
                .cases
                .values()
                .filter_map(|t| t.ty.as_ref())
                .all(|t| types.type_named_valtype(t, set)),
            ComponentDefinedType::Result { ok, err } => {
                ok.as_ref()
                    .map(|t| types.type_named_valtype(t, set))
                    .unwrap_or(true)
                    && err
                        .as_ref()
                        .map(|t| types.type_named_valtype(t, set))
                        .unwrap_or(true)
            }
            ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => {
                types.type_named_valtype(ty, set)
            }

            // The resource referred to by own/borrow must be named.
            ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => {
                set.contains(&ComponentAnyTypeId::from(*id))
            }
        }
    }

    fn all_valtypes_named_in_func(
        &self,
        types: &TypeAlloc,
        id: ComponentFuncTypeId,
        set: &Set<ComponentAnyTypeId>,
    ) -> bool {
        let ty = &types[id];
        // Function types must have all their parameters/results named.
        ty.params
            .iter()
            .map(|(_, ty)| ty)
            .chain(ty.results.iter().map(|(_, ty)| ty))
            .all(|ty| types.type_named_valtype(ty, set))
    }

    /// Updates the type `id` specified, an identifier for a component instance
    /// type, to be imported into this component.
    ///
    /// Importing an instance type into a component specially handles the
    /// defined resources registered in the instance type. Notably all
    /// defined resources are "freshened" into brand new type variables and
    /// these new variables are substituted within the type. This is what
    /// creates a new `TypeId` and may update the `id` specified.
    ///
    /// One side effect of this operation, for example, is that if an instance
    /// type is used twice to import two different instances then the instances
    /// do not share resource types despite sharing the same original instance
    /// type.
    fn prepare_instance_import(&mut self, id: &mut ComponentInstanceTypeId, types: &mut TypeAlloc) {
        let ty = &types[*id];

        // No special treatment for imports of instances which themselves have
        // no defined resources
        if ty.defined_resources.is_empty() {
            return;
        }

        let mut new_ty = ComponentInstanceType {
            // Copied from the input verbatim
            info: ty.info,

            // Copied over as temporary storage for now, and both of these are
            // filled out and expanded below.
            exports: ty.exports.clone(),
            explicit_resources: ty.explicit_resources.clone(),

            // Explicitly discard this field since the
            // defined resources are lifted into `self`
            defined_resources: Default::default(),
        };

        // Create brand new resources for all defined ones in the instance.
        let resources = (0..ty.defined_resources.len())
            .map(|_| types.alloc_resource_id())
            .collect::<IndexSet<_>>();

        // Build a map from the defined resources in `ty` to those in `new_ty`.
        //
        // As part of this same loop the new resources, which were previously
        // defined in `ty`, now become imported variables in `self`. Their
        // path for where they're imported is updated as well with
        // `self.next_import_index` as the import-to-be soon.
        let mut mapping = Remapping::default();
        let ty = &types[*id];
        for (old, new) in ty.defined_resources.iter().zip(&resources) {
            let prev = mapping.resources.insert(*old, new.resource());
            assert!(prev.is_none());

            let mut base = vec![self.imports.len()];
            base.extend(ty.explicit_resources[old].iter().copied());
            self.imported_resources.insert(new.resource(), base);
        }

        // Using the old-to-new resource mapping perform a substitution on
        // the `exports` and `explicit_resources` fields of `new_ty`
        for ty in new_ty.exports.values_mut() {
            types.remap_component_entity(ty, &mut mapping);
        }
        for (id, path) in mem::take(&mut new_ty.explicit_resources) {
            let id = *mapping.resources.get(&id).unwrap_or(&id);
            new_ty.explicit_resources.insert(id, path);
        }

        // Now that `new_ty` is complete finish its registration and then
        // update `id` on the way out.
        *id = types.push_ty(new_ty);
    }

    /// Prepares an instance type, pointed to `id`, for being exported as a
    /// concrete instance from `self`.
    ///
    /// This will internally perform any resource "freshening" as required and
    /// then additionally update metadata within `self` about resources being
    /// exported or defined.
    fn prepare_instance_export(&mut self, id: &mut ComponentInstanceTypeId, types: &mut TypeAlloc) {
        // Exports of an instance mean that the enclosing context
        // is inheriting the resources that the instance
        // encapsulates. This means that the instance type
        // recorded for this export will itself have no
        // defined resources.
        let ty = &types[*id];

        // Check to see if `defined_resources` is non-empty, and if so then
        // "freshen" all the resources and inherit them to our own defined
        // resources, updating `id` in the process.
        //
        // Note though that this specifically is not rewriting the resources of
        // exported instances. The `defined_resources` set on instance types is
        // a little subtle (see its documentation for more info), but the
        // general idea is that for a concrete instance it's always empty. Only
        // for instance type definitions does it ever have elements in it.
        //
        // That means that if this set is non-empty then what's happening is
        // that we're in a type context an exporting an instance of a previously
        // specified type. In this case all resources are required to be
        // "freshened" to ensure that multiple exports of the same type all
        // export different types of resources.
        //
        // And finally note that this operation empties out the
        // `defined_resources` set of the type that is registered for the
        // instance, as this export is modeled as producing a concrete instance.
        if !ty.defined_resources.is_empty() {
            let mut new_ty = ty.clone();
            let mut mapping = Remapping::default();
            for old in mem::take(&mut new_ty.defined_resources) {
                let new = types.alloc_resource_id();
                mapping.resources.insert(old, new.resource());
                self.defined_resources.insert(new.resource(), None);
            }
            for ty in new_ty.exports.values_mut() {
                types.remap_component_entity(ty, &mut mapping);
            }
            for (id, path) in mem::take(&mut new_ty.explicit_resources) {
                let id = mapping.resources.get(&id).copied().unwrap_or(id);
                new_ty.explicit_resources.insert(id, path);
            }
            *id = types.push_ty(new_ty);
        }

        // Any explicit resources in the instance are now additionally explicit
        // in this component since it's exported.
        //
        // The path to each explicit resources gets one element prepended which
        // is `self.next_export_index`, the index of the export about to be
        // generated.
        let ty = &types[*id];
        for (id, path) in ty.explicit_resources.iter() {
            let mut new_path = vec![self.exports.len()];
            new_path.extend(path);
            self.explicit_resources.insert(*id, new_path);
        }
    }

    pub fn add_export(
        &mut self,
        name: ComponentExportName<'_>,
        mut ty: ComponentEntityType,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
        check_limit: bool,
    ) -> Result<()> {
        if check_limit {
            check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?;
        }
        self.add_entity(
            &mut ty,
            Some((name.0, ExternKind::Export)),
            features,
            types,
            offset,
        )?;
        self.toplevel_exported_resources.validate_extern(
            name.0,
            ExternKind::Export,
            &ty,
            types,
            offset,
            &mut self.export_names,
            &mut self.exports,
            &mut self.type_info,
            features,
        )?;
        Ok(())
    }

    pub fn lift_function(
        &mut self,
        core_func_index: u32,
        type_index: u32,
        options: Vec<CanonicalOption>,
        types: &TypeList,
        offset: usize,
    ) -> Result<()> {
        let ty = self.function_type_at(type_index, types, offset)?;
        let core_ty = types[self.core_function_at(core_func_index, offset)?].unwrap_func();

        // Lifting a function is for an export, so match the expected canonical ABI
        // export signature
        let info = ty.lower(types, false);
        self.check_options(Some(core_ty), &info, &options, types, offset)?;

        if core_ty.params() != info.params.as_slice() {
            bail!(
                offset,
                "lowered parameter types `{:?}` do not match parameter types \
                 `{:?}` of core function {core_func_index}",
                info.params.as_slice(),
                core_ty.params(),
            );
        }

        if core_ty.results() != info.results.as_slice() {
            bail!(
                offset,
                "lowered result types `{:?}` do not match result types \
                 `{:?}` of core function {core_func_index}",
                info.results.as_slice(),
                core_ty.results()
            );
        }

        self.funcs
            .push(self.types[type_index as usize].unwrap_func());

        Ok(())
    }

    pub fn lower_function(
        &mut self,
        func_index: u32,
        options: Vec<CanonicalOption>,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<()> {
        let ty = &types[self.function_at(func_index, offset)?];

        // Lowering a function is for an import, so use a function type that matches
        // the expected canonical ABI import signature.
        let info = ty.lower(types, true);

        self.check_options(None, &info, &options, types, offset)?;

        let lowered_ty = SubType::func(info.into_func_type(), false);
        let id = types.intern_sub_type(lowered_ty, offset);
        self.core_funcs.push(id);

        Ok(())
    }

    pub fn resource_new(
        &mut self,
        resource: u32,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<()> {
        let rep = self.check_local_resource(resource, types, offset)?;
        let func_ty = FuncType::new([rep], [ValType::I32]);
        let core_ty = SubType::func(func_ty, false);
        let id = types.intern_sub_type(core_ty, offset);
        self.core_funcs.push(id);
        Ok(())
    }

    pub fn resource_drop(
        &mut self,
        resource: u32,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<()> {
        self.resource_at(resource, types, offset)?;
        let func_ty = FuncType::new([ValType::I32], []);
        let core_ty = SubType::func(func_ty, false);
        let id = types.intern_sub_type(core_ty, offset);
        self.core_funcs.push(id);
        Ok(())
    }

    pub fn resource_rep(
        &mut self,
        resource: u32,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<()> {
        let rep = self.check_local_resource(resource, types, offset)?;
        let func_ty = FuncType::new([ValType::I32], [rep]);
        let core_ty = SubType::func(func_ty, false);
        let id = types.intern_sub_type(core_ty, offset);
        self.core_funcs.push(id);
        Ok(())
    }

    fn check_local_resource(&self, idx: u32, types: &TypeList, offset: usize) -> Result<ValType> {
        let resource = self.resource_at(idx, types, offset)?;
        match self
            .defined_resources
            .get(&resource.resource())
            .and_then(|rep| *rep)
        {
            Some(ty) => Ok(ty),
            None => bail!(offset, "type {idx} is not a local resource"),
        }
    }

    fn resource_at<'a>(
        &self,
        idx: u32,
        _types: &'a TypeList,
        offset: usize,
    ) -> Result<AliasableResourceId> {
        if let ComponentAnyTypeId::Resource(id) = self.component_type_at(idx, offset)? {
            return Ok(id);
        }
        bail!(offset, "type index {} is not a resource type", idx)
    }

    pub fn thread_spawn(
        &mut self,
        func_ty_index: u32,
        types: &mut TypeAlloc,
        offset: usize,
        features: &WasmFeatures,
    ) -> Result<()> {
        if !features.shared_everything_threads() {
            bail!(
                offset,
                "`thread.spawn` requires the shared-everything-threads proposal"
            )
        }

        // Validate the type accepted by `thread.spawn`.
        let core_type_id = match self.core_type_at(func_ty_index, offset)? {
            ComponentCoreTypeId::Sub(c) => c,
            ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"),
        };
        let sub_ty = &types[core_type_id];
        if !sub_ty.composite_type.shared {
            bail!(offset, "spawn type must be shared");
        }
        match &sub_ty.composite_type.inner {
            CompositeInnerType::Func(func_ty) => {
                if func_ty.params() != [ValType::I32] {
                    bail!(
                        offset,
                        "spawn function must take a single `i32` argument (currently)"
                    );
                }
                if func_ty.results() != [] {
                    bail!(offset, "spawn function must not return any values");
                }
            }
            _ => bail!(offset, "spawn type must be a function"),
        }

        // Insert the core function.
        let packed_index = PackedIndex::from_id(core_type_id).ok_or_else(|| {
            format_err!(offset, "implementation limit: too many types in `TypeList`")
        })?;
        let start_func_ref = RefType::concrete(true, packed_index);
        let func_ty = FuncType::new([ValType::Ref(start_func_ref), ValType::I32], [ValType::I32]);
        let core_ty = SubType::func(func_ty, true);
        let id = types.intern_sub_type(core_ty, offset);
        self.core_funcs.push(id);

        Ok(())
    }

    pub fn thread_hw_concurrency(
        &mut self,
        types: &mut TypeAlloc,
        offset: usize,
        features: &WasmFeatures,
    ) -> Result<()> {
        if !features.shared_everything_threads() {
            bail!(
                offset,
                "`thread.hw_concurrency` requires the shared-everything-threads proposal"
            )
        }

        let func_ty = FuncType::new([], [ValType::I32]);
        let core_ty = SubType::func(func_ty, true);
        let id = types.intern_sub_type(core_ty, offset);
        self.core_funcs.push(id);

        Ok(())
    }

    pub fn add_component(&mut self, component: ComponentType, types: &mut TypeAlloc) -> Result<()> {
        let id = types.push_ty(component);
        self.components.push(id);
        Ok(())
    }

    pub fn add_instance(
        &mut self,
        instance: crate::ComponentInstance,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<()> {
        let instance = match instance {
            crate::ComponentInstance::Instantiate {
                component_index,
                args,
            } => self.instantiate_component(
                component_index,
                args.into_vec(),
                features,
                types,
                offset,
            )?,
            crate::ComponentInstance::FromExports(exports) => {
                self.instantiate_component_exports(exports.into_vec(), features, types, offset)?
            }
        };

        self.instances.push(instance);

        Ok(())
    }

    pub fn add_alias(
        components: &mut [Self],
        alias: crate::ComponentAlias,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<()> {
        match alias {
            crate::ComponentAlias::InstanceExport {
                instance_index,
                kind,
                name,
            } => components.last_mut().unwrap().alias_instance_export(
                instance_index,
                kind,
                name,
                features,
                types,
                offset,
            ),
            crate::ComponentAlias::CoreInstanceExport {
                instance_index,
                kind,
                name,
            } => components.last_mut().unwrap().alias_core_instance_export(
                instance_index,
                kind,
                name,
                types,
                offset,
            ),
            crate::ComponentAlias::Outer { kind, count, index } => match kind {
                ComponentOuterAliasKind::CoreModule => {
                    Self::alias_module(components, count, index, offset)
                }
                ComponentOuterAliasKind::CoreType => {
                    Self::alias_core_type(components, count, index, offset)
                }
                ComponentOuterAliasKind::Type => {
                    Self::alias_type(components, count, index, types, offset)
                }
                ComponentOuterAliasKind::Component => {
                    Self::alias_component(components, count, index, offset)
                }
            },
        }
    }

    pub fn add_start(
        &mut self,
        func_index: u32,
        args: &[u32],
        results: u32,
        features: &WasmFeatures,
        types: &mut TypeList,
        offset: usize,
    ) -> Result<()> {
        if !features.component_model_values() {
            bail!(
                offset,
                "support for component model `value`s is not enabled"
            );
        }
        if self.has_start {
            return Err(BinaryReaderError::new(
                "component cannot have more than one start function",
                offset,
            ));
        }

        let ft = &types[self.function_at(func_index, offset)?];

        if ft.params.len() != args.len() {
            bail!(
                offset,
                "component start function requires {} arguments but was given {}",
                ft.params.len(),
                args.len()
            );
        }

        if ft.results.len() as u32 != results {
            bail!(
                offset,
                "component start function has a result count of {results} \
                 but the function type has a result count of {type_results}",
                type_results = ft.results.len(),
            );
        }

        let cx = SubtypeCx::new(types, types);
        for (i, ((_, ty), arg)) in ft.params.iter().zip(args).enumerate() {
            // Ensure the value's type is a subtype of the parameter type
            cx.component_val_type(self.value_at(*arg, offset)?, ty, offset)
                .with_context(|| {
                    format!("value type mismatch for component start function argument {i}")
                })?;
        }

        for (_, ty) in ft.results.iter() {
            self.values.push((*ty, false));
        }

        self.has_start = true;

        Ok(())
    }

    fn check_options(
        &self,
        core_ty: Option<&FuncType>,
        info: &LoweringInfo,
        options: &[CanonicalOption],
        types: &TypeList,
        offset: usize,
    ) -> Result<()> {
        fn display(option: CanonicalOption) -> &'static str {
            match option {
                CanonicalOption::UTF8 => "utf8",
                CanonicalOption::UTF16 => "utf16",
                CanonicalOption::CompactUTF16 => "latin1-utf16",
                CanonicalOption::Memory(_) => "memory",
                CanonicalOption::Realloc(_) => "realloc",
                CanonicalOption::PostReturn(_) => "post-return",
            }
        }

        let mut encoding = None;
        let mut memory = None;
        let mut realloc = None;
        let mut post_return = None;

        for option in options {
            match option {
                CanonicalOption::UTF8 | CanonicalOption::UTF16 | CanonicalOption::CompactUTF16 => {
                    match encoding {
                        Some(existing) => {
                            bail!(
                                offset,
                                "canonical encoding option `{}` conflicts with option `{}`",
                                display(existing),
                                display(*option),
                            )
                        }
                        None => encoding = Some(*option),
                    }
                }
                CanonicalOption::Memory(idx) => {
                    memory = match memory {
                        None => {
                            self.memory_at(*idx, offset)?;
                            Some(*idx)
                        }
                        Some(_) => {
                            return Err(BinaryReaderError::new(
                                "canonical option `memory` is specified more than once",
                                offset,
                            ))
                        }
                    }
                }
                CanonicalOption::Realloc(idx) => {
                    realloc = match realloc {
                        None => {
                            let ty = types[self.core_function_at(*idx, offset)?].unwrap_func();
                            if ty.params()
                                != [ValType::I32, ValType::I32, ValType::I32, ValType::I32]
                                || ty.results() != [ValType::I32]
                            {
                                return Err(BinaryReaderError::new(
                                    "canonical option `realloc` uses a core function with an incorrect signature",
                                    offset,
                                ));
                            }
                            Some(*idx)
                        }
                        Some(_) => {
                            return Err(BinaryReaderError::new(
                                "canonical option `realloc` is specified more than once",
                                offset,
                            ))
                        }
                    }
                }
                CanonicalOption::PostReturn(idx) => {
                    post_return = match post_return {
                        None => {
                            let core_ty = core_ty.ok_or_else(|| {
                                BinaryReaderError::new(
                                    "canonical option `post-return` cannot be specified for lowerings",
                                    offset,
                                )
                            })?;

                            let ty = types[self.core_function_at(*idx, offset)?].unwrap_func();

                            if ty.params() != core_ty.results() || !ty.results().is_empty() {
                                return Err(BinaryReaderError::new(
                                    "canonical option `post-return` uses a core function with an incorrect signature",
                                    offset,
                                ));
                            }
                            Some(*idx)
                        }
                        Some(_) => {
                            return Err(BinaryReaderError::new(
                                "canonical option `post-return` is specified more than once",
                                offset,
                            ))
                        }
                    }
                }
            }
        }

        if info.requires_memory && memory.is_none() {
            return Err(BinaryReaderError::new(
                "canonical option `memory` is required",
                offset,
            ));
        }

        if info.requires_realloc && realloc.is_none() {
            return Err(BinaryReaderError::new(
                "canonical option `realloc` is required",
                offset,
            ));
        }

        Ok(())
    }

    fn check_type_ref(
        &mut self,
        ty: &ComponentTypeRef,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<ComponentEntityType> {
        Ok(match ty {
            ComponentTypeRef::Module(index) => {
                let id = self.core_type_at(*index, offset)?;
                match id {
                    ComponentCoreTypeId::Sub(_) => {
                        bail!(offset, "core type index {index} is not a module type")
                    }
                    ComponentCoreTypeId::Module(id) => ComponentEntityType::Module(id),
                }
            }
            ComponentTypeRef::Func(index) => {
                let id = self.component_type_at(*index, offset)?;
                match id {
                    ComponentAnyTypeId::Func(id) => ComponentEntityType::Func(id),
                    _ => bail!(offset, "type index {index} is not a function type"),
                }
            }
            ComponentTypeRef::Value(ty) => {
                self.check_value_support(features, offset)?;
                let ty = match ty {
                    crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty),
                    crate::ComponentValType::Type(index) => {
                        ComponentValType::Type(self.defined_type_at(*index, offset)?)
                    }
                };
                ComponentEntityType::Value(ty)
            }
            ComponentTypeRef::Type(TypeBounds::Eq(index)) => {
                let referenced = self.component_type_at(*index, offset)?;
                let created = types.with_unique(referenced);
                ComponentEntityType::Type {
                    referenced,
                    created,
                }
            }
            ComponentTypeRef::Type(TypeBounds::SubResource) => {
                let id = types.alloc_resource_id();
                ComponentEntityType::Type {
                    referenced: id.into(),
                    created: id.into(),
                }
            }
            ComponentTypeRef::Instance(index) => {
                let id = self.component_type_at(*index, offset)?;
                match id {
                    ComponentAnyTypeId::Instance(id) => ComponentEntityType::Instance(id),
                    _ => bail!(offset, "type index {index} is not an instance type"),
                }
            }
            ComponentTypeRef::Component(index) => {
                let id = self.component_type_at(*index, offset)?;
                match id {
                    ComponentAnyTypeId::Component(id) => ComponentEntityType::Component(id),
                    _ => bail!(offset, "type index {index} is not a component type"),
                }
            }
        })
    }

    pub fn export_to_entity_type(
        &mut self,
        export: &crate::ComponentExport,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<ComponentEntityType> {
        let actual = match export.kind {
            ComponentExternalKind::Module => {
                ComponentEntityType::Module(self.module_at(export.index, offset)?)
            }
            ComponentExternalKind::Func => {
                ComponentEntityType::Func(self.function_at(export.index, offset)?)
            }
            ComponentExternalKind::Value => {
                self.check_value_support(features, offset)?;
                ComponentEntityType::Value(*self.value_at(export.index, offset)?)
            }
            ComponentExternalKind::Type => {
                let referenced = self.component_type_at(export.index, offset)?;
                let created = types.with_unique(referenced);
                ComponentEntityType::Type {
                    referenced,
                    created,
                }
            }
            ComponentExternalKind::Instance => {
                ComponentEntityType::Instance(self.instance_at(export.index, offset)?)
            }
            ComponentExternalKind::Component => {
                ComponentEntityType::Component(self.component_at(export.index, offset)?)
            }
        };

        let ascribed = match &export.ty {
            Some(ty) => self.check_type_ref(ty, features, types, offset)?,
            None => return Ok(actual),
        };

        SubtypeCx::new(types, types)
            .component_entity_type(&actual, &ascribed, offset)
            .with_context(|| "ascribed type of export is not compatible with item's type")?;

        Ok(ascribed)
    }

    fn create_module_type(
        components: &[Self],
        decls: Vec<crate::ModuleTypeDeclaration>,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<ModuleType> {
        let mut state = Module::default();

        for decl in decls {
            match decl {
                crate::ModuleTypeDeclaration::Type(rec) => {
                    state.add_types(rec, features, types, offset, true)?;
                }
                crate::ModuleTypeDeclaration::Export { name, mut ty } => {
                    let ty = state.check_type_ref(&mut ty, features, types, offset)?;
                    state.add_export(name, ty, features, offset, true, types)?;
                }
                crate::ModuleTypeDeclaration::OuterAlias { kind, count, index } => {
                    match kind {
                        crate::OuterAliasKind::Type => {
                            let ty = if count == 0 {
                                // Local alias, check the local module state
                                ComponentCoreTypeId::Sub(state.type_id_at(index, offset)?)
                            } else {
                                // Otherwise, check the enclosing component state
                                let component =
                                    Self::check_alias_count(components, count - 1, offset)?;
                                component.core_type_at(index, offset)?
                            };

                            check_max(state.types.len(), 1, MAX_WASM_TYPES, "types", offset)?;

                            match ty {
                                ComponentCoreTypeId::Sub(ty) => state.types.push(ty),
                                // TODO https://github.com/WebAssembly/component-model/issues/265
                                ComponentCoreTypeId::Module(_) => bail!(
                                    offset,
                                    "not implemented: aliasing core module types into a core \
                                     module's types index space"
                                ),
                            }
                        }
                    }
                }
                crate::ModuleTypeDeclaration::Import(import) => {
                    state.add_import(import, features, types, offset)?;
                }
            }
        }

        let imports = state.imports_for_module_type(offset)?;

        Ok(ModuleType {
            info: TypeInfo::core(state.type_size),
            imports,
            exports: state.exports,
        })
    }

    fn create_component_type(
        components: &mut Vec<Self>,
        decls: Vec<crate::ComponentTypeDeclaration>,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<ComponentType> {
        components.push(ComponentState::new(ComponentKind::ComponentType));

        for decl in decls {
            match decl {
                crate::ComponentTypeDeclaration::CoreType(ty) => {
                    Self::add_core_type(components, ty, features, types, offset, true)?;
                }
                crate::ComponentTypeDeclaration::Type(ty) => {
                    Self::add_type(components, ty, features, types, offset, true)?;
                }
                crate::ComponentTypeDeclaration::Export { name, ty } => {
                    let current = components.last_mut().unwrap();
                    let ty = current.check_type_ref(&ty, features, types, offset)?;
                    current.add_export(name, ty, features, types, offset, true)?;
                }
                crate::ComponentTypeDeclaration::Import(import) => {
                    components
                        .last_mut()
                        .unwrap()
                        .add_import(import, features, types, offset)?;
                }
                crate::ComponentTypeDeclaration::Alias(alias) => {
                    Self::add_alias(components, alias, features, types, offset)?;
                }
            };
        }

        components.pop().unwrap().finish(types, offset)
    }

    fn create_instance_type(
        components: &mut Vec<Self>,
        decls: Vec<crate::InstanceTypeDeclaration>,
        features: &WasmFeatures,
        types: &mut TypeAlloc,
        offset: usize,
    ) -> Result<ComponentInstanceType> {
        components.push(ComponentState::new(ComponentKind::InstanceType));

        for decl in decls {
            match decl {
                crate::InstanceTypeDeclaration::CoreType(ty) => {
                    Self::add_core_type(components, ty, features, types, offset, true)?;
                }
                crate::InstanceTypeDeclaration::Type(ty) => {
                    Self::add_type(components, ty, features, types, offset, true)?;
                }
                crate::InstanceTypeDeclaration::Export { name, ty } => {
                    let current = components.last_mut().unwrap();
                    let ty = current.check_type_ref(&ty, features, types, offset)?;
                    current.add_export(name, ty, features, types, offset, true)?;
                }
                crate::InstanceTypeDeclaration::Alias(alias) => {
                    Self::add_alias(components, alias, features, types, offset)?;
                }
            };
        }

        let mut state = components.pop().unwrap();

        assert!(state.imported_resources.is_empty());

        Ok(ComponentInstanceType {
            info: state.type_info,

            // The defined resources for this instance type are those listed on
            // the component state. The path to each defined resource is
            // guaranteed to live within the `explicit_resources` map since,
            // when in the type context, the introduction of any defined
            // resource must have been done with `(export "x" (type (sub
            // resource)))` which, in a sense, "fuses" the introduction of the
            // variable with the export. This means that all defined resources,
            // if any, should be guaranteed to have an `explicit_resources` path
            // listed.
            defined_resources: mem::take(&mut state.defined_resources)
                .into_iter()
                .map(|(id, rep)| {
                    assert!(rep.is_none());
                    id
                })
                .collect(),

            // The map of what resources are explicitly exported and where
            // they're exported is plumbed through as-is.
--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.63 Sekunden  ]