use crate::*;
use anyhow::{anyhow, bail};
use indexmap::IndexSet;
use std::mem;
use std::{collections::HashMap, io::Read};
use wasmparser::Chunk;
use wasmparser::{
    component_types::{
        ComponentAnyTypeId, ComponentDefinedType, ComponentEntityType, ComponentFuncType,
        ComponentInstanceType, ComponentType, ComponentValType,
    },
    names::{ComponentName, ComponentNameKind},
    types,
    types::Types,
    ComponentExternalKind, Parser, Payload, PrimitiveValType, ValidPayload, Validator,
};

/// Represents information about a decoded WebAssembly component.
struct ComponentInfo {
    /// Wasmparser-defined type information learned after a component is fully
    /// validated.
    types: types::Types,
    /// List of all imports and exports from this component.
    externs: Vec<(String, Extern)>,
    /// Decoded package metadata
    package_metadata: Option<PackageMetadata>,
}

struct DecodingExport {
    name: String,
    kind: ComponentExternalKind,
    index: u32,
}

enum Extern {
    Import(String),
    Export(DecodingExport),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum WitEncodingVersion {
    V1,
    V2,
}

impl ComponentInfo {
    /// Creates a new component info by parsing the given WebAssembly component bytes.

    fn from_reader(mut reader: impl Read) -> Result<Self> {
        let mut validator = Validator::new();
        let mut externs = Vec::new();
        let mut depth = 1;
        let mut types = None;
        let mut _package_metadata = None;
        let mut cur = Parser::new(0);
        let mut eof = false;
        let mut stack = Vec::new();
        let mut buffer = Vec::new();

        loop {
            let chunk = cur.parse(&buffer, eof)?;
            let (payload, consumed) = match chunk {
                Chunk::NeedMoreData(hint) => {
                    assert!(!eof); // otherwise an error would be returned

                    // Use the hint to preallocate more space, then read
                    // some more data into our buffer.
                    //
                    // Note that the buffer management here is not ideal,
                    // but it's compact enough to fit in an example!
                    let len = buffer.len();
                    buffer.extend((0..hint).map(|_| 0u8));
                    let n = reader.read(&mut buffer[len..])?;
                    buffer.truncate(len + n);
                    eof = n == 0;
                    continue;
                }

                Chunk::Parsed { consumed, payload } => (payload, consumed),
            };
            match validator.payload(&payload)? {
                ValidPayload::Ok => {}
                ValidPayload::Parser(_) => depth += 1,
                ValidPayload::End(t) => {
                    depth -= 1;
                    if depth == 0 {
                        types = Some(t);
                    }
                }
                ValidPayload::Func(..) => {}
            }

            match payload {
                Payload::ComponentImportSection(s) if depth == 1 => {
                    for import in s {
                        let import = import?;
                        externs.push((
                            import.name.0.to_string(),
                            Extern::Import(import.name.0.to_string()),
                        ));
                    }
                }
                Payload::ComponentExportSection(s) if depth == 1 => {
                    for export in s {
                        let export = export?;
                        externs.push((
                            export.name.0.to_string(),
                            Extern::Export(DecodingExport {
                                name: export.name.0.to_string(),
                                kind: export.kind,
                                index: export.index,
                            }),
                        ));
                    }
                }
                #[cfg(feature = "serde")]
                Payload::CustomSection(s) if s.name() == PackageMetadata::SECTION_NAME => {
                    if _package_metadata.is_some() {
                        bail!("multiple {:?} sections", PackageMetadata::SECTION_NAME);
                    }
                    _package_metadata = Some(PackageMetadata::decode(s.data())?);
                }
                Payload::ModuleSection { parser, .. }
                | Payload::ComponentSection { parser, .. } => {
                    stack.push(cur.clone());
                    cur = parser.clone();
                }
                Payload::End(_) => {
                    if let Some(parent_parser) = stack.pop() {
                        cur = parent_parser.clone();
                    } else {
                        break;
                    }
                }
                _ => {}
            }

            // once we're done processing the payload we can forget the
            // original.
            buffer.drain(..consumed);
        }

        Ok(Self {
            types: types.unwrap(),
            externs,
            package_metadata: _package_metadata,
        })
    }

    fn is_wit_package(&self) -> Option<WitEncodingVersion> {
        // all wit package exports must be component types, and there must be at
        // least one
        if self.externs.is_empty() {
            return None;
        }

        if !self.externs.iter().all(|(_, item)| {
            let export = match item {
                Extern::Export(e) => e,
                _ => return false,
            };
            match export.kind {
                ComponentExternalKind::Type => matches!(
                    self.types.as_ref().component_any_type_at(export.index),
                    ComponentAnyTypeId::Component(_)
                ),
                _ => false,
            }
        }) {
            return None;
        }

        // The distinction between v1 and v2 encoding formats is the structure of the export
        // strings for each component. The v1 format uses "<namespace>:<package>/wit" as the name
        // for the top-level exports, while the v2 format uses the unqualified name of the encoded
        // entity.
        match ComponentName::new(&self.externs[0].0, 0).ok()?.kind() {
            ComponentNameKind::Interface(name) if name.interface().as_str() == "wit" => {
                Some(WitEncodingVersion::V1)
            }
            ComponentNameKind::Label(_) => Some(WitEncodingVersion::V2),
            _ => None,
        }
    }

    fn decode_wit_v1_package(&self) -> Result<(Resolve, PackageId)> {
        let mut decoder = WitPackageDecoder::new(&self.types);

        let mut pkg = None;
        for (name, item) in self.externs.iter() {
            let export = match item {
                Extern::Export(e) => e,
                _ => unreachable!(),
            };
            let id = self.types.as_ref().component_type_at(export.index);
            let ty = &self.types[id];
            if pkg.is_some() {
                bail!("more than one top-level exported component type found");
            }
            let name = ComponentName::new(name, 0).unwrap();
            pkg = Some(
                decoder
                    .decode_v1_package(&name, ty)
                    .with_context(|| format!("failed to decode document `{name}`"))?,
            );
        }

        let pkg = pkg.ok_or_else(|| anyhow!("no exported component type found"))?;
        let (mut resolve, package) = decoder.finish(pkg);
        if let Some(package_metadata) = &self.package_metadata {
            package_metadata.inject(&mut resolve, package)?;
        }
        Ok((resolve, package))
    }

    fn decode_wit_v2_package(&self) -> Result<(Resolve, PackageId)> {
        let mut decoder = WitPackageDecoder::new(&self.types);

        let mut pkg_name = None;

        let mut interfaces = IndexMap::new();
        let mut worlds = IndexMap::new();
        let mut fields = PackageFields {
            interfaces: &mut interfaces,
            worlds: &mut worlds,
        };

        for (_, item) in self.externs.iter() {
            let export = match item {
                Extern::Export(e) => e,
                _ => unreachable!(),
            };

            let index = export.index;
            let id = self.types.as_ref().component_type_at(index);
            let component = &self.types[id];

            // The single export of this component will determine if it's a world or an interface:
            // worlds export a component, while interfaces export an instance.
            if component.exports.len() != 1 {
                bail!(
                    "Expected a single export, but found {} instead",
                    component.exports.len()
                );
            }

            let name = component.exports.keys().nth(0).unwrap();

            let name = match component.exports[name] {
                ComponentEntityType::Component(ty) => {
                    let package_name =
                        decoder.decode_world(name.as_str(), &self.types[ty], &mut fields)?;
                    package_name
                }
                ComponentEntityType::Instance(ty) => {
                    let package_name = decoder.decode_interface(
                        name.as_str(),
                        &component.imports,
                        &self.types[ty],
                        &mut fields,
                    )?;
                    package_name
                }
                _ => unreachable!(),
            };

            if let Some(pkg_name) = pkg_name.as_ref() {
                // TODO: when we have fully switched to the v2 format, we should switch to parsing
                // multiple wit documents instead of bailing.
                if pkg_name != &name {
                    bail!("item defined with mismatched package name")
                }
            } else {
                pkg_name.replace(name);
            }
        }

        let pkg = if let Some(name) = pkg_name {
            Package {
                name,
                docs: Docs::default(),
                interfaces,
                worlds,
            }
        } else {
            bail!("no exported component type found");
        };

        let (mut resolve, package) = decoder.finish(pkg);
        if let Some(package_metadata) = &self.package_metadata {
            package_metadata.inject(&mut resolve, package)?;
        }
        Ok((resolve, package))
    }

    fn decode_component(&self) -> Result<(Resolve, WorldId)> {
        assert!(self.is_wit_package().is_none());
        let mut decoder = WitPackageDecoder::new(&self.types);
        // Note that this name is arbitrarily chosen. We may one day perhaps
        // want to encode this in the component binary format itself, but for
        // now it shouldn't be an issue to have a defaulted name here.
        let world_name = "root";
        let world = decoder.resolve.worlds.alloc(World {
            name: world_name.to_string(),
            docs: Default::default(),
            imports: Default::default(),
            exports: Default::default(),
            package: None,
            includes: Default::default(),
            include_names: Default::default(),
            stability: Default::default(),
        });
        let mut package = Package {
            // Similar to `world_name` above this is arbitrarily chosen as it's
            // not otherwise encoded in a binary component. This theoretically
            // shouldn't cause issues, however.
            name: PackageName {
                namespace: "root".to_string(),
                version: None,
                name: "component".to_string(),
            },
            docs: Default::default(),
            worlds: [(world_name.to_string(), world)].into_iter().collect(),
            interfaces: Default::default(),
        };

        let mut fields = PackageFields {
            worlds: &mut package.worlds,
            interfaces: &mut package.interfaces,
        };

        for (_name, item) in self.externs.iter() {
            match item {
                Extern::Import(import) => {
                    decoder.decode_component_import(import, world, &mut fields)?
                }
                Extern::Export(export) => {
                    decoder.decode_component_export(export, world, &mut fields)?
                }
            }
        }

        let (resolve, _) = decoder.finish(package);
        Ok((resolve, world))
    }
}

/// Result of the [`decode`] function.
pub enum DecodedWasm {
    /// The input to [`decode`] was one or more binary-encoded WIT package(s).
    ///
    /// The full resolve graph is here plus the identifier of the packages that
    /// were encoded. Note that other packages may be within the resolve if any
    /// of the main packages refer to other, foreign packages.
    WitPackage(Resolve, PackageId),

    /// The input to [`decode`] was a component and its interface is specified
    /// by the world here.
    Component(Resolve, WorldId),
}

impl DecodedWasm {
    /// Returns the [`Resolve`] for WIT types contained.
    pub fn resolve(&self) -> &Resolve {
        match self {
            DecodedWasm::WitPackage(resolve, _) => resolve,
            DecodedWasm::Component(resolve, _) => resolve,
        }
    }

    /// Returns the main packages of what was decoded.
    pub fn package(&self) -> PackageId {
        match self {
            DecodedWasm::WitPackage(_, id) => *id,
            DecodedWasm::Component(resolve, world) => resolve.worlds[*world].package.unwrap(),
        }
    }
}

/// Decode for incremental reading
pub fn decode_reader(reader: impl Read) -> Result<DecodedWasm> {
    let info = ComponentInfo::from_reader(reader)?;

    if let Some(version) = info.is_wit_package() {
        match version {
            WitEncodingVersion::V1 => {
                log::debug!("decoding a v1 WIT package encoded as wasm");
                let (resolve, pkg) = info.decode_wit_v1_package()?;
                Ok(DecodedWasm::WitPackage(resolve, pkg))
            }
            WitEncodingVersion::V2 => {
                log::debug!("decoding a v2 WIT package encoded as wasm");
                let (resolve, pkg) = info.decode_wit_v2_package()?;
                Ok(DecodedWasm::WitPackage(resolve, pkg))
            }
        }
    } else {
        log::debug!("inferring the WIT of a concrete component");
        let (resolve, world) = info.decode_component()?;
        Ok(DecodedWasm::Component(resolve, world))
    }
}
/// Decodes an in-memory WebAssembly binary into a WIT [`Resolve`] and
/// associated metadata.
///
/// The WebAssembly binary provided here can either be a
/// WIT-package-encoded-as-binary or an actual component itself. A [`Resolve`]
/// is always created and the return value indicates which was detected.
pub fn decode(bytes: &[u8]) -> Result<DecodedWasm> {
    decode_reader(bytes)
}

/// Decodes the single component type `world` specified as a WIT world.
///
/// The `world` should be an exported component type. The `world` must have been
/// previously created via `encode_world` meaning that it is a component that
/// itself imports nothing and exports a single component, and the single
/// component export represents the world. The name of the export is also the
/// name of the package/world/etc.
pub fn decode_world(wasm: &[u8]) -> Result<(Resolve, WorldId)> {
    let mut validator = Validator::new();
    let mut exports = Vec::new();
    let mut depth = 1;
    let mut types = None;

    for payload in Parser::new(0).parse_all(wasm) {
        let payload = payload?;

        match validator.payload(&payload)? {
            ValidPayload::Ok => {}
            ValidPayload::Parser(_) => depth += 1,
            ValidPayload::End(t) => {
                depth -= 1;
                if depth == 0 {
                    types = Some(t);
                }
            }
            ValidPayload::Func(..) => {}
        }

        match payload {
            Payload::ComponentExportSection(s) if depth == 1 => {
                for export in s {
                    exports.push(export?);
                }
            }
            _ => {}
        }
    }

    if exports.len() != 1 {
        bail!("expected one export in component");
    }
    if exports[0].kind != ComponentExternalKind::Type {
        bail!("expected an export of a type");
    }
    if exports[0].ty.is_some() {
        bail!("expected an un-ascribed exported type");
    }
    let types = types.as_ref().unwrap();
    let world = match types.as_ref().component_any_type_at(exports[0].index) {
        ComponentAnyTypeId::Component(c) => c,
        _ => bail!("expected an exported component type"),
    };

    let mut decoder = WitPackageDecoder::new(types);
    let mut interfaces = IndexMap::new();
    let mut worlds = IndexMap::new();
    let ty = &types[world];
    assert_eq!(ty.imports.len(), 0);
    assert_eq!(ty.exports.len(), 1);
    let name = ty.exports.keys().nth(0).unwrap();
    let ty = match ty.exports[0] {
        ComponentEntityType::Component(ty) => ty,
        _ => unreachable!(),
    };
    let name = decoder.decode_world(
        name,
        &types[ty],
        &mut PackageFields {
            interfaces: &mut interfaces,
            worlds: &mut worlds,
        },
    )?;
    let (resolve, pkg) = decoder.finish(Package {
        name,
        interfaces,
        worlds,
        docs: Default::default(),
    });
    // The package decoded here should only have a single world so extract that
    // here to return.
    let world = *resolve.packages[pkg].worlds.iter().next().unwrap().1;
    Ok((resolve, world))
}

struct PackageFields<'a> {
    interfaces: &'a mut IndexMap<String, InterfaceId>,
    worlds: &'a mut IndexMap<String, WorldId>,
}

struct WitPackageDecoder<'a> {
    resolve: Resolve,
    types: &'a Types,
    foreign_packages: IndexMap<String, Package>,
    iface_to_package_index: HashMap<InterfaceId, usize>,
    named_interfaces: HashMap<String, InterfaceId>,

    /// A map which tracks named resources to what their corresponding `TypeId`
    /// is. This first layer of key in this map is the owner scope of a
    /// resource, more-or-less the `world` or `interface` that it's defined
    /// within. The second layer of this map is keyed by name of the resource
    /// and points to the actual ID of the resource.
    ///
    /// This map is populated in `register_type_export`.
    resources: HashMap<TypeOwner, HashMap<String, TypeId>>,

    /// A map from a type id to what it's been translated to.
    type_map: HashMap<ComponentAnyTypeId, TypeId>,
}

impl WitPackageDecoder<'_> {
    fn new<'a>(types: &'a Types) -> WitPackageDecoder<'a> {
        WitPackageDecoder {
            resolve: Resolve::default(),
            types,
            type_map: HashMap::new(),
            foreign_packages: Default::default(),
            iface_to_package_index: Default::default(),
            named_interfaces: Default::default(),
            resources: Default::default(),
        }
    }

    fn decode_v1_package(&mut self, name: &ComponentName, ty: &ComponentType) -> Result<Package> {
        // Process all imports for this package first, where imports are
        // importing from remote packages.
        for (name, ty) in ty.imports.iter() {
            let ty = match ty {
                ComponentEntityType::Instance(idx) => &self.types[*idx],
                _ => bail!("import `{name}` is not an instance"),
            };
            self.register_import(name, ty)
                .with_context(|| format!("failed to process import `{name}`"))?;
        }

        let mut package = Package {
            // The name encoded for packages must be of the form `foo:bar/wit`
            // where "wit" is just a placeholder for now. The package name in
            // this case would be `foo:bar`.
            name: match name.kind() {
                ComponentNameKind::Interface(name) if name.interface().as_str() == "wit" => {
                    name.to_package_name()
                }
                _ => bail!("package name is not a valid id: {name}"),
            },
            docs: Default::default(),
            interfaces: Default::default(),
            worlds: Default::default(),
        };

        let mut fields = PackageFields {
            interfaces: &mut package.interfaces,
            worlds: &mut package.worlds,
        };

        for (name, ty) in ty.exports.iter() {
            match ty {
                ComponentEntityType::Instance(idx) => {
                    let ty = &self.types[*idx];
                    self.register_interface(name.as_str(), ty, &mut fields)
                        .with_context(|| format!("failed to process export `{name}`"))?;
                }
                ComponentEntityType::Component(idx) => {
                    let ty = &self.types[*idx];
                    self.register_world(name.as_str(), ty, &mut fields)
                        .with_context(|| format!("failed to process export `{name}`"))?;
                }
                _ => bail!("component export `{name}` is not an instance or component"),
            }
        }
        Ok(package)
    }

    fn decode_interface<'a>(
        &mut self,
        name: &str,
        imports: &wasmparser::collections::IndexMap<String, ComponentEntityType>,
        ty: &ComponentInstanceType,
        fields: &mut PackageFields<'a>,
    ) -> Result<PackageName> {
        let component_name = self
            .parse_component_name(name)
            .context("expected world name to have an ID form")?;

        let package = match component_name.kind() {
            ComponentNameKind::Interface(name) => name.to_package_name(),
            _ => bail!("expected world name to be fully qualified"),
        };

        for (name, ty) in imports.iter() {
            let ty = match ty {
                ComponentEntityType::Instance(idx) => &self.types[*idx],
                _ => bail!("import `{name}` is not an instance"),
            };
            self.register_import(name, ty)
                .with_context(|| format!("failed to process import `{name}`"))?;
        }

        let _ = self.register_interface(name, ty, fields)?;

        Ok(package)
    }

    fn decode_world<'a>(
        &mut self,
        name: &str,
        ty: &ComponentType,
        fields: &mut PackageFields<'a>,
    ) -> Result<PackageName> {
        let kebab_name = self
            .parse_component_name(name)
            .context("expected world name to have an ID form")?;

        let package = match kebab_name.kind() {
            ComponentNameKind::Interface(name) => name.to_package_name(),
            _ => bail!("expected world name to be fully qualified"),
        };

        let _ = self.register_world(name, ty, fields)?;

        Ok(package)
    }

    fn decode_component_import<'a>(
        &mut self,
        name: &str,
        world: WorldId,
        package: &mut PackageFields<'a>,
    ) -> Result<()> {
        log::debug!("decoding component import `{name}`");
        let ty = self
            .types
            .as_ref()
            .component_entity_type_of_import(name)
            .unwrap();
        let owner = TypeOwner::World(world);
        let (name, item) = match ty {
            ComponentEntityType::Instance(i) => {
                let ty = &self.types[i];
                let (name, id) = if name.contains('/') {
                    let id = self.register_import(name, ty)?;
                    (WorldKey::Interface(id), id)
                } else {
                    self.register_interface(name, ty, package)
                        .with_context(|| format!("failed to decode WIT from import `{name}`"))?
                };
                (
                    name,
                    WorldItem::Interface {
                        id,
                        stability: Default::default(),
                    },
                )
            }
            ComponentEntityType::Func(i) => {
                let ty = &self.types[i];
                let func = self
                    .convert_function(name, ty, owner)
                    .with_context(|| format!("failed to decode function from import `{name}`"))?;
                (WorldKey::Name(name.to_string()), WorldItem::Function(func))
            }
            ComponentEntityType::Type {
                referenced,
                created,
            } => {
                let id = self
                    .register_type_export(name, owner, referenced, created)
                    .with_context(|| format!("failed to decode type from export `{name}`"))?;
                (WorldKey::Name(name.to_string()), WorldItem::Type(id))
            }
            // All other imports do not form part of the component's world
            _ => return Ok(()),
        };
        self.resolve.worlds[world].imports.insert(name, item);
        Ok(())
    }

    fn decode_component_export<'a>(
        &mut self,
        export: &DecodingExport,
        world: WorldId,
        package: &mut PackageFields<'a>,
    ) -> Result<()> {
        let name = &export.name;
        log::debug!("decoding component export `{name}`");
        let types = self.types.as_ref();
        let ty = types.component_entity_type_of_export(name).unwrap();
        let (name, item) = match ty {
            ComponentEntityType::Func(i) => {
                let ty = &types[i];
                let func = self
                    .convert_function(name, ty, TypeOwner::World(world))
                    .with_context(|| format!("failed to decode function from export `{name}`"))?;

                (WorldKey::Name(name.to_string()), WorldItem::Function(func))
            }
            ComponentEntityType::Instance(i) => {
                let ty = &types[i];
                let (name, id) = if name.contains('/') {
                    let id = self.register_import(name, ty)?;
                    (WorldKey::Interface(id), id)
                } else {
                    self.register_interface(name, ty, package)
                        .with_context(|| format!("failed to decode WIT from export `{name}`"))?
                };
                (
                    name,
                    WorldItem::Interface {
                        id,
                        stability: Default::default(),
                    },
                )
            }
            _ => {
                bail!("component export `{name}` was not a function or instance")
            }
        };
        self.resolve.worlds[world].exports.insert(name, item);
        Ok(())
    }

    /// Registers that the `name` provided is either imported interface from a
    /// foreign package or  referencing a previously defined interface in this
    /// package.
    ///
    /// This function will internally ensure that `name` is well-structured and
    /// will fill in any information as necessary. For example with a foreign
    /// dependency the foreign package structure, types, etc, all need to be
    /// created. For a local dependency it's instead ensured that all the types
    /// line up with the previous definitions.
    fn register_import(&mut self, name: &str, ty: &ComponentInstanceType) -> Result<InterfaceId> {
        let (is_local, interface) = match self.named_interfaces.get(name) {
            Some(id) => (true, *id),
            None => (false, self.extract_dep_interface(name)?),
        };
        let owner = TypeOwner::Interface(interface);
        for (name, ty) in ty.exports.iter() {
            log::debug!("decoding import instance export `{name}`");
            match *ty {
                ComponentEntityType::Type {
                    referenced,
                    created,
                } => {
                    match self.resolve.interfaces[interface]
                        .types
                        .get(name.as_str())
                        .copied()
                    {
                        // If this name is already defined as a type in the
                        // specified interface then that's ok. For package-local
                        // interfaces that's expected since the interface was
                        // fully defined. For remote interfaces it means we're
                        // using something that was already used elsewhere. In
                        // both cases continue along.
                        //
                        // Notably for the remotely defined case this will also
                        // walk over the structure of the type and register
                        // internal wasmparser ids with wit-parser ids. This is
                        // necessary to ensure that anonymous types like
                        // `list<u8>` defined in original definitions are
                        // unified with anonymous types when duplicated inside
                        // of worlds. Overall this prevents, for example, extra
                        // `list<u8>` types from popping up when decoding. This
                        // is not strictly necessary but assists with
                        // roundtripping assertions during fuzzing.
                        Some(id) => {
                            log::debug!("type already exist");
                            match referenced {
                                ComponentAnyTypeId::Defined(ty) => {
                                    self.register_defined(id, &self.types[ty])?;
                                }
                                ComponentAnyTypeId::Resource(_) => {}
                                _ => unreachable!(),
                            }
                            let prev = self.type_map.insert(created, id);
                            assert!(prev.is_none());
                        }

                        // If the name is not defined, however, then there's two
                        // possibilities:
                        //
                        // * For package-local interfaces this is an error
                        //   because the package-local interface defined
                        //   everything already and this is referencing
                        //   something that isn't defined.
                        //
                        // * For remote interfaces they're never fully declared
                        //   so it's lazily filled in here. This means that the
                        //   view of remote interfaces ends up being the minimal
                        //   slice needed for this resolve, which is what's
                        //   intended.
                        None => {
                            if is_local {
                                bail!("instance type export `{name}` not defined in interface");
                            }
                            let id = self.register_type_export(
                                name.as_str(),
                                owner,
                                referenced,
                                created,
                            )?;
                            let prev = self.resolve.interfaces[interface]
                                .types
                                .insert(name.to_string(), id);
                            assert!(prev.is_none());
                        }
                    }
                }

                // This has similar logic to types above where we lazily fill in
                // functions for remote dependencies and otherwise assert
                // they're already defined for local dependencies.
                ComponentEntityType::Func(ty) => {
                    let def = &self.types[ty];
                    if self.resolve.interfaces[interface]
                        .functions
                        .contains_key(name.as_str())
                    {
                        // TODO: should ideally verify that function signatures
                        // match.
                        continue;
                    }
                    if is_local {
                        bail!("instance function export `{name}` not defined in interface");
                    }
                    let func = self.convert_function(name.as_str(), def, owner)?;
                    let prev = self.resolve.interfaces[interface]
                        .functions
                        .insert(name.to_string(), func);
                    assert!(prev.is_none());
                }

                _ => bail!("instance type export `{name}` is not a type"),
            }
        }

        Ok(interface)
    }

    fn find_alias(&self, id: ComponentAnyTypeId) -> Option<TypeId> {
        // Consult `type_map` for `referenced` or anything in its
        // chain of aliases to determine what it maps to. This may
        // bottom out in `None` in the case that this type is
        // just now being defined, but this should otherwise follow
        // chains of aliases to determine what exactly this was a
        // `use` of if it exists.
        let mut prev = None;
        let mut cur = id;
        while prev.is_none() {
            prev = self.type_map.get(&cur).copied();
            cur = match self.types.as_ref().peel_alias(cur) {
                Some(next) => next,
                None => break,
            };
        }
        prev
    }

    /// This will parse the `name_string` as a component model ID string and
    /// ensure that there's an `InterfaceId` corresponding to its components.
    fn extract_dep_interface(&mut self, name_string: &str) -> Result<InterfaceId> {
        let name = ComponentName::new(name_string, 0).unwrap();
        let name = match name.kind() {
            ComponentNameKind::Interface(name) => name,
            _ => bail!("package name is not a valid id: {name_string}"),
        };
        let package_name = name.to_package_name();
        // Lazily create a `Package` as necessary, along with the interface.
        let package = self
            .foreign_packages
            .entry(package_name.to_string())
            .or_insert_with(|| Package {
                name: package_name.clone(),
                docs: Default::default(),
                interfaces: Default::default(),
                worlds: Default::default(),
            });
        let interface = *package
            .interfaces
            .entry(name.interface().to_string())
            .or_insert_with(|| {
                self.resolve.interfaces.alloc(Interface {
                    name: Some(name.interface().to_string()),
                    docs: Default::default(),
                    types: IndexMap::default(),
                    functions: IndexMap::new(),
                    package: None,
                    stability: Default::default(),
                })
            });

        // Record a mapping of which foreign package this interface belongs to
        self.iface_to_package_index.insert(
            interface,
            self.foreign_packages
                .get_full(&package_name.to_string())
                .unwrap()
                .0,
        );
        Ok(interface)
    }

    /// A general-purpose helper function to translate a component instance
    /// into a WIT interface.
    ///
    /// This is one of the main workhorses of this module. This handles
    /// interfaces both at the type level, for concrete components, and
    /// internally within worlds as well.
    ///
    /// The `name` provided is the contextual ID or name of the interface. This
    /// could be a kebab-name in the case of a world import or export or it can
    /// also be an ID. This is used to guide insertion into various maps.
    ///
    /// The `ty` provided is the actual component type being decoded.
    ///
    /// The `package` is where to insert the final interface if `name` is an ID
    /// meaning it's registered as a named standalone item within the package.
    fn register_interface<'a>(
        &mut self,
        name: &str,
        ty: &ComponentInstanceType,
        package: &mut PackageFields<'a>,
    ) -> Result<(WorldKey, InterfaceId)> {
        // If this interface's name is already known then that means this is an
        // interface that's both imported and exported.  Use `register_import`
        // to draw connections between types and this interface's types.
        if self.named_interfaces.contains_key(name) {
            let id = self.register_import(name, ty)?;
            return Ok((WorldKey::Interface(id), id));
        }

        // If this is a bare kebab-name for an interface then the interface's
        // listed name is `None` and the name goes out through the key.
        // Otherwise this name is extracted from `name` interpreted as an ID.
        let interface_name = self.extract_interface_name_from_component_name(name)?;

        let mut interface = Interface {
            name: interface_name.clone(),
            docs: Default::default(),
            types: IndexMap::default(),
            functions: IndexMap::new(),
            package: None,
            stability: Default::default(),
        };

        let owner = TypeOwner::Interface(self.resolve.interfaces.next_id());
        for (name, ty) in ty.exports.iter() {
            match *ty {
                ComponentEntityType::Type {
                    referenced,
                    created,
                } => {
                    let ty = self
                        .register_type_export(name.as_str(), owner, referenced, created)
                        .with_context(|| format!("failed to register type export '{name}'"))?;
                    let prev = interface.types.insert(name.to_string(), ty);
                    assert!(prev.is_none());
                }

                ComponentEntityType::Func(ty) => {
                    let ty = &self.types[ty];
                    let func = self
                        .convert_function(name.as_str(), ty, owner)
                        .with_context(|| format!("failed to convert function '{name}'"))?;
                    let prev = interface.functions.insert(name.to_string(), func);
                    assert!(prev.is_none());
                }
                _ => bail!("instance type export `{name}` is not a type or function"),
            };
        }
        let id = self.resolve.interfaces.alloc(interface);
        let key = match interface_name {
            // If this interface is named then it's part of the package, so
            // insert it. Additionally register it in `named_interfaces` so
            // further use comes back to this original definition.
            Some(interface_name) => {
                let prev = package.interfaces.insert(interface_name, id);
                assert!(prev.is_none(), "duplicate interface added for {name:?}");
                let prev = self.named_interfaces.insert(name.to_string(), id);
                assert!(prev.is_none());
                WorldKey::Interface(id)
            }

            // If this interface isn't named then its key is always a
            // kebab-name.
            None => WorldKey::Name(name.to_string()),
        };
        Ok((key, id))
    }

    fn parse_component_name(&self, name: &str) -> Result<ComponentName> {
        ComponentName::new(name, 0)
            .with_context(|| format!("cannot extract item name from: {name}"))
    }

    fn extract_interface_name_from_component_name(&self, name: &str) -> Result<Option<String>> {
        let component_name = self.parse_component_name(name)?;
        match component_name.kind() {
            ComponentNameKind::Interface(name) => Ok(Some(name.interface().to_string())),
            ComponentNameKind::Label(_name) => Ok(None),
            _ => bail!("cannot extract item name from: {name}"),
        }
    }

    fn register_type_export(
        &mut self,
        name: &str,
        owner: TypeOwner,
        referenced: ComponentAnyTypeId,
        created: ComponentAnyTypeId,
    ) -> Result<TypeId> {
        let kind = match self.find_alias(referenced) {
            // If this `TypeId` points to a type which has
            // previously been defined, meaning we're aliasing a
            // prior definition.
            Some(prev) => {
                log::debug!("type export for `{name}` is an alias");
                TypeDefKind::Type(Type::Id(prev))
            }

            // ... or this `TypeId`'s source definition has never
            // been seen before, so declare the full type.
            None => {
                log::debug!("type export for `{name}` is a new type");
                match referenced {
                    ComponentAnyTypeId::Defined(ty) => self
                        .convert_defined(&self.types[ty])
                        .context("failed to convert unaliased type")?,
                    ComponentAnyTypeId::Resource(_) => TypeDefKind::Resource,
                    _ => unreachable!(),
                }
            }
        };
        let ty = self.resolve.types.alloc(TypeDef {
            name: Some(name.to_string()),
            kind,
            docs: Default::default(),
            stability: Default::default(),
            owner,
        });

        // If this is a resource then doubly-register it in `self.resources` so
        // the ID allocated here can be looked up via name later on during
        // `convert_function`.
        if let TypeDefKind::Resource = self.resolve.types[ty].kind {
            let prev = self
                .resources
                .entry(owner)
                .or_insert(HashMap::new())
                .insert(name.to_string(), ty);
            assert!(prev.is_none());
        }

        let prev = self.type_map.insert(created, ty);
        assert!(prev.is_none());
        Ok(ty)
    }

    fn register_world<'a>(
        &mut self,
        name: &str,
        ty: &ComponentType,
        package: &mut PackageFields<'a>,
    ) -> Result<WorldId> {
        let name = self
            .extract_interface_name_from_component_name(name)?
            .context("expected world name to have an ID form")?;
        let mut world = World {
            name: name.clone(),
            docs: Default::default(),
            imports: Default::default(),
            exports: Default::default(),
            includes: Default::default(),
            include_names: Default::default(),
            package: None,
            stability: Default::default(),
        };

        let owner = TypeOwner::World(self.resolve.worlds.next_id());
        for (name, ty) in ty.imports.iter() {
            let (name, item) = match ty {
                ComponentEntityType::Instance(idx) => {
                    let ty = &self.types[*idx];
                    let (name, id) = if name.contains('/') {
                        // If a name is an interface import then it is either to
                        // a package-local or foreign interface, and both
                        // situations are handled in `register_import`.
                        let id = self.register_import(name, ty)?;
                        (WorldKey::Interface(id), id)
                    } else {
                        // A plain kebab-name indicates an inline interface that
                        // wasn't declared explicitly elsewhere with a name, and
                        // `register_interface` will create a new `Interface`
                        // with no name.
                        self.register_interface(name, ty, package)?
                    };
                    (
                        name,
                        WorldItem::Interface {
                            id,
                            stability: Default::default(),
                        },
                    )
                }
                ComponentEntityType::Type {
                    created,
                    referenced,
                } => {
                    let ty =
                        self.register_type_export(name.as_str(), owner, *referenced, *created)?;
                    (WorldKey::Name(name.to_string()), WorldItem::Type(ty))
                }
                ComponentEntityType::Func(idx) => {
                    let ty = &self.types[*idx];
                    let func = self.convert_function(name.as_str(), ty, owner)?;
                    (WorldKey::Name(name.to_string()), WorldItem::Function(func))
                }
                _ => bail!("component import `{name}` is not an instance, func, or type"),
            };
            world.imports.insert(name, item);
        }

        for (name, ty) in ty.exports.iter() {
            let (name, item) = match ty {
                ComponentEntityType::Instance(idx) => {
                    let ty = &self.types[*idx];
                    let (name, id) = if name.contains('/') {
                        // Note that despite this being an export this is
                        // calling `register_import`. With a URL this interface
                        // must have been previously defined so this will
                        // trigger the logic of either filling in a remotely
                        // defined interface or connecting items to local
                        // definitions of our own interface.
                        let id = self.register_import(name, ty)?;
                        (WorldKey::Interface(id), id)
                    } else {
                        self.register_interface(name, ty, package)?
                    };
                    (
                        name,
                        WorldItem::Interface {
                            id,
                            stability: Default::default(),
                        },
                    )
                }

                ComponentEntityType::Func(idx) => {
                    let ty = &self.types[*idx];
                    let func = self.convert_function(name.as_str(), ty, owner)?;
                    (WorldKey::Name(name.to_string()), WorldItem::Function(func))
                }

                _ => bail!("component export `{name}` is not an instance or function"),
            };
            world.exports.insert(name, item);
        }
        let id = self.resolve.worlds.alloc(world);
        let prev = package.worlds.insert(name, id);
        assert!(prev.is_none());
        Ok(id)
    }

    fn convert_function(
        &mut self,
        name: &str,
        ty: &ComponentFuncType,
        owner: TypeOwner,
    ) -> Result<Function> {
        let name = ComponentName::new(name, 0).unwrap();
        let params = ty
            .params
            .iter()
            .map(|(name, ty)| Ok((name.to_string(), self.convert_valtype(ty)?)))
            .collect::<Result<Vec<_>>>()
            .context("failed to convert params")?;
        let results = if ty.results.len() == 1 && ty.results[0].0.is_none() {
            Results::Anon(
                self.convert_valtype(&ty.results[0].1)
                    .context("failed to convert anonymous result type")?,
            )
        } else {
            Results::Named(
                ty.results
                    .iter()
                    .map(|(name, ty)| {
                        Ok((
                            name.as_ref().unwrap().to_string(),
                            self.convert_valtype(ty)?,
                        ))
                    })
                    .collect::<Result<Vec<_>>>()
                    .context("failed to convert named result types")?,
            )
        };
        Ok(Function {
            docs: Default::default(),
            stability: Default::default(),
            kind: match name.kind() {
                ComponentNameKind::Label(_) => FunctionKind::Freestanding,
                ComponentNameKind::Constructor(resource) => {
                    FunctionKind::Constructor(self.resources[&owner][resource.as_str()])
                }
                ComponentNameKind::Method(name) => {
                    FunctionKind::Method(self.resources[&owner][name.resource().as_str()])
                }
                ComponentNameKind::Static(name) => {
                    FunctionKind::Static(self.resources[&owner][name.resource().as_str()])
                }

                // Functions shouldn't have ID-based names at this time.
                ComponentNameKind::Interface(_)
                | ComponentNameKind::Url(_)
                | ComponentNameKind::Hash(_)
                | ComponentNameKind::Dependency(_) => unreachable!(),
            },

            // Note that this name includes "name mangling" such as
            // `[method]foo.bar` which is intentional. The `FunctionKind`
            // discriminant calculated above indicates how to interpret this
            // name.
            name: name.to_string(),
            params,
            results,
        })
    }

    fn convert_valtype(&mut self, ty: &ComponentValType) -> Result<Type> {
        let id = match ty {
            ComponentValType::Primitive(ty) => return Ok(self.convert_primitive(*ty)),
            ComponentValType::Type(id) => *id,
        };

        // Don't create duplicate types for anything previously created.
        if let Some(ret) = self.type_map.get(&id.into()) {
            return Ok(Type::Id(*ret));
        }

        // Otherwise create a new `TypeDef` without a name since this is an
        // anonymous valtype. Note that this is invalid for some types so return
        // errors on those types, but eventually the `bail!` here  is
        // more-or-less unreachable due to expected validation to be added to
        // the component model binary format itself.
        let def = &self.types[id];
        let kind = self.convert_defined(def)?;
        match &kind {
            TypeDefKind::Type(_)
            | TypeDefKind::List(_)
            | TypeDefKind::Tuple(_)
            | TypeDefKind::Option(_)
            | TypeDefKind::Result(_)
            | TypeDefKind::Handle(_) => {}

            TypeDefKind::Resource
            | TypeDefKind::Record(_)
            | TypeDefKind::Enum(_)
            | TypeDefKind::Variant(_)
            | TypeDefKind::Flags(_)
            | TypeDefKind::Future(_)
            | TypeDefKind::Stream(_) => {
                bail!("unexpected unnamed type of kind '{}'", kind.as_str());
            }
            TypeDefKind::Unknown => unreachable!(),
        }
        let ty = self.resolve.types.alloc(TypeDef {
            name: None,
            docs: Default::default(),
            stability: Default::default(),
            owner: TypeOwner::None,
            kind,
        });
        let prev = self.type_map.insert(id.into(), ty);
        assert!(prev.is_none());
        Ok(Type::Id(ty))
    }

    /// Converts a wasmparser `ComponentDefinedType`, the definition of a type
    /// in the component model, to a WIT `TypeDefKind` to get inserted into the
    /// types arena by the caller.
    fn convert_defined(&mut self, ty: &ComponentDefinedType) -> Result<TypeDefKind> {
        match ty {
            ComponentDefinedType::Primitive(t) => Ok(TypeDefKind::Type(self.convert_primitive(*t))),

            ComponentDefinedType::List(t) => {
                let t = self.convert_valtype(t)?;
                Ok(TypeDefKind::List(t))
            }

            ComponentDefinedType::Tuple(t) => {
                let types = t
                    .types
                    .iter()
                    .map(|t| self.convert_valtype(t))
                    .collect::<Result<_>>()?;
                Ok(TypeDefKind::Tuple(Tuple { types }))
            }

            ComponentDefinedType::Option(t) => {
                let t = self.convert_valtype(t)?;
                Ok(TypeDefKind::Option(t))
            }

            ComponentDefinedType::Result { ok, err } => {
                let ok = match ok {
                    Some(t) => Some(self.convert_valtype(t)?),
                    None => None,
                };
                let err = match err {
                    Some(t) => Some(self.convert_valtype(t)?),
                    None => None,
                };
                Ok(TypeDefKind::Result(Result_ { ok, err }))
            }

            ComponentDefinedType::Record(r) => {
                let fields = r
                    .fields
                    .iter()
                    .map(|(name, ty)| {
                        Ok(Field {
                            name: name.to_string(),
                            ty: self.convert_valtype(ty).with_context(|| {
                                format!("failed to convert record field '{name}'")
                            })?,
                            docs: Default::default(),
                        })
                    })
                    .collect::<Result<_>>()?;
                Ok(TypeDefKind::Record(Record { fields }))
            }

            ComponentDefinedType::Variant(v) => {
                let cases = v
                    .cases
                    .iter()
                    .map(|(name, case)| {
                        if case.refines.is_some() {
                            bail!("unimplemented support for `refines`");
                        }
                        Ok(Case {
                            name: name.to_string(),
                            ty: match &case.ty {
                                Some(ty) => Some(self.convert_valtype(ty)?),
                                None => None,
                            },
                            docs: Default::default(),
                        })
                    })
                    .collect::<Result<_>>()?;
                Ok(TypeDefKind::Variant(Variant { cases }))
            }

            ComponentDefinedType::Flags(f) => {
                let flags = f
                    .iter()
                    .map(|name| Flag {
                        name: name.to_string(),
                        docs: Default::default(),
                    })
                    .collect();
                Ok(TypeDefKind::Flags(Flags { flags }))
            }

            ComponentDefinedType::Enum(e) => {
                let cases = e
                    .iter()
                    .cloned()
                    .map(|name| EnumCase {
                        name: name.into(),
                        docs: Default::default(),
                    })
                    .collect();
                Ok(TypeDefKind::Enum(Enum { cases }))
            }

            ComponentDefinedType::Own(id) => {
                let id = self.type_map[&(*id).into()];
                Ok(TypeDefKind::Handle(Handle::Own(id)))
            }

            ComponentDefinedType::Borrow(id) => {
                let id = self.type_map[&(*id).into()];
                Ok(TypeDefKind::Handle(Handle::Borrow(id)))
            }
        }
    }

    fn convert_primitive(&self, ty: PrimitiveValType) -> Type {
        match ty {
            PrimitiveValType::U8 => Type::U8,
            PrimitiveValType::S8 => Type::S8,
            PrimitiveValType::U16 => Type::U16,
            PrimitiveValType::S16 => Type::S16,
            PrimitiveValType::U32 => Type::U32,
            PrimitiveValType::S32 => Type::S32,
            PrimitiveValType::U64 => Type::U64,
            PrimitiveValType::S64 => Type::S64,
            PrimitiveValType::Bool => Type::Bool,
            PrimitiveValType::Char => Type::Char,
            PrimitiveValType::String => Type::String,
            PrimitiveValType::F32 => Type::F32,
            PrimitiveValType::F64 => Type::F64,
        }
    }

    fn register_defined(&mut self, id: TypeId, def: &ComponentDefinedType) -> Result<()> {
        Registrar {
            types: &self.types,
            type_map: &mut self.type_map,
            resolve: &self.resolve,
        }
        .defined(id, def)
    }

    /// Completes the decoding of this resolve by finalizing all packages into
    /// their topological ordering within the returned `Resolve`.
    ///
    /// Takes the root package as an argument to insert.
    fn finish(mut self, package: Package) -> (Resolve, PackageId) {
        // Build a topological ordering is then calculated by visiting all the
        // transitive dependencies of packages.
        let mut order = IndexSet::new();
        for i in 0..self.foreign_packages.len() {
            self.visit_package(i, &mut order);
        }

        // Using the topological ordering create a temporary map from
        // index-in-`foreign_packages` to index-in-`order`
        let mut idx_to_pos = vec![0; self.foreign_packages.len()];
        for (pos, idx) in order.iter().enumerate() {
            idx_to_pos[*idx] = pos;
        }
        // .. and then using `idx_to_pos` sort the `foreign_packages` array based
        // on the position it's at in the topological ordering
        let mut deps = mem::take(&mut self.foreign_packages)
            .into_iter()
            .enumerate()
            .collect::<Vec<_>>();
        deps.sort_by_key(|(idx, _)| idx_to_pos[*idx]);

        // .. and finally insert the packages, in their final topological
        // ordering, into the returned array.
        for (_idx, (_url, pkg)) in deps {
            self.insert_package(pkg);
        }

        let id = self.insert_package(package);
        assert!(self.resolve.worlds.iter().all(|(_, w)| w.package.is_some()));
        assert!(self
            .resolve
            .interfaces
            .iter()
            .all(|(_, i)| i.package.is_some()));
        (self.resolve, id)
    }

    fn insert_package(&mut self, package: Package) -> PackageId {
        let Package {
            name,
            interfaces,
            worlds,
            docs,
        } = package;

        // Most of the time the `package` being inserted is not already present
        // in `self.resolve`, but in the case of the top-level `decode_world`
        // function this isn't the case. This shouldn't in general be a problem
        // so union-up the packages here while asserting that nothing gets
        // replaced by accident which would indicate a bug.
        let pkg = self
            .resolve
            .package_names
            .get(&name)
            .copied()
            .unwrap_or_else(|| {
                let id = self.resolve.packages.alloc(Package {
                    name: name.clone(),
                    interfaces: Default::default(),
                    worlds: Default::default(),
                    docs,
                });
                let prev = self.resolve.package_names.insert(name, id);
                assert!(prev.is_none());
                id
            });

        for (name, id) in interfaces {
            let prev = self.resolve.packages[pkg].interfaces.insert(name, id);
            assert!(prev.is_none());
            self.resolve.interfaces[id].package = Some(pkg);
        }

        for (name, id) in worlds {
            let prev = self.resolve.packages[pkg].worlds.insert(name, id);
            assert!(prev.is_none());
            let world = &mut self.resolve.worlds[id];
            world.package = Some(pkg);
            for (name, item) in world.imports.iter().chain(world.exports.iter()) {
                if let WorldKey::Name(_) = name {
                    if let WorldItem::Interface { id, .. } = item {
                        self.resolve.interfaces[*id].package = Some(pkg);
                    }
                }
            }
        }

        pkg
    }

    fn visit_package(&self, idx: usize, order: &mut IndexSet<usize>) {
        if order.contains(&idx) {
            return;
        }

        let (_name, pkg) = self.foreign_packages.get_index(idx).unwrap();
        let interfaces = pkg.interfaces.values().copied().chain(
            pkg.worlds
                .values()
                .flat_map(|w| {
                    let world = &self.resolve.worlds[*w];
                    world.imports.values().chain(world.exports.values())
                })
                .filter_map(|item| match item {
                    WorldItem::Interface { id, .. } => Some(*id),
                    WorldItem::Function(_) | WorldItem::Type(_) => None,
                }),
        );
        for iface in interfaces {
            for dep in self.resolve.interface_direct_deps(iface) {
                let dep_idx = self.iface_to_package_index[&dep];
                if dep_idx != idx {
                    self.visit_package(dep_idx, order);
                }
            }
        }

        assert!(order.insert(idx));
    }
}

/// Helper type to register the structure of a wasm-defined type against a
/// wit-defined type.
struct Registrar<'a> {
    types: &'a Types,
    type_map: &'a mut HashMap<ComponentAnyTypeId, TypeId>,
    resolve: &'a Resolve,
}

impl Registrar<'_> {
    /// Verifies that the wasm structure of `def` matches the wit structure of
    /// `id` and recursively registers types.
    fn defined(&mut self, id: TypeId, def: &ComponentDefinedType) -> Result<()> {
        match def {
            ComponentDefinedType::Primitive(_) => Ok(()),

            ComponentDefinedType::List(t) => {
                let ty = match &self.resolve.types[id].kind {
                    TypeDefKind::List(r) => r,
                    // Note that all cases below have this match and the general
                    // idea is that once a type is named or otherwise identified
                    // here there's no need to recurse. The purpose of this
                    // registrar is to build connections for anonymous types
                    // that don't otherwise have a name to ensure that they're
                    // decoded to reuse the same constructs consistently. For
                    // that reason once something is named we can bail out.
                    TypeDefKind::Type(Type::Id(_)) => return Ok(()),
                    _ => bail!("expected a list"),
                };
                self.valtype(t, ty)
            }

            ComponentDefinedType::Tuple(t) => {
                let ty = match &self.resolve.types[id].kind {
                    TypeDefKind::Tuple(r) => r,
                    TypeDefKind::Type(Type::Id(_)) => return Ok(()),
                    _ => bail!("expected a tuple"),
                };
                if ty.types.len() != t.types.len() {
                    bail!("mismatched number of tuple fields");
                }
                for (a, b) in t.types.iter().zip(ty.types.iter()) {
                    self.valtype(a, b)?;
                }
                Ok(())
            }

            ComponentDefinedType::Option(t) => {
                let ty = match &self.resolve.types[id].kind {
                    TypeDefKind::Option(r) => r,
                    TypeDefKind::Type(Type::Id(_)) => return Ok(()),
                    _ => bail!("expected an option"),
                };
                self.valtype(t, ty)
            }

            ComponentDefinedType::Result { ok, err } => {
                let ty = match &self.resolve.types[id].kind {
                    TypeDefKind::Result(r) => r,
                    TypeDefKind::Type(Type::Id(_)) => return Ok(()),
                    _ => bail!("expected a result"),
                };
                match (ok, &ty.ok) {
                    (Some(a), Some(b)) => self.valtype(a, b)?,
                    (None, None) => {}
                    _ => bail!("disagreement on result structure"),
                }
                match (err, &ty.err) {
                    (Some(a), Some(b)) => self.valtype(a, b)?,
                    (None, None) => {}
                    _ => bail!("disagreement on result structure"),
                }
                Ok(())
            }

            ComponentDefinedType::Record(def) => {
                let ty = match &self.resolve.types[id].kind {
                    TypeDefKind::Record(r) => r,
                    TypeDefKind::Type(Type::Id(_)) => return Ok(()),
                    _ => bail!("expected a record"),
                };
                if def.fields.len() != ty.fields.len() {
                    bail!("mismatched number of record fields");
                }
                for ((name, ty), field) in def.fields.iter().zip(&ty.fields) {
                    if name.as_str() != field.name {
                        bail!("mismatched field order");
                    }
                    self.valtype(ty, &field.ty)?;
                }
                Ok(())
            }

            ComponentDefinedType::Variant(def) => {
                let ty = match &self.resolve.types[id].kind {
                    TypeDefKind::Variant(r) => r,
                    TypeDefKind::Type(Type::Id(_)) => return Ok(()),
                    _ => bail!("expected a variant"),
                };
                if def.cases.len() != ty.cases.len() {
                    bail!("mismatched number of variant cases");
                }
                for ((name, ty), case) in def.cases.iter().zip(&ty.cases) {
                    if name.as_str() != case.name {
                        bail!("mismatched case order");
                    }
                    match (&ty.ty, &case.ty) {
                        (Some(a), Some(b)) => self.valtype(a, b)?,
                        (None, None) => {}
                        _ => bail!("disagreement on case type"),
                    }
                }
                Ok(())
            }

            // These have no recursive structure so they can bail out.
            ComponentDefinedType::Flags(_)
            | ComponentDefinedType::Enum(_)
            | ComponentDefinedType::Own(_)
            | ComponentDefinedType::Borrow(_) => Ok(()),
        }
    }

    fn valtype(&mut self, wasm: &ComponentValType, wit: &Type) -> Result<()> {
        let wasm = match wasm {
            ComponentValType::Type(wasm) => *wasm,
            ComponentValType::Primitive(_wasm) => {
                assert!(!matches!(wit, Type::Id(_)));
                return Ok(());
            }
        };
        let wit = match wit {
            Type::Id(id) => *id,
            _ => bail!("expected id-based type"),
        };
        let prev = match self.type_map.insert(wasm.into(), wit) {
            Some(prev) => prev,
            None => {
                let wasm = &self.types[wasm];
                return self.defined(wit, wasm);
            }
        };
        // If `wit` matches `prev` then we've just rediscovered what we already
        // knew which is that the `wasm` id maps to the `wit` id.
        //
        // If, however, `wit` is not equal to `prev` then that's more
        // interesting. Consider a component such as:
        //
        // ```wasm
        // (component
        //   (import (interface "a:b/name") (instance
        //      (type $l (list string))
        //      (type $foo (variant (case "l" $l)))
        //      (export "foo" (type (eq $foo)))
        //   ))
        //   (component $c
        //     (type $l (list string))
        //     (type $bar (variant (case "n" u16) (case "l" $l)))
        //     (export "bar" (type $bar))
        //     (type $foo (variant (case "l" $l)))
        //     (export "foo" (type $foo))
        //   )
        //   (instance $i (instantiate $c))
        //   (export (interface "a:b/name") (instance $i))
        // )
        // ```
        //
        // This roughly corresponds to:
        //
        // ```wit
        // package a:b
        //
        // interface name {
        //   variant bar {
        //     n(u16),
        //     l(list<string>),
        //   }
        //
        //   variant foo {
        //     l(list<string>),
        //   }
        // }
        //
        // world module {
        //   import name
        //   export name
        // }
        // ```
        //
        // In this situation first we'll see the `import` which records type
        // information for the `foo` type in `interface name`. Later on the full
        // picture of `interface name` becomes apparent with the export of a
        // component which has full type information. When walking over this
        // first `bar` is seen and its recursive structure.
        //
        // The problem arises when walking over the `foo` type. In this
        // situation the code path we're currently on will be hit because
        // there's a preexisting definition of `foo` from the import and it's
        // now going to be unified with what we've seen in the export. When
        // visiting the `list<string>` case of the `foo` variant this ends up
        // being different than the `list<string>` used by the `bar` variant. The
        // reason for this is that when visiting `bar` the wasm-defined `(list
        // string)` hasn't been seen before so a new type is allocated. Later
        // though this same wasm type is unified with the first `(list string)`
        // type in the `import`.
        //
        // All-in-all this ends up meaning that it's possible for `prev` to not
        // match `wit`. In this situation it means the decoded WIT interface
        // will have duplicate definitions of `list<string>`. This is,
        // theoretically, not that big of a problem because the same underlying
        // definition is still there and the meaning of the type is the same.
        // This can, however, perhaps be a problem for consumers where it's
        // assumed that all `list<string>` are equal and there's only one. For
        // example a bindings generator for C may assume that `list<string>`
        // will only appear once and generate a single name for it, but with two
        // different types in play here it may generate two types of the same
        // name (or something like that).
        //
        // For now though this is left for a future refactoring. Fixing this
        // issue would require tracking anonymous types during type translation
        // so the decoding process for the `bar` export would reuse the
        // `list<string>` type created from decoding the `foo` import. That's
        // somewhat nontrivial at this time, so it's left for a future
        // refactoring.
        let _ = prev;
        Ok(())
    }
}

pub(crate) trait InterfaceNameExt {
    fn to_package_name(&self) -> PackageName;
}

impl InterfaceNameExt for wasmparser::names::InterfaceName<'_> {
    fn to_package_name(&self) -> PackageName {
        PackageName {
            namespace: self.namespace().to_string(),
            name: self.package().to_string(),
            version: self.version(),
        }
    }
}
