Repository: bytecodealliance/wasm-tools
Pull request #1252 (2023-10-13 22:10:25)

Change the encoding of wit definitions
Address https://github.com/WebAssembly/component-model/pull/248 by implementing support for the new encoding proposal. Additionally, this PR maintains backwards compatibility with decoding the previous encoding, by detecting when the newer encoding was used.

The rollout of the v2 encoding scheme will follow roughly the same plan as for semicolons in wit: there's a new environment variable introduced that controls the encoding scheme, `WIT_COMPONENT_ENCODING_V2` that can be used to control when we encode in the new format, with the default behavior being what's done on main. After tooling has caught up to expecting the new format we can switch the default behavior to be the new format, and then completely remove support for v1 after we're confident nothing depends on it anymore.

elliottt: @alexcrichton I've switched the fuzzer over to using the V2 format, and also modified it to never produce an empty package.

Patch:
diff --git a/crates/wit-component/src/decoding.rs b/crates/wit-component/src/decoding.rs
index 8fc5ca21..a998104a 100644
--- a/crates/wit-component/src/decoding.rs
+++ b/crates/wit-component/src/decoding.rs
@@ -27,6 +27,12 @@ enum Extern<'a> {
     Export(ComponentExport<'a>),
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum WitEncodingVersion {
+    V1,
+    V2,
+}
+
 impl<'a> ComponentInfo<'a> {
     /// Creates a new component info by parsing the given WebAssembly component bytes.
     fn new(bytes: &'a [u8]) -> Result<Self> {
@@ -79,27 +85,43 @@ impl<'a> ComponentInfo<'a> {
         })
     }
 
-    fn is_wit_package(&self) -> bool {
+    fn is_wit_package(&self) -> Option<WitEncodingVersion> {
         // all wit package exports must be component types, and there must be at
         // least one
-        !self.externs.is_empty()
-            && self.externs.iter().all(|(_, item)| {
-                let export = match item {
-                    Extern::Export(e) => e,
-                    _ => return false,
-                };
-                match export.kind {
-                    ComponentExternalKind::Type => matches!(
-                        &self.types[self.types.component_type_at(export.index)],
-                        types::Type::Component(_)
-                    ),
-                    _ => false,
-                }
-            })
+        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[self.types.component_type_at(export.index)],
+                    types::Type::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 KebabName::new(self.externs[0].0, 0).ok()?.kind() {
+            KebabNameKind::Id { interface, .. } if interface.as_str() == "wit" => {
+                Some(WitEncodingVersion::V1)
+            }
+            KebabNameKind::Normal(_) => Some(WitEncodingVersion::V2),
+            _ => None,
+        }
     }
 
-    fn decode_wit_package(&self) -> Result<(Resolve, PackageId)> {
-        assert!(self.is_wit_package());
+    fn decode_wit_v1_package(&self) -> Result<(Resolve, PackageId)> {
         let resolve = Resolve::default();
         let mut decoder = WitPackageDecoder {
             resolve,
@@ -125,7 +147,7 @@ impl<'a> ComponentInfo<'a> {
             let name = KebabName::new(*name, 0).unwrap();
             pkg = Some(
                 decoder
-                    .decode_package(&name, ty)
+                    .decode_v1_package(&name, ty)
                     .with_context(|| format!("failed to decode document `{name}`"))?,
             );
         }
@@ -138,8 +160,102 @@ impl<'a> ComponentInfo<'a> {
         Ok((resolve, package))
     }
 
+    fn decode_wit_v2_package(&self) -> Result<(Resolve, PackageId)> {
+        let resolve = Resolve::default();
+        let mut decoder = WitPackageDecoder {
+            resolve,
+            info: self,
+            type_map: HashMap::new(),
+            foreign_packages: Default::default(),
+            iface_to_package_index: Default::default(),
+            named_interfaces: Default::default(),
+            resources: Default::default(),
+        };
+
+        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.component_type_at(index);
+            let component = self.types[id].unwrap_component();
+
+            // 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 exported = match component.exports[name] {
+                types::ComponentEntityType::Component(ty) => &self.types[ty],
+                types::ComponentEntityType::Instance(ty) => &self.types[ty],
+                _ => unreachable!(),
+            };
+
+            let name = match exported {
+                types::Type::Component(ty) => {
+                    let package_name = decoder.decode_world(name.as_str(), ty, &mut fields)?;
+                    package_name
+                }
+                types::Type::ComponentInstance(ty) => {
+                    let package_name = decoder.decode_interface(
+                        name.as_str(),
+                        &component.imports,
+                        ty,
+                        &mut fields,
+                    )?;
+                    package_name
+                }
+                _ => panic!(),
+            };
+
+            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_docs) = &self.package_docs {
+            package_docs.inject(&mut resolve, package)?;
+        }
+        Ok((resolve, package))
+    }
+
     fn decode_component(&self) -> Result<(Resolve, WorldId)> {
-        assert!(!self.is_wit_package());
+        assert!(self.is_wit_package().is_none());
         let mut resolve = Resolve::default();
         // Note that this name is arbitrarily chosen. We may one day perhaps
         // want to encode this in the component binary format itself, but for
@@ -177,13 +293,18 @@ impl<'a> ComponentInfo<'a> {
             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 package)?
+                    decoder.decode_component_import(import, world, &mut fields)?
                 }
                 Extern::Export(export) => {
-                    decoder.decode_component_export(export, world, &mut package)?
+                    decoder.decode_component_export(export, world, &mut fields)?
                 }
             }
         }
@@ -234,10 +355,19 @@ impl DecodedWasm {
 pub fn decode(bytes: &[u8]) -> Result<DecodedWasm> {
     let info = ComponentInfo::new(bytes)?;
 
-    if info.is_wit_package() {
-        log::debug!("decoding a WIT package encoded as wasm");
-        let (resolve, pkg) = info.decode_wit_package()?;
-        Ok(DecodedWasm::WitPackage(resolve, pkg))
+    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()?;
@@ -245,6 +375,11 @@ pub fn decode(bytes: &[u8]) -> Result<DecodedWasm> {
     }
 }
 
+struct PackageFields<'a> {
+    interfaces: &'a mut IndexMap<String, InterfaceId>,
+    worlds: &'a mut IndexMap<String, WorldId>,
+}
+
 struct WitPackageDecoder<'a> {
     resolve: Resolve,
     info: &'a ComponentInfo<'a>,
@@ -266,7 +401,11 @@ struct WitPackageDecoder<'a> {
 }
 
 impl WitPackageDecoder<'_> {
-    fn decode_package(&mut self, name: &KebabName, ty: &types::ComponentType) -> Result<Package> {
+    fn decode_v1_package(
+        &mut self,
+        name: &KebabName,
+        ty: &types::ComponentType,
+    ) -> Result<Package> {
         // Process all imports for this package first, where imports are
         // importing from remote packages.
         for (name, ty) in ty.imports.iter() {
@@ -302,16 +441,21 @@ impl WitPackageDecoder<'_> {
             worlds: Default::default(),
         };
 
+        let mut fields = PackageFields {
+            interfaces: &mut package.interfaces,
+            worlds: &mut package.worlds,
+        };
+
         for (name, ty) in ty.exports.iter() {
             match ty {
                 types::ComponentEntityType::Instance(idx) => {
                     let ty = self.info.types[*idx].unwrap_component_instance();
-                    self.register_interface(name.as_str(), ty, &mut package)
+                    self.register_interface(name.as_str(), ty, &mut fields)
                         .with_context(|| format!("failed to process export `{name}`"))?;
                 }
                 types::ComponentEntityType::Component(idx) => {
                     let ty = self.info.types[*idx].unwrap_component();
-                    self.register_world(name.as_str(), ty, &mut package)
+                    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"),
@@ -320,11 +464,81 @@ impl WitPackageDecoder<'_> {
         Ok(package)
     }
 
-    fn decode_component_import(
+    fn decode_interface<'a>(
+        &mut self,
+        name: &str,
+        imports: &IndexMap<String, types::ComponentEntityType>,
+        ty: &types::ComponentInstanceType,
+        fields: &mut PackageFields<'a>,
+    ) -> Result<PackageName> {
+        let kebab_name = self
+            .extract_kebab_name(name)
+            .context("expected world name to have an ID form")?;
+
+        let package = match kebab_name.kind() {
+            KebabNameKind::Id {
+                namespace,
+                package,
+                version,
+                ..
+            } => PackageName {
+                namespace: namespace.to_string(),
+                name: package.to_string(),
+                version,
+            },
+            _ => bail!("expected world name to be fully qualified"),
+        };
+
+        for (name, ty) in imports.iter() {
+            let ty = match ty {
+                types::ComponentEntityType::Instance(idx) => {
+                    self.info.types[*idx].unwrap_component_instance()
+                }
+                _ => 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: &types::ComponentType,
+        fields: &mut PackageFields<'a>,
+    ) -> Result<PackageName> {
+        let kebab_name = self
+            .extract_kebab_name(name)
+            .context("expected world name to have an ID form")?;
+
+        let package = match kebab_name.kind() {
+            KebabNameKind::Id {
+                namespace,
+                package,
+                version,
+                ..
+            } => PackageName {
+                namespace: namespace.to_string(),
+                name: package.to_string(),
+                version,
+            },
+            _ => bail!("expected world name to be fully qualified"),
+        };
+
+        let _ = self.register_world(name, ty, fields)?;
+
+        Ok(package)
+    }
+
+    fn decode_component_import<'a>(
         &mut self,
         import: &ComponentImport<'_>,
         world: WorldId,
-        package: &mut Package,
+        package: &mut PackageFields<'a>,
     ) -> Result<()> {
         let name = import.name.as_str();
         log::debug!("decoding component import `{name}`");
@@ -369,11 +583,11 @@ impl WitPackageDecoder<'_> {
         Ok(())
     }
 
-    fn decode_component_export(
+    fn decode_component_export<'a>(
         &mut self,
         export: &ComponentExport<'_>,
         world: WorldId,
-        package: &mut Package,
+        package: &mut PackageFields<'a>,
     ) -> Result<()> {
         let name = export.name.as_str();
         log::debug!("decoding component export `{name}`");
@@ -618,11 +832,11 @@ impl WitPackageDecoder<'_> {
     ///
     /// 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(
+    fn register_interface<'a>(
         &mut self,
         name: &str,
         ty: &types::ComponentInstanceType,
-        package: &mut Package,
+        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`
@@ -690,16 +904,21 @@ impl WitPackageDecoder<'_> {
         Ok((key, id))
     }
 
-    fn extract_interface_name_from_kebab_name(&self, name: &str) -> Result<Option<String>> {
+    fn extract_kebab_name(&self, name: &str) -> Result<KebabName> {
         let import_name = if name.contains('/') {
             ComponentExternName::Interface(name)
         } else {
             ComponentExternName::Kebab(name)
         };
-        let kebab_name = KebabName::new(import_name, 0);
-        match kebab_name.as_ref().map(|k| k.kind()) {
-            Ok(KebabNameKind::Id { interface, .. }) => Ok(Some(interface.to_string())),
-            Ok(KebabNameKind::Normal(_name)) => Ok(None),
+        KebabName::new(import_name, 0)
+            .with_context(|| format!("cannot extract item name from: {name}"))
+    }
+
+    fn extract_interface_name_from_kebab_name(&self, name: &str) -> Result<Option<String>> {
+        let kebab_name = self.extract_kebab_name(name)?;
+        match kebab_name.kind() {
+            KebabNameKind::Id { interface, .. } => Ok(Some(interface.to_string())),
+            KebabNameKind::Normal(_name) => Ok(None),
             _ => bail!("cannot extract item name from: {name}"),
         }
     }
@@ -757,11 +976,11 @@ impl WitPackageDecoder<'_> {
         Ok(ty)
     }
 
-    fn register_world(
+    fn register_world<'a>(
         &mut self,
         name: &str,
         ty: &types::ComponentType,
-        package: &mut Package,
+        package: &mut PackageFields<'a>,
     ) -> Result<WorldId> {
         let name = self
             .extract_interface_name_from_kebab_name(name)?
diff --git a/crates/wit-component/src/encoding/wit/mod.rs b/crates/wit-component/src/encoding/wit/mod.rs
new file mode 100644
index 00000000..72e82baf
--- /dev/null
+++ b/crates/wit-component/src/encoding/wit/mod.rs
@@ -0,0 +1,68 @@
+use anyhow::Result;
+use wasm_encoder::{ComponentBuilder, ComponentType};
+use wit_parser::{PackageId, Resolve, WorldId};
+
+mod v1;
+mod v2;
+
+const ENCODE_V2_BY_DEFAULT: bool = false;
+
+fn use_v2_encoding() -> bool {
+    match std::env::var("WIT_COMPONENT_ENCODING_V2") {
+        Ok(s) => s == "1",
+        Err(_) => ENCODE_V2_BY_DEFAULT,
+    }
+}
+
+/// Encodes the given `package` within `resolve` to a binary WebAssembly
+/// representation.
+///
+/// This function is the root of the implementation of serializing a WIT package
+/// into a WebAssembly representation. The wasm representation serves two
+/// purposes:
+///
+/// * One is to be a binary encoding of a WIT document which is ideally more
+///   stable than the WIT textual format itself.
+/// * Another is to provide a clear mapping of all WIT features into the
+///   component model through use of its binary representation.
+///
+/// The `resolve` provided is a set of packages and types and such and the
+/// `package` argument is an ID within the world provided. The documents within
+/// `package` will all be encoded into the binary returned.
+///
+/// The binary returned can be [`decode`d](crate::decode) to recover the WIT
+/// package provided.
+pub fn encode(use_v2: Option<bool>, resolve: &Resolve, package: PackageId) -> Result<Vec<u8>> {
+    if use_v2.unwrap_or_else(use_v2_encoding) {
+        v2::encode(resolve, package)
+    } else {
+        v1::encode(resolve, package)
+    }
+}
+
+/// Exactly like `encode`, except gives an unfinished `ComponentBuilder` in case you need
+/// to append anything else before finishing.
+pub fn encode_component(
+    use_v2: Option<bool>,
+    resolve: &Resolve,
+    package: PackageId,
+) -> Result<ComponentBuilder> {
+    if use_v2.unwrap_or_else(use_v2_encoding) {
+        v2::encode_component(resolve, package)
+    } else {
+        v1::encode_component(resolve, package)
+    }
+}
+
+/// Encodes a `world` as a component type.
+pub fn encode_world(
+    use_v2: Option<bool>,
+    resolve: &Resolve,
+    world_id: WorldId,
+) -> Result<ComponentType> {
+    if use_v2.unwrap_or_else(use_v2_encoding) {
+        v2::encode_world(resolve, world_id)
+    } else {
+        v1::encode_world(resolve, world_id)
+    }
+}
diff --git a/crates/wit-component/src/encoding/wit.rs b/crates/wit-component/src/encoding/wit/v1.rs
similarity index 99%
rename from crates/wit-component/src/encoding/wit.rs
rename to crates/wit-component/src/encoding/wit/v1.rs
index 0c90dcc0..e83b91b0 100644
--- a/crates/wit-component/src/encoding/wit.rs
+++ b/crates/wit-component/src/encoding/wit/v1.rs
@@ -1,4 +1,7 @@
-use crate::encoding::types::{FunctionKey, ValtypeEncoder};
+use crate::encoding::{
+    docs::PackageDocs,
+    types::{FunctionKey, ValtypeEncoder},
+};
 use anyhow::Result;
 use indexmap::IndexSet;
 use std::collections::HashMap;
@@ -6,8 +9,6 @@ use std::mem;
 use wasm_encoder::*;
 use wit_parser::*;
 
-use super::docs::PackageDocs;
-
 /// Encodes the given `package` within `resolve` to a binary WebAssembly
 /// representation.
 ///
diff --git a/crates/wit-component/src/encoding/wit/v2.rs b/crates/wit-component/src/encoding/wit/v2.rs
new file mode 100644
index 00000000..2a3a2d78
--- /dev/null
+++ b/crates/wit-component/src/encoding/wit/v2.rs
@@ -0,0 +1,417 @@
+use crate::encoding::{
+    docs::PackageDocs,
+    types::{FunctionKey, ValtypeEncoder},
+};
+use anyhow::Result;
+use indexmap::IndexSet;
+use std::collections::HashMap;
+use std::mem;
+use wasm_encoder::*;
+use wit_parser::*;
+
+/// Encodes the given `package` within `resolve` to a binary WebAssembly
+/// representation.
+///
+/// This function is the root of the implementation of serializing a WIT package
+/// into a WebAssembly representation. The wasm representation serves two
+/// purposes:
+///
+/// * One is to be a binary encoding of a WIT document which is ideally more
+///   stable than the WIT textual format itself.
+/// * Another is to provide a clear mapping of all WIT features into the
+///   component model through use of its binary representation.
+///
+/// The `resolve` provided is a set of packages and types and such and the
+/// `package` argument is an ID within the world provided. The documents within
+/// `package` will all be encoded into the binary returned.
+///
+/// The binary returned can be [`decode`d](crate::decode) to recover the WIT
+/// package provided.
+pub fn encode(resolve: &Resolve, package: PackageId) -> Result<Vec<u8>> {
+    let mut component = encode_component(resolve, package)?;
+    component.raw_custom_section(&crate::base_producers().raw_custom_section());
+    Ok(component.finish())
+}
+
+/// Exactly like `encode`, except gives an unfinished `ComponentBuilder` in case you need
+/// to append anything else before finishing.
+pub fn encode_component(resolve: &Resolve, package: PackageId) -> Result<ComponentBuilder> {
+    let mut encoder = Encoder {
+        component: ComponentBuilder::default(),
+        resolve,
+        package,
+    };
+    encoder.run()?;
+
+    let package_docs = PackageDocs::extract(resolve, package);
+    encoder
+        .component
+        .raw_custom_section(&package_docs.raw_custom_section()?);
+
+    Ok(encoder.component)
+}
+
+struct Encoder<'a> {
+    component: ComponentBuilder,
+    resolve: &'a Resolve,
+    package: PackageId,
+}
+
+impl Encoder<'_> {
+    fn run(&mut self) -> Result<()> {
+        // Build a set of interfaces reachable from this document, including the
+        // interfaces in the document itself. This is used to import instances
+        // into the component type we're encoding. Note that entire interfaces
+        // are imported with all their types as opposed to just the needed types
+        // in an interface for this document. That's done to assist with the
+        // decoding process where everyone's view of a foreign document agrees
+        // notably on the order that types are defined in to assist with
+        // roundtripping.
+        for (name, &id) in self.resolve.packages[self.package].interfaces.iter() {
+            let component_ty = self.encode_interface(id)?;
+            let ty = self.component.type_component(&component_ty);
+            self.component
+                .export(name.as_ref(), ComponentExportKind::Type, ty, None);
+        }
+
+        for (name, &world) in self.resolve.packages[self.package].worlds.iter() {
+            let component_ty = encode_world(self.resolve, world)?;
+            let ty = self.component.type_component(&component_ty);
+            self.component
+                .export(name.as_ref(), ComponentExportKind::Type, ty, None);
+        }
+
+        Ok(())
+    }
+
+    fn encode_interface(&mut self, id: InterfaceId) -> Result<ComponentType> {
+        // Build a set of interfaces reachable from this document, including the
+        // interfaces in the document itself. This is used to import instances
+        // into the component type we're encoding. Note that entire interfaces
+        // are imported with all their types as opposed to just the needed types
+        // in an interface for this document. That's done to assist with the
+        // decoding process where everyone's view of a foreign document agrees
+        // notably on the order that types are defined in to assist with
+        // roundtripping.
+        let mut interfaces = IndexSet::new();
+        self.add_live_interfaces(&mut interfaces, id);
+
+        // Seed the set of used names with all exported interfaces to ensure
+        // that imported interfaces choose different names as the import names
+        // aren't used during decoding.
+        let mut used_names = IndexSet::new();
+        for id in interfaces.iter() {
+            let iface = &self.resolve.interfaces[*id];
+            if iface.package == Some(self.package) {
+                let first = used_names.insert(iface.name.as_ref().unwrap().clone());
+                assert!(first);
+            }
+        }
+
+        let mut encoder = InterfaceEncoder::new(self.resolve);
+        for interface in interfaces {
+            encoder.interface = Some(interface);
+            let iface = &self.resolve.interfaces[interface];
+            let name = self.resolve.id_of(interface).unwrap();
+            if interface == id {
+                let idx = encoder.encode_instance(interface)?;
+                log::trace!("exporting self as {idx}");
+                encoder.outer.export(&name, ComponentTypeRef::Instance(idx));
+            } else {
+                encoder.push_instance();
+                for (_, id) in iface.types.iter() {
+                    encoder.encode_valtype(self.resolve, &Type::Id(*id))?;
+                }
+                let instance = encoder.pop_instance();
+                let idx = encoder.outer.type_count();
+                encoder.outer.ty().instance(&instance);
+                encoder.import_map.insert(interface, encoder.instances);
+                encoder.instances += 1;
+                encoder.outer.import(&name, ComponentTypeRef::Instance(idx));
+            }
+        }
+
+        encoder.interface = None;
+
+        Ok(encoder.outer)
+    }
+
+    /// Recursively add all live interfaces reachable from `id` into the
+    /// `interfaces` set, and then add `id` to the set.
+    fn add_live_interfaces(&self, interfaces: &mut IndexSet<InterfaceId>, id: InterfaceId) {
+        if interfaces.contains(&id) {
+            return;
+        }
+        for id in self.resolve.interface_direct_deps(id) {
+            self.add_live_interfaces(interfaces, id);
+        }
+        assert!(interfaces.insert(id));
+    }
+}
+
+struct InterfaceEncoder<'a> {
+    resolve: &'a Resolve,
+    outer: ComponentType,
+    ty: Option<InstanceType>,
+    func_type_map: HashMap<FunctionKey<'a>, u32>,
+    type_map: HashMap<TypeId, u32>,
+    saved_types: Option<(HashMap<TypeId, u32>, HashMap<FunctionKey<'a>, u32>)>,
+    import_map: HashMap<InterfaceId, u32>,
+    outer_type_map: HashMap<TypeId, u32>,
+    instances: u32,
+    import_types: bool,
+    interface: Option<InterfaceId>,
+}
+
+impl InterfaceEncoder<'_> {
+    fn new(resolve: &Resolve) -> InterfaceEncoder<'_> {
+        InterfaceEncoder {
+            resolve,
+            outer: ComponentType::new(),
+            ty: None,
+            type_map: Default::default(),
+            func_type_map: Default::default(),
+            import_map: Default::default(),
+            outer_type_map: Default::default(),
+            instances: 0,
+            saved_types: None,
+            import_types: false,
+            interface: None,
+        }
+    }
+
+    fn encode_instance(&mut self, interface: InterfaceId) -> Result<u32> {
+        self.push_instance();
+        let iface = &self.resolve.interfaces[interface];
+        let mut type_order = IndexSet::new();
+        for (_, id) in iface.types.iter() {
+            self.encode_valtype(self.resolve, &Type::Id(*id))?;
+            type_order.insert(*id);
+        }
+
+        // Sort functions based on whether or not they're associated with
+        // resources.
+        //
+        // This is done here to ensure that when a WIT package is printed as WIT
+        // then decoded, or if it's printed as Wasm then decoded, the final
+        // result is the same. When printing via WIT resource methods are
+        // attached to the resource types themselves meaning that they'll appear
+        // intermingled with the rest of the types, namely first before all
+        // other functions. The purpose of this sort is to perform a stable sort
+        // over all functions by shuffling the resource-related functions first,
+        // in order of when their associated resource was encoded, and putting
+        // freestanding functions last.
+        //
+        // Note that this is not actually required for correctness, it's
+        // basically here to make fuzzing happy.
+        let mut funcs = iface.functions.iter().collect::<Vec<_>>();
+        funcs.sort_by_key(|(_name, func)| match func.kind {
+            FunctionKind::Freestanding => type_order.len(),
+            FunctionKind::Method(id) | FunctionKind::Constructor(id) | FunctionKind::Static(id) => {
+                type_order.get_index_of(&id).unwrap()
+            }
+        });
+
+        for (name, func) in funcs {
+            let ty = self.encode_func_type(self.resolve, func)?;
+            self.ty
+                .as_mut()
+                .unwrap()
+                .export(name, ComponentTypeRef::Func(ty));
+        }
+        let instance = self.pop_instance();
+        let idx = self.outer.type_count();
+        self.outer.ty().instance(&instance);
+        self.import_map.insert(interface, self.instances);
+        self.instances += 1;
+        Ok(idx)
+    }
+
+    fn push_instance(&mut self) {
+        assert!(self.ty.is_none());
+        assert!(self.saved_types.is_none());
+        self.saved_types = Some((
+            mem::take(&mut self.type_map),
+            mem::take(&mut self.func_type_map),
+        ));
+        self.ty = Some(InstanceType::default());
+    }
+
+    fn pop_instance(&mut self) -> InstanceType {
+        let (types, funcs) = self.saved_types.take().unwrap();
+        self.type_map = types;
+        self.func_type_map = funcs;
+        mem::take(&mut self.ty).unwrap()
+    }
+}
+
+impl<'a> ValtypeEncoder<'a> for InterfaceEncoder<'a> {
+    fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) {
+        match &mut self.ty {
+            Some(ty) => (ty.type_count(), ty.ty().defined_type()),
+            None => (self.outer.type_count(), self.outer.ty().defined_type()),
+        }
+    }
+    fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) {
+        match &mut self.ty {
+            Some(ty) => (ty.type_count(), ty.ty().function()),
+            None => (self.outer.type_count(), self.outer.ty().function()),
+        }
+    }
+    fn export_type(&mut self, index: u32, name: &'a str) -> Option<u32> {
+        match &mut self.ty {
+            Some(ty) => {
+                assert!(!self.import_types);
+                let ret = ty.type_count();
+                ty.export(name, ComponentTypeRef::Type(TypeBounds::Eq(index)));
+                Some(ret)
+            }
+            None => {
+                let ret = self.outer.type_count();
+                if self.import_types {
+                    self.outer
+                        .import(name, ComponentTypeRef::Type(TypeBounds::Eq(index)));
+                } else {
+                    self.outer
+                        .export(name, ComponentTypeRef::Type(TypeBounds::Eq(index)));
+                }
+                Some(ret)
+            }
+        }
+    }
+    fn export_resource(&mut self, name: &'a str) -> u32 {
+        let type_ref = ComponentTypeRef::Type(TypeBounds::SubResource);
+        match &mut self.ty {
+            Some(ty) => {
+                assert!(!self.import_types);
+                ty.export(name, type_ref);
+                ty.type_count() - 1
+            }
+            None => {
+                if self.import_types {
+                    self.outer.import(name, type_ref);
+                } else {
+                    self.outer.export(name, type_ref);
+                }
+                self.outer.type_count() - 1
+            }
+        }
+    }
+    fn type_map(&mut self) -> &mut HashMap<TypeId, u32> {
+        &mut self.type_map
+    }
+    fn interface(&self) -> Option<InterfaceId> {
+        self.interface
+    }
+    fn import_type(&mut self, owner: InterfaceId, id: TypeId) -> u32 {
+        let ty = &self.resolve.types[id];
+        let instance = self.import_map[&owner];
+        let outer_idx = *self.outer_type_map.entry(id).or_insert_with(|| {
+            let ret = self.outer.type_count();
+            self.outer.alias(Alias::InstanceExport {
+                instance,
+                name: ty.name.as_ref().unwrap(),
+                kind: ComponentExportKind::Type,
+            });
+            ret
+        });
+        match &mut self.ty {
+            Some(ty) => {
+                let ret = ty.type_count();
+                ty.alias(Alias::Outer {
+                    count: 1,
+                    index: outer_idx,
+                    kind: ComponentOuterAliasKind::Type,
+                });
+                ret
+            }
+            None => outer_idx,
+        }
+    }
+    fn func_type_map(&mut self) -> &mut HashMap<FunctionKey<'a>, u32> {
+        &mut self.func_type_map
+    }
+}
+
+/// Encodes a `world` as a component type.
+pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentType> {
+    let mut encoder = InterfaceEncoder::new(resolve);
+    let world = &resolve.worlds[world_id];
+    log::trace!("encoding world {}", world.name);
+
+    // This sort is similar in purpose to the sort below in
+    // `encode_instance`, but different in its sort. The purpose here is
+    // to ensure that when a document is either printed as WIT or
+    // encoded as wasm that decoding from those artifacts produces the
+    // same WIT package. Namely both encoding processes should encode
+    // things in the same order.
+    //
+    // When printing worlds in WIT freestanding function imports are
+    // printed first, then types. Resource functions are attached to
+    // types which means that they all come last. Sort all
+    // resource-related functions here to the back of the `imports` list
+    // while keeping everything else in front, using a stable sort to
+    // preserve preexisting ordering.
+    let mut imports = world.imports.iter().collect::<Vec<_>>();
+    imports.sort_by_key(|(_name, import)| match import {
+        WorldItem::Function(f) => match f.kind {
+            FunctionKind::Freestanding => 0,
+            _ => 1,
+        },
+        _ => 0,
+    });
+
+    // Encode the imports
+    for (name, import) in imports {
+        let name = resolve.name_world_key(name);
+        log::trace!("encoding import {name}");
+        let ty = match import {
+            WorldItem::Interface(i) => {
+                encoder.interface = Some(*i);
+                let idx = encoder.encode_instance(*i)?;
+                ComponentTypeRef::Instance(idx)
+            }
+            WorldItem::Function(f) => {
+                encoder.interface = None;
+                let idx = encoder.encode_func_type(resolve, f)?;
+                ComponentTypeRef::Func(idx)
+            }
+            WorldItem::Type(t) => {
+                encoder.interface = None;
+                encoder.import_types = true;
+                encoder.encode_valtype(resolve, &Type::Id(*t))?;
+                encoder.import_types = false;
+                continue;
+            }
+        };
+        encoder.outer.import(&name, ty);
+    }
+    // Encode the exports
+    for (name, export) in world.exports.iter() {
+        let name = resolve.name_world_key(name);
+        let ty = match export {
+            WorldItem::Interface(i) => {
+                encoder.interface = Some(*i);
+                let idx = encoder.encode_instance(*i)?;
+                ComponentTypeRef::Instance(idx)
+            }
+            WorldItem::Function(f) => {
+                encoder.interface = None;
+                let idx = encoder.encode_func_type(resolve, f)?;
+                ComponentTypeRef::Func(idx)
+            }
+            WorldItem::Type(_) => unreachable!(),
+        };
+        encoder.outer.export(&name, ty);
+    }
+
+    let mut component = ComponentType::new();
+    component.ty().component(&encoder.outer);
+
+    let name = match world.package {
+        Some(id) => resolve.packages[id].name.interface_id(&world.name),
+        None => world.name.clone(),
+    };
+    component.export(&name, ComponentTypeRef::Component(0));
+    Ok(component)
+}
diff --git a/crates/wit-component/src/metadata.rs b/crates/wit-component/src/metadata.rs
index a452e5ef..bb65aed6 100644
--- a/crates/wit-component/src/metadata.rs
+++ b/crates/wit-component/src/metadata.rs
@@ -176,7 +176,8 @@ pub fn encode(
     });
     world.name.encode(&mut ret);
     // This appends a wasm binary encoded Component to the ret:
-    let mut component_builder = crate::encoding::encode_component(resolve, world.package.unwrap())?;
+    let mut component_builder =
+        crate::encoding::encode_component(None, resolve, world.package.unwrap())?;
 
     let mut producers = crate::base_producers();
     if let Some(p) = extra_producers {
diff --git a/crates/wit-component/src/targets.rs b/crates/wit-component/src/targets.rs
index cfc252f2..c33062bc 100644
--- a/crates/wit-component/src/targets.rs
+++ b/crates/wit-component/src/targets.rs
@@ -16,7 +16,7 @@ pub fn targets(resolve: &Resolve, world: WorldId, component_to_test: &[u8]) -> R
     // (2) Encode the world to a component type and embed a new component which
     // imports the encoded component type.
     let test_component_idx = {
-        let component_ty = encode_world(resolve, world)?;
+        let component_ty = encode_world(None, resolve, world)?;
         let mut component = ComponentBuilder::default();
         let component_ty_idx = component.type_component(&component_ty);
         component.import(
diff --git a/crates/wit-smith/src/config.rs b/crates/wit-smith/src/config.rs
index ea837c5c..948fbb73 100644
--- a/crates/wit-smith/src/config.rs
+++ b/crates/wit-smith/src/config.rs
@@ -44,7 +44,7 @@ impl Arbitrary<'_> for Config {
             max_type_size: u.int_in_range(0..=1000)?,
             max_interface_items: u.int_in_range(0..=20)?,
             max_world_items: u.int_in_range(0..=10)?,
-            max_pkg_items: u.int_in_range(0..=10)?,
+            max_pkg_items: u.int_in_range(1..=10)?,
             max_type_parts: u.int_in_range(1..=10)?,
             max_resource_items: u.int_in_range(0..=10)?,
         })
diff --git a/crates/wit-smith/src/generate.rs b/crates/wit-smith/src/generate.rs
index 66d8a7b9..aaa64783 100644
--- a/crates/wit-smith/src/generate.rs
+++ b/crates/wit-smith/src/generate.rs
@@ -58,7 +58,7 @@ impl Generator {
     pub fn gen(&mut self, u: &mut Unstructured<'_>) -> Result<Vec<Package>> {
         let mut packages = Vec::new();
         let mut names = HashSet::new();
-        while packages.len() < self.config.max_packages && (packages.is_empty() || u.arbitrary()?) {
+        while packages.len() < self.config.max_packages && packages.is_empty() {
             let (pkg, interfaces) = self.gen_package(u, &mut names)?;
             if interfaces.len() > 0 {
                 self.packages.push((pkg.name.clone(), interfaces));
@@ -89,7 +89,7 @@ impl Generator {
             sources: SourceMap::new(),
         };
 
-        #[derive(Arbitrary)]
+        #[derive(Arbitrary, Clone)]
         enum Generate {
             Interface,
             Use,
@@ -98,11 +98,12 @@ impl Generator {
         }
 
         let mut items = 0;
+        let mut empty = true;
         let mut files = vec![File::default()];
         let mut package_names = HashSet::new();
         let mut package = File::default();
         log::debug!("===================== new package ====================");
-        while items < self.config.max_pkg_items && !u.is_empty() {
+        while items < self.config.max_pkg_items {
             items += 1;
             let max = if files.len() < self.config.max_files_per_package {
                 files.len() + 1
@@ -125,12 +126,23 @@ impl Generator {
                     files.last_mut().unwrap()
                 }
             };
-            match u.arbitrary()? {
+
+            // Only generate Use/Done if we've already generated a world or interface. This ensures
+            // that we never generate empty packages, which aren't representable.
+            let gen = if empty {
+                u.choose(&[Generate::World, Generate::Interface])?.clone()
+            } else {
+                u.arbitrary()?
+            };
+
+            match gen {
                 Generate::World => {
                     let name = file.gen_unique_package_name(u, &mut package_names)?;
                     log::debug!("new world `{name}` in {i}");
                     let world = self.gen_world(u, &name, file)?;
                     file.items.push(world);
+
+                    empty = false;
                 }
                 Generate::Interface => {
                     let name = file.gen_unique_package_name(u, &mut package_names)?;
@@ -166,6 +178,8 @@ impl Generator {
                     for file in files.iter_mut() {
                         file.insert_definition(interface.clone());
                     }
+
+                    empty = false;
                 }
                 Generate::Use => {
                     let mut piece = String::new();
diff --git a/crates/wit-smith/src/lib.rs b/crates/wit-smith/src/lib.rs
index bbd5e863..36410ada 100644
--- a/crates/wit-smith/src/lib.rs
+++ b/crates/wit-smith/src/lib.rs
@@ -38,5 +38,5 @@ pub fn smith(config: &Config, u: &mut Unstructured<'_>) -> Result<Vec<u8>> {
     }
     let pkg = last.unwrap();
 
-    Ok(wit_component::encode(&resolve, pkg).expect("failed to encode WIT document"))
+    Ok(wit_component::encode(Some(true), &resolve, pkg).expect("failed to encode WIT document"))
 }
diff --git a/fuzz/src/roundtrip_wit.rs b/fuzz/src/roundtrip_wit.rs
index 9a6c74c2..04f29249 100644
--- a/fuzz/src/roundtrip_wit.rs
+++ b/fuzz/src/roundtrip_wit.rs
@@ -15,6 +15,7 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
         DecodedWasm::WitPackage(resolve, pkg) => (resolve, pkg),
         DecodedWasm::Component(..) => unreachable!(),
     };
+
     roundtrip_through_printing("doc1", &resolve, &wasm);
 
     let (resolve2, pkg2) = match wit_component::decode(&wasm).unwrap() {
@@ -22,7 +23,8 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
         DecodedWasm::Component(..) => unreachable!(),
     };
 
-    let wasm2 = wit_component::encode(&resolve2, pkg2).expect("failed to encode WIT document");
+    let wasm2 =
+        wit_component::encode(Some(true), &resolve2, pkg2).expect("failed to encode WIT document");
     write_file("doc2.wasm", &wasm2);
     roundtrip_through_printing("doc2", &resolve2, &wasm2);
 
@@ -80,7 +82,7 @@ fn roundtrip_through_printing(file: &str, resolve: &Resolve, wasm: &[u8]) {
 
     // Finally encode the `new_resolve` which should be the exact same as
     // before.
-    let wasm2 = wit_component::encode(&new_resolve, last.unwrap()).unwrap();
+    let wasm2 = wit_component::encode(Some(true), &new_resolve, last.unwrap()).unwrap();
     write_file(&format!("{file}-reencoded.wasm"), &wasm2);
     if wasm != wasm2 {
         panic!("failed to roundtrip through text printing");
diff --git a/src/bin/wasm-tools/component.rs b/src/bin/wasm-tools/component.rs
index 0ba7aa3b..f680fb35 100644
--- a/src/bin/wasm-tools/component.rs
+++ b/src/bin/wasm-tools/component.rs
@@ -507,7 +507,7 @@ impl WitOpts {
         assert!(self.wasm || self.wat);
         assert!(self.out_dir.is_none());
 
-        let bytes = wit_component::encode(decoded.resolve(), decoded.package())?;
+        let bytes = wit_component::encode(None, decoded.resolve(), decoded.package())?;
         if !self.skip_validation {
             wasmparser::Validator::new_with_features(wasmparser::WasmFeatures {
                 component_model: true,


Test patch:
diff --git a/crates/wit-component/tests/components/error-link-duplicate-initializers/error.txt b/crates/wit-component/tests/components/error-link-duplicate-initializers/error.txt
index 86de6c15..ecf9edd3 100644
--- a/crates/wit-component/tests/components/error-link-duplicate-initializers/error.txt
+++ b/crates/wit-component/tests/components/error-link-duplicate-initializers/error.txt
@@ -1,1 +1,1 @@
-library foo exports both `__wasm_call_ctors` and `_initialize`; expected at most one of the two
+library foo exports both `__wasm_call_ctors` and `_initialize`; expected at most one of the two
\ No newline at end of file
diff --git a/crates/wit-component/tests/interfaces.rs b/crates/wit-component/tests/interfaces.rs
index 9327d60a..0fec470c 100644
--- a/crates/wit-component/tests/interfaces.rs
+++ b/crates/wit-component/tests/interfaces.rs
@@ -55,7 +55,7 @@ fn run_test(path: &Path, is_dir: bool) -> Result<()> {
     // First convert the WIT package to a binary WebAssembly output, then
     // convert that binary wasm to textual wasm, then assert it matches the
     // expectation.
-    let wasm = wit_component::encode(&resolve, package)?;
+    let wasm = wit_component::encode(Some(true), &resolve, package)?;
     let wat = wasmprinter::print_bytes(&wasm)?;
     assert_output(&path.with_extension("wat"), &wat)?;
     wasmparser::Validator::new_with_features(features)
@@ -71,7 +71,7 @@ fn run_test(path: &Path, is_dir: bool) -> Result<()> {
 
     // Finally convert the decoded package to wasm again and make sure it
     // matches the prior wasm.
-    let wasm2 = wit_component::encode(resolve, decoded.package())?;
+    let wasm2 = wit_component::encode(Some(true), resolve, decoded.package())?;
     if wasm != wasm2 {
         let wat2 = wasmprinter::print_bytes(&wasm)?;
         assert_eq!(wat, wat2, "document did not roundtrip correctly");
diff --git a/crates/wit-component/tests/interfaces/console.wat b/crates/wit-component/tests/interfaces/console.wat
index 6aa6caf4..8825a84c 100644
--- a/crates/wit-component/tests/interfaces/console.wat
+++ b/crates/wit-component/tests/interfaces/console.wat
@@ -10,7 +10,7 @@
       (export (;0;) (interface "foo:console/console") (instance (type 0)))
     )
   )
-  (export (;1;) (interface "foo:console/wit") (type 0))
+  (export (;1;) "console" (type 0))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/diamond-disambiguate.wat b/crates/wit-component/tests/interfaces/diamond-disambiguate.wat
index c7e87181..f1744b29 100644
--- a/crates/wit-component/tests/interfaces/diamond-disambiguate.wat
+++ b/crates/wit-component/tests/interfaces/diamond-disambiguate.wat
@@ -8,14 +8,24 @@
         )
       )
       (export (;0;) (interface "foo:foo/shared1") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "shared1" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (instance
           (type (;0;) u8)
           (export (;1;) "t2" (type (eq 0)))
         )
       )
-      (export (;1;) (interface "foo:foo/shared2") (instance (type 1)))
-      (type (;2;)
+      (export (;0;) (interface "foo:foo/shared2") (instance (type 0)))
+    )
+  )
+  (export (;3;) "shared2" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -49,10 +59,10 @@
           (import "bar" (instance (;3;) (type 5)))
         )
       )
-      (export (;0;) (interface "foo:foo/w1") (component (type 2)))
+      (export (;0;) (interface "foo:foo/w1") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;5;) "w1" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/diamond.wat b/crates/wit-component/tests/interfaces/diamond.wat
index ec379188..ea0da3aa 100644
--- a/crates/wit-component/tests/interfaces/diamond.wat
+++ b/crates/wit-component/tests/interfaces/diamond.wat
@@ -8,7 +8,12 @@
         )
       )
       (export (;0;) (interface "foo:foo/shared-items") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "shared-items" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -34,8 +39,13 @@
           (import "bar" (instance (;2;) (type 3)))
         )
       )
-      (export (;0;) (interface "foo:foo/w1") (component (type 1)))
-      (type (;2;)
+      (export (;0;) (interface "foo:foo/w1") (component (type 0)))
+    )
+  )
+  (export (;3;) "w1" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -61,8 +71,13 @@
           (export (;2;) "bar" (instance (type 3)))
         )
       )
-      (export (;1;) (interface "foo:foo/w2") (component (type 2)))
-      (type (;3;)
+      (export (;0;) (interface "foo:foo/w2") (component (type 0)))
+    )
+  )
+  (export (;5;) "w2" (type 4))
+  (type (;6;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -81,10 +96,10 @@
           (export (;1;) "bar" (instance (type 2)))
         )
       )
-      (export (;2;) (interface "foo:foo/w3") (component (type 3)))
+      (export (;0;) (interface "foo:foo/w3") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;7;) "w3" (type 6))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/doc-comments.wat b/crates/wit-component/tests/interfaces/doc-comments.wat
index 7f3cd033..16dfb3ae 100644
--- a/crates/wit-component/tests/interfaces/doc-comments.wat
+++ b/crates/wit-component/tests/interfaces/doc-comments.wat
@@ -26,15 +26,25 @@
         )
       )
       (export (;0;) (interface "foo:foo/coverage-iface") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "coverage-iface" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (instance
           (type (;0;) (func))
           (export (;0;) "multiple-lines-split" (func (type 0)))
           (export (;1;) "mixed-forms" (func (type 0)))
         )
       )
-      (export (;1;) (interface "foo:foo/other-comment-forms") (instance (type 1)))
-      (type (;2;)
+      (export (;0;) (interface "foo:foo/other-comment-forms") (instance (type 0)))
+    )
+  )
+  (export (;3;) "other-comment-forms" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
         (component
           (type (;0;) u32)
           (import "t" (type (;1;) (eq 0)))
@@ -52,10 +62,10 @@
           (export (;0;) "i" (instance (type 3)))
         )
       )
-      (export (;0;) (interface "foo:foo/coverage-world") (component (type 2)))
+      (export (;0;) (interface "foo:foo/coverage-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;5;) "coverage-world" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/empty.wat b/crates/wit-component/tests/interfaces/empty.wat
index 02906cca..efea26d3 100644
--- a/crates/wit-component/tests/interfaces/empty.wat
+++ b/crates/wit-component/tests/interfaces/empty.wat
@@ -5,7 +5,12 @@
         (instance)
       )
       (export (;0;) (interface "foo:empty/empty") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "empty" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance)
@@ -25,14 +30,19 @@
           (export (;3;) "empty2" (instance (type 3)))
         )
       )
-      (export (;0;) (interface "foo:empty/empty-world") (component (type 1)))
-      (type (;2;)
+      (export (;0;) (interface "foo:empty/empty-world") (component (type 0)))
+    )
+  )
+  (export (;3;) "empty-world" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
         (component)
       )
-      (export (;1;) (interface "foo:empty/actually-empty-world") (component (type 2)))
+      (export (;0;) (interface "foo:empty/actually-empty-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:empty/wit") (type 0))
+  (export (;5;) "actually-empty-world" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/export-other-packages-interface.wat b/crates/wit-component/tests/interfaces/export-other-packages-interface.wat
index e9569e89..49329a39 100644
--- a/crates/wit-component/tests/interfaces/export-other-packages-interface.wat
+++ b/crates/wit-component/tests/interfaces/export-other-packages-interface.wat
@@ -15,7 +15,7 @@
       (export (;0;) (interface "foo:foo/foo") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;1;) "foo" (type 0))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/exports.wat b/crates/wit-component/tests/interfaces/exports.wat
index 3f2bd040..99da09b4 100644
--- a/crates/wit-component/tests/interfaces/exports.wat
+++ b/crates/wit-component/tests/interfaces/exports.wat
@@ -10,7 +10,12 @@
         )
       )
       (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -23,10 +28,10 @@
           (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
         )
       )
-      (export (;0;) (interface "foo:foo/export-foo") (component (type 1)))
+      (export (;0;) (interface "foo:foo/export-foo") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;3;) "export-foo" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/flags.wat b/crates/wit-component/tests/interfaces/flags.wat
index 1c07f490..b39eee54 100644
--- a/crates/wit-component/tests/interfaces/flags.wat
+++ b/crates/wit-component/tests/interfaces/flags.wat
@@ -34,7 +34,12 @@
         )
       )
       (export (;0;) (interface "foo:flags/imports") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "imports" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -71,10 +76,10 @@
           (import (interface "foo:flags/imports") (instance (;0;) (type 0)))
         )
       )
-      (export (;0;) (interface "foo:flags/flags-world") (component (type 1)))
+      (export (;0;) (interface "foo:flags/flags-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:flags/wit") (type 0))
+  (export (;3;) "flags-world" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/floats.wat b/crates/wit-component/tests/interfaces/floats.wat
index e974ebe8..fa163945 100644
--- a/crates/wit-component/tests/interfaces/floats.wat
+++ b/crates/wit-component/tests/interfaces/floats.wat
@@ -14,7 +14,12 @@
         )
       )
       (export (;0;) (interface "foo:floats/floats") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "floats" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -31,10 +36,10 @@
           (import (interface "foo:floats/floats") (instance (;0;) (type 0)))
         )
       )
-      (export (;0;) (interface "foo:floats/floats-world") (component (type 1)))
+      (export (;0;) (interface "foo:floats/floats-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:floats/wit") (type 0))
+  (export (;3;) "floats-world" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/foreign-use-chain.wat b/crates/wit-component/tests/interfaces/foreign-use-chain.wat
index c55bb5a1..d98b07a2 100644
--- a/crates/wit-component/tests/interfaces/foreign-use-chain.wat
+++ b/crates/wit-component/tests/interfaces/foreign-use-chain.wat
@@ -23,7 +23,7 @@
       (export (;0;) (interface "foo:foo/foo") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;1;) "foo" (type 0))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/import-and-export.wat b/crates/wit-component/tests/interfaces/import-and-export.wat
index 627281ee..494f72e5 100644
--- a/crates/wit-component/tests/interfaces/import-and-export.wat
+++ b/crates/wit-component/tests/interfaces/import-and-export.wat
@@ -8,14 +8,24 @@
         )
       )
       (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (instance
           (type (;0;) (func))
           (export (;0;) "bar" (func (type 0)))
         )
       )
-      (export (;1;) (interface "foo:foo/bar") (instance (type 1)))
-      (type (;2;)
+      (export (;0;) (interface "foo:foo/bar") (instance (type 0)))
+    )
+  )
+  (export (;3;) "bar" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -33,10 +43,10 @@
           (export (;1;) (interface "foo:foo/bar") (instance (type 1)))
         )
       )
-      (export (;0;) (interface "foo:foo/import-and-export") (component (type 2)))
+      (export (;0;) (interface "foo:foo/import-and-export") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;5;) "import-and-export" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/integers.wat b/crates/wit-component/tests/interfaces/integers.wat
index a4baed89..dd55f771 100644
--- a/crates/wit-component/tests/interfaces/integers.wat
+++ b/crates/wit-component/tests/interfaces/integers.wat
@@ -45,7 +45,12 @@
         )
       )
       (export (;0;) (interface "foo:foo/integers") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "integers" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -93,10 +98,10 @@
           (import (interface "foo:foo/integers") (instance (;0;) (type 0)))
         )
       )
-      (export (;0;) (interface "foo:foo/integers-world") (component (type 1)))
+      (export (;0;) (interface "foo:foo/integers-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;3;) "integers-world" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/lists.wat b/crates/wit-component/tests/interfaces/lists.wat
index 21940bb2..5d19e477 100644
--- a/crates/wit-component/tests/interfaces/lists.wat
+++ b/crates/wit-component/tests/interfaces/lists.wat
@@ -96,7 +96,12 @@
         )
       )
       (export (;0;) (interface "foo:foo/lists") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "lists" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -195,10 +200,10 @@
           (import (interface "foo:foo/lists") (instance (;0;) (type 0)))
         )
       )
-      (export (;0;) (interface "foo:foo/lists-world") (component (type 1)))
+      (export (;0;) (interface "foo:foo/lists-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;3;) "lists-world" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/multi-doc.wat b/crates/wit-component/tests/interfaces/multi-doc.wat
index e99ce635..fff5254c 100644
--- a/crates/wit-component/tests/interfaces/multi-doc.wat
+++ b/crates/wit-component/tests/interfaces/multi-doc.wat
@@ -8,6 +8,18 @@
         )
       )
       (export (;0;) (interface "foo:foo/b") (instance (type 0)))
+    )
+  )
+  (export (;1;) "b" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) (record (field "f" u8)))
+          (export (;1;) "the-type" (type (eq 0)))
+        )
+      )
+      (import (interface "foo:foo/b") (instance (;0;) (type 0)))
       (alias export 0 "the-type" (type (;1;)))
       (type (;2;)
         (instance
@@ -16,23 +28,49 @@
         )
       )
       (export (;1;) (interface "foo:foo/a") (instance (type 2)))
-      (type (;3;)
+    )
+  )
+  (export (;3;) "a" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) (record (field "f" u8)))
+          (export (;1;) "the-type" (type (eq 0)))
+        )
+      )
+      (import (interface "foo:foo/b") (instance (;0;) (type 0)))
+      (alias export 0 "the-type" (type (;1;)))
+      (type (;2;)
         (instance
           (alias outer 1 1 (type (;0;)))
           (export (;1;) "the-type" (type (eq 0)))
         )
       )
-      (export (;2;) (interface "foo:foo/b2") (instance (type 3)))
-      (type (;4;)
+      (export (;1;) (interface "foo:foo/b2") (instance (type 2)))
+    )
+  )
+  (export (;5;) "b2" (type 4))
+  (type (;6;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) (record (field "f" u8)))
+          (export (;1;) "the-type" (type (eq 0)))
+        )
+      )
+      (import (interface "foo:foo/b") (instance (;0;) (type 0)))
+      (alias export 0 "the-type" (type (;1;)))
+      (type (;2;)
         (instance
           (alias outer 1 1 (type (;0;)))
           (export (;1;) "the-type" (type (eq 0)))
         )
       )
-      (export (;3;) (interface "foo:foo/a2") (instance (type 4)))
+      (export (;1;) (interface "foo:foo/a2") (instance (type 2)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;7;) "a2" (type 6))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/multiple-use.wat b/crates/wit-component/tests/interfaces/multiple-use.wat
index 38eff77f..adab86d9 100644
--- a/crates/wit-component/tests/interfaces/multiple-use.wat
+++ b/crates/wit-component/tests/interfaces/multiple-use.wat
@@ -10,13 +10,39 @@
         )
       )
       (export (;0;) (interface "foo:multiuse/foo") (instance (type 0)))
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) u8)
+          (export (;1;) "u" (type (eq 0)))
+        )
+      )
+      (export (;0;) (interface "foo:multiuse/bar") (instance (type 0)))
+    )
+  )
+  (export (;3;) "bar" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) u8)
+          (export (;1;) "t1" (type (eq 0)))
+          (type (;2;) u8)
+          (export (;3;) "t2" (type (eq 2)))
+        )
+      )
+      (import (interface "foo:multiuse/foo") (instance (;0;) (type 0)))
       (type (;1;)
         (instance
           (type (;0;) u8)
           (export (;1;) "u" (type (eq 0)))
         )
       )
-      (export (;1;) (interface "foo:multiuse/bar") (instance (type 1)))
+      (import (interface "foo:multiuse/bar") (instance (;1;) (type 1)))
       (alias export 0 "t1" (type (;2;)))
       (alias export 1 "u" (type (;3;)))
       (alias export 0 "t2" (type (;4;)))
@@ -33,7 +59,7 @@
       (export (;2;) (interface "foo:multiuse/baz") (instance (type 5)))
     )
   )
-  (export (;1;) (interface "foo:multiuse/wit") (type 0))
+  (export (;5;) "baz" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain.wat b/crates/wit-component/tests/interfaces/pkg-use-chain.wat
index 3271c3f4..4c02b18f 100644
--- a/crates/wit-component/tests/interfaces/pkg-use-chain.wat
+++ b/crates/wit-component/tests/interfaces/pkg-use-chain.wat
@@ -8,6 +8,18 @@
         )
       )
       (export (;0;) (interface "foo:chain/a") (instance (type 0)))
+    )
+  )
+  (export (;1;) "a" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) u8)
+          (export (;1;) "a" (type (eq 0)))
+        )
+      )
+      (import (interface "foo:chain/a") (instance (;0;) (type 0)))
       (alias export 0 "a" (type (;1;)))
       (type (;2;)
         (instance
@@ -18,6 +30,28 @@
         )
       )
       (export (;1;) (interface "foo:chain/def") (instance (type 2)))
+    )
+  )
+  (export (;3;) "def" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) u8)
+          (export (;1;) "a" (type (eq 0)))
+        )
+      )
+      (import (interface "foo:chain/a") (instance (;0;) (type 0)))
+      (alias export 0 "a" (type (;1;)))
+      (type (;2;)
+        (instance
+          (alias outer 1 1 (type (;0;)))
+          (export (;1;) "a" (type (eq 0)))
+          (type (;2;) (enum "other"))
+          (export (;3;) "name" (type (eq 2)))
+        )
+      )
+      (import (interface "foo:chain/def") (instance (;1;) (type 2)))
       (alias export 1 "name" (type (;3;)))
       (type (;4;)
         (instance
@@ -28,7 +62,7 @@
       (export (;2;) (interface "foo:chain/foo") (instance (type 4)))
     )
   )
-  (export (;1;) (interface "foo:chain/wit") (type 0))
+  (export (;5;) "foo" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/pkg-use-chain2.wat b/crates/wit-component/tests/interfaces/pkg-use-chain2.wat
index 65c10e61..cded6090 100644
--- a/crates/wit-component/tests/interfaces/pkg-use-chain2.wat
+++ b/crates/wit-component/tests/interfaces/pkg-use-chain2.wat
@@ -8,6 +8,18 @@
         )
       )
       (export (;0;) (interface "foo:foo/other") (instance (type 0)))
+    )
+  )
+  (export (;1;) "other" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) (record (field "f" u8)))
+          (export (;1;) "name" (type (eq 0)))
+        )
+      )
+      (import (interface "foo:foo/other") (instance (;0;) (type 0)))
       (alias export 0 "name" (type (;1;)))
       (type (;2;)
         (instance
@@ -18,6 +30,28 @@
         )
       )
       (export (;1;) (interface "foo:foo/bar") (instance (type 2)))
+    )
+  )
+  (export (;3;) "bar" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) (record (field "f" u8)))
+          (export (;1;) "name" (type (eq 0)))
+        )
+      )
+      (import (interface "foo:foo/other") (instance (;0;) (type 0)))
+      (alias export 0 "name" (type (;1;)))
+      (type (;2;)
+        (instance
+          (alias outer 1 1 (type (;0;)))
+          (export (;1;) "the-name" (type (eq 0)))
+          (type (;2;) (enum "a"))
+          (export (;3;) "name" (type (eq 2)))
+        )
+      )
+      (import (interface "foo:foo/bar") (instance (;1;) (type 2)))
       (alias export 1 "the-name" (type (;3;)))
       (type (;4;)
         (instance
@@ -28,7 +62,7 @@
       (export (;2;) (interface "foo:foo/foo") (instance (type 4)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;5;) "foo" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat b/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat
index 41d21f3a..9c3d93b7 100644
--- a/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat
+++ b/crates/wit-component/tests/interfaces/preserve-dep-type-order.wat
@@ -18,7 +18,12 @@
         )
       )
       (export (;1;) (interface "foo:foo/foo") (instance (type 2)))
-      (type (;3;)
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -31,10 +36,10 @@
           (import (interface "foo:dep/foo") (instance (;0;) (type 0)))
         )
       )
-      (export (;0;) (interface "foo:foo/bar") (component (type 3)))
+      (export (;0;) (interface "foo:foo/bar") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;3;) "bar" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat b/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat
index e82cad59..736988e6 100644
--- a/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat
+++ b/crates/wit-component/tests/interfaces/preserve-foreign-reexport.wat
@@ -16,7 +16,7 @@
       (export (;0;) (interface "foo:foo/foo") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;1;) "foo" (type 0))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/print-keyword.wat b/crates/wit-component/tests/interfaces/print-keyword.wat
index 742b8644..5619770f 100644
--- a/crates/wit-component/tests/interfaces/print-keyword.wat
+++ b/crates/wit-component/tests/interfaces/print-keyword.wat
@@ -13,7 +13,7 @@
       (export (;0;) (interface "foo:foo/interface") (instance (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;1;) "interface" (type 0))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/records.wat b/crates/wit-component/tests/interfaces/records.wat
index c5d7d31e..3f76796c 100644
--- a/crates/wit-component/tests/interfaces/records.wat
+++ b/crates/wit-component/tests/interfaces/records.wat
@@ -41,7 +41,12 @@
         )
       )
       (export (;0;) (interface "foo:records/records") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "records" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -125,10 +130,10 @@
           (export (;1;) (interface "foo:records/records") (instance (type 1)))
         )
       )
-      (export (;0;) (interface "foo:records/records-world") (component (type 1)))
+      (export (;0;) (interface "foo:records/records-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:records/wit") (type 0))
+  (export (;3;) "records-world" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/reference-out-of-order.wat b/crates/wit-component/tests/interfaces/reference-out-of-order.wat
index 81f9af8f..13573eae 100644
--- a/crates/wit-component/tests/interfaces/reference-out-of-order.wat
+++ b/crates/wit-component/tests/interfaces/reference-out-of-order.wat
@@ -22,7 +22,12 @@
         )
       )
       (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -47,10 +52,10 @@
           (import (interface "foo:foo/foo") (instance (;0;) (type 0)))
         )
       )
-      (export (;0;) (interface "foo:foo/foo-world") (component (type 1)))
+      (export (;0;) (interface "foo:foo/foo-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;3;) "foo-world" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/resources.wat b/crates/wit-component/tests/interfaces/resources.wat
index ccc47625..b95fa83d 100644
--- a/crates/wit-component/tests/interfaces/resources.wat
+++ b/crates/wit-component/tests/interfaces/resources.wat
@@ -20,6 +20,20 @@
         )
       )
       (export (;0;) (interface "foo:bar/foo") (instance (type 0)))
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
+        (instance
+          (export (;0;) "bar" (type (sub resource)))
+          (export (;1;) "t" (type (eq 0)))
+          (type (;2;) (own 0))
+          (export (;3;) "t2" (type (eq 2)))
+        )
+      )
+      (import (interface "foo:bar/foo") (instance (;0;) (type 0)))
       (alias export 0 "bar" (type (;1;)))
       (alias export 0 "t" (type (;2;)))
       (type (;3;)
@@ -37,7 +51,12 @@
         )
       )
       (export (;1;) (interface "foo:bar/baz") (instance (type 3)))
-      (type (;4;)
+    )
+  )
+  (export (;3;) "baz" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
         (instance
           (export (;0;) "a" (type (sub resource)))
           (type (;1;) (own 0))
@@ -48,8 +67,13 @@
           (export (;1;) "c" (func (type 4)))
         )
       )
-      (export (;2;) (interface "foo:bar/implicit-own-handles") (instance (type 4)))
-      (type (;5;)
+      (export (;0;) (interface "foo:bar/implicit-own-handles") (instance (type 0)))
+    )
+  )
+  (export (;5;) "implicit-own-handles" (type 4))
+  (type (;6;)
+    (component
+      (type (;0;)
         (instance
           (export (;0;) "a" (type (sub resource)))
           (export (;1;) "b" (type (sub resource)))
@@ -67,8 +91,13 @@
           (export (;2;) "[static]c.a" (func (type 10)))
         )
       )
-      (export (;3;) (interface "foo:bar/implicit-own-handles2") (instance (type 5)))
-      (type (;6;)
+      (export (;0;) (interface "foo:bar/implicit-own-handles2") (instance (type 0)))
+    )
+  )
+  (export (;7;) "implicit-own-handles2" (type 6))
+  (type (;8;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -132,8 +161,13 @@
           (export (;2;) "y" (func (type 11)))
         )
       )
-      (export (;0;) (interface "foo:bar/some-world") (component (type 6)))
-      (type (;7;)
+      (export (;0;) (interface "foo:bar/some-world") (component (type 0)))
+    )
+  )
+  (export (;9;) "some-world" (type 8))
+  (type (;10;)
+    (component
+      (type (;0;)
         (component
           (import "a" (type (;0;) (sub resource)))
           (type (;1;) (own 0))
@@ -142,10 +176,10 @@
           (import "[constructor]a" (func (;0;) (type 3)))
         )
       )
-      (export (;1;) (interface "foo:bar/implicit-own-handles3") (component (type 7)))
+      (export (;0;) (interface "foo:bar/implicit-own-handles3") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:bar/wit") (type 0))
+  (export (;11;) "implicit-own-handles3" (type 10))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/simple-deps.wat b/crates/wit-component/tests/interfaces/simple-deps.wat
index 66f3bfca..d8730975 100644
--- a/crates/wit-component/tests/interfaces/simple-deps.wat
+++ b/crates/wit-component/tests/interfaces/simple-deps.wat
@@ -18,7 +18,7 @@
       (export (;1;) (interface "foo:foo/foo") (instance (type 2)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;1;) "foo" (type 0))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/simple-multi.wat b/crates/wit-component/tests/interfaces/simple-multi.wat
index 2a0222d1..fabd6da4 100644
--- a/crates/wit-component/tests/interfaces/simple-multi.wat
+++ b/crates/wit-component/tests/interfaces/simple-multi.wat
@@ -5,13 +5,18 @@
         (instance)
       )
       (export (;0;) (interface "foo:foo/bar") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "bar" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (instance)
       )
-      (export (;1;) (interface "foo:foo/foo") (instance (type 1)))
+      (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;3;) "foo" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/simple-use.wat b/crates/wit-component/tests/interfaces/simple-use.wat
index caf6e5fe..f1dcfcb8 100644
--- a/crates/wit-component/tests/interfaces/simple-use.wat
+++ b/crates/wit-component/tests/interfaces/simple-use.wat
@@ -8,6 +8,18 @@
         )
       )
       (export (;0;) (interface "foo:foo/types") (instance (type 0)))
+    )
+  )
+  (export (;1;) "types" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) (enum "info" "debug"))
+          (export (;1;) "level" (type (eq 0)))
+        )
+      )
+      (import (interface "foo:foo/types") (instance (;0;) (type 0)))
       (alias export 0 "level" (type (;1;)))
       (type (;2;)
         (instance
@@ -20,7 +32,7 @@
       (export (;1;) (interface "foo:foo/console") (instance (type 2)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;3;) "console" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/simple-world.wat b/crates/wit-component/tests/interfaces/simple-world.wat
index 1354327a..a7dd0472 100644
--- a/crates/wit-component/tests/interfaces/simple-world.wat
+++ b/crates/wit-component/tests/interfaces/simple-world.wat
@@ -8,7 +8,12 @@
         )
       )
       (export (;0;) (interface "foo:foo/console") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "console" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -19,10 +24,10 @@
           (import (interface "foo:foo/console") (instance (;0;) (type 0)))
         )
       )
-      (export (;0;) (interface "foo:foo/the-world") (component (type 1)))
+      (export (;0;) (interface "foo:foo/the-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;3;) "the-world" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/single-named-result.wat b/crates/wit-component/tests/interfaces/single-named-result.wat
index 980b3361..c7398bb7 100644
--- a/crates/wit-component/tests/interfaces/single-named-result.wat
+++ b/crates/wit-component/tests/interfaces/single-named-result.wat
@@ -10,7 +10,7 @@
       (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;1;) "foo" (type 0))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/type-alias.wat b/crates/wit-component/tests/interfaces/type-alias.wat
index 23c38d4b..5bb85d88 100644
--- a/crates/wit-component/tests/interfaces/type-alias.wat
+++ b/crates/wit-component/tests/interfaces/type-alias.wat
@@ -11,7 +11,12 @@
         )
       )
       (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -35,10 +40,10 @@
           (export (;1;) (interface "foo:foo/foo") (instance (type 1)))
         )
       )
-      (export (;0;) (interface "foo:foo/my-world") (component (type 1)))
+      (export (;0;) (interface "foo:foo/my-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;3;) "my-world" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/type-alias2.wat b/crates/wit-component/tests/interfaces/type-alias2.wat
index 85d2d1f0..11306474 100644
--- a/crates/wit-component/tests/interfaces/type-alias2.wat
+++ b/crates/wit-component/tests/interfaces/type-alias2.wat
@@ -11,7 +11,12 @@
         )
       )
       (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -25,10 +30,10 @@
           (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
         )
       )
-      (export (;0;) (interface "foo:foo/my-world") (component (type 1)))
+      (export (;0;) (interface "foo:foo/my-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;3;) "my-world" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat b/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat
index 22c03c3a..9f1cf07a 100644
--- a/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat
+++ b/crates/wit-component/tests/interfaces/upstream-deps-same-name.wat
@@ -28,7 +28,7 @@
       (export (;2;) (interface "foo:foo/a") (instance (type 4)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;1;) "a" (type 0))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/use-chain.wat b/crates/wit-component/tests/interfaces/use-chain.wat
index e555b67a..7c417336 100644
--- a/crates/wit-component/tests/interfaces/use-chain.wat
+++ b/crates/wit-component/tests/interfaces/use-chain.wat
@@ -10,6 +10,20 @@
         )
       )
       (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) u32)
+          (export (;1;) "a" (type (eq 0)))
+          (export (;2;) "b" (type (eq 1)))
+          (export (;3;) "c" (type (eq 2)))
+        )
+      )
+      (import (interface "foo:foo/foo") (instance (;0;) (type 0)))
       (alias export 0 "c" (type (;1;)))
       (type (;2;)
         (instance
@@ -18,6 +32,28 @@
         )
       )
       (export (;1;) (interface "foo:foo/bar") (instance (type 2)))
+    )
+  )
+  (export (;3;) "bar" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) u32)
+          (export (;1;) "a" (type (eq 0)))
+          (export (;2;) "b" (type (eq 1)))
+          (export (;3;) "c" (type (eq 2)))
+        )
+      )
+      (import (interface "foo:foo/foo") (instance (;0;) (type 0)))
+      (alias export 0 "c" (type (;1;)))
+      (type (;2;)
+        (instance
+          (alias outer 1 1 (type (;0;)))
+          (export (;1;) "c" (type (eq 0)))
+        )
+      )
+      (import (interface "foo:foo/bar") (instance (;1;) (type 2)))
       (alias export 1 "c" (type (;3;)))
       (type (;4;)
         (instance
@@ -28,7 +64,7 @@
       (export (;2;) (interface "foo:foo/baz") (instance (type 4)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;5;) "baz" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/use-for-type.wat b/crates/wit-component/tests/interfaces/use-for-type.wat
index dd19b865..a6f44949 100644
--- a/crates/wit-component/tests/interfaces/use-for-type.wat
+++ b/crates/wit-component/tests/interfaces/use-for-type.wat
@@ -5,26 +5,43 @@
         (instance)
       )
       (export (;0;) (interface "foo:foo/foo") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) u8)
+          (export (;1;) "t" (type (eq 0)))
+        )
+      )
+      (export (;0;) (interface "foo:foo/bar") (instance (type 0)))
+    )
+  )
+  (export (;3;) "bar" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
         (instance
           (type (;0;) u8)
           (export (;1;) "t" (type (eq 0)))
         )
       )
-      (export (;1;) (interface "foo:foo/bar") (instance (type 1)))
-      (alias export 1 "t" (type (;2;)))
-      (type (;3;)
+      (import (interface "foo:foo/bar") (instance (;0;) (type 0)))
+      (alias export 0 "t" (type (;1;)))
+      (type (;2;)
         (instance
-          (alias outer 1 2 (type (;0;)))
+          (alias outer 1 1 (type (;0;)))
           (export (;1;) "t" (type (eq 0)))
           (type (;2;) (record (field "a" 1)))
           (export (;3;) "bar" (type (eq 2)))
         )
       )
-      (export (;2;) (interface "foo:foo/baz") (instance (type 3)))
+      (export (;1;) (interface "foo:foo/baz") (instance (type 2)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;5;) "baz" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/variants.wat b/crates/wit-component/tests/interfaces/variants.wat
index a239f02a..2061db28 100644
--- a/crates/wit-component/tests/interfaces/variants.wat
+++ b/crates/wit-component/tests/interfaces/variants.wat
@@ -89,7 +89,12 @@
         )
       )
       (export (;0;) (interface "foo:variants/variants") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "variants" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -181,10 +186,10 @@
           (import (interface "foo:variants/variants") (instance (;0;) (type 0)))
         )
       )
-      (export (;0;) (interface "foo:variants/variants-world") (component (type 1)))
+      (export (;0;) (interface "foo:variants/variants-world") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:variants/wit") (type 0))
+  (export (;3;) "variants-world" (type 2))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/wasi-http.wat b/crates/wit-component/tests/interfaces/wasi-http.wat
index 64424876..2a9dce8e 100644
--- a/crates/wit-component/tests/interfaces/wasi-http.wat
+++ b/crates/wit-component/tests/interfaces/wasi-http.wat
@@ -139,6 +139,74 @@
         )
       )
       (export (;2;) (interface "wasi:http/types") (instance (type 5)))
+    )
+  )
+  (export (;1;) "types" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) u32)
+          (export (;1;) "pollable" (type (eq 0)))
+        )
+      )
+      (import (interface "wasi:poll/poll") (instance (;0;) (type 0)))
+      (alias export 0 "pollable" (type (;1;)))
+      (type (;2;)
+        (instance
+          (alias outer 1 1 (type (;0;)))
+          (export (;1;) "pollable" (type (eq 0)))
+          (type (;2;) (record (field "f" u8)))
+          (export (;3;) "stream-error" (type (eq 2)))
+          (type (;4;) u32)
+          (export (;5;) "input-stream" (type (eq 4)))
+          (type (;6;) u32)
+          (export (;7;) "output-stream" (type (eq 6)))
+        )
+      )
+      (import (interface "wasi:io/streams") (instance (;1;) (type 2)))
+      (alias export 1 "input-stream" (type (;3;)))
+      (alias export 1 "output-stream" (type (;4;)))
+      (type (;5;)
+        (instance
+          (alias outer 1 3 (type (;0;)))
+          (export (;1;) "input-stream" (type (eq 0)))
+          (alias outer 1 4 (type (;2;)))
+          (export (;3;) "output-stream" (type (eq 2)))
+          (alias outer 1 1 (type (;4;)))
+          (export (;5;) "pollable" (type (eq 4)))
+          (type (;6;) (variant (case "get") (case "head") (case "post") (case "put") (case "delete") (case "connect") (case "options") (case "trace") (case "patch") (case "other" string)))
+          (export (;7;) "method" (type (eq 6)))
+          (type (;8;) (variant (case "HTTP") (case "HTTPS") (case "other" string)))
+          (export (;9;) "scheme" (type (eq 8)))
+          (type (;10;) (variant (case "invalid-url" string) (case "timeout-error" string) (case "protocol-error" string) (case "unexpected-error" string)))
+          (export (;11;) "error" (type (eq 10)))
+          (type (;12;) u32)
+          (export (;13;) "fields" (type (eq 12)))
+          (export (;14;) "headers" (type (eq 13)))
+          (export (;15;) "trailers" (type (eq 13)))
+          (export (;16;) "incoming-stream" (type (eq 1)))
+          (export (;17;) "outgoing-stream" (type (eq 3)))
+          (type (;18;) u32)
+          (export (;19;) "incoming-request" (type (eq 18)))
+          (type (;20;) u32)
+          (export (;21;) "outgoing-request" (type (eq 20)))
+          (type (;22;) (option u32))
+          (type (;23;) (record (field "connect-timeout-ms" 22) (field "first-byte-timeout-ms" 22) (field "between-bytes-timeout-ms" 22)))
+          (export (;24;) "request-options" (type (eq 23)))
+          (type (;25;) u32)
+          (export (;26;) "response-outparam" (type (eq 25)))
+          (type (;27;) u16)
+          (export (;28;) "status-code" (type (eq 27)))
+          (type (;29;) u32)
+          (export (;30;) "incoming-response" (type (eq 29)))
+          (type (;31;) u32)
+          (export (;32;) "outgoing-response" (type (eq 31)))
+          (type (;33;) u32)
+          (export (;34;) "future-incoming-response" (type (eq 33)))
+        )
+      )
+      (import (interface "wasi:http/types") (instance (;2;) (type 5)))
       (alias export 2 "incoming-request" (type (;6;)))
       (alias export 2 "response-outparam" (type (;7;)))
       (type (;8;)
@@ -152,24 +220,97 @@
         )
       )
       (export (;3;) (interface "wasi:http/incoming-handler") (instance (type 8)))
-      (alias export 2 "outgoing-request" (type (;9;)))
-      (alias export 2 "request-options" (type (;10;)))
-      (alias export 2 "future-incoming-response" (type (;11;)))
-      (type (;12;)
+    )
+  )
+  (export (;3;) "incoming-handler" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) u32)
+          (export (;1;) "pollable" (type (eq 0)))
+        )
+      )
+      (import (interface "wasi:poll/poll") (instance (;0;) (type 0)))
+      (alias export 0 "pollable" (type (;1;)))
+      (type (;2;)
+        (instance
+          (alias outer 1 1 (type (;0;)))
+          (export (;1;) "pollable" (type (eq 0)))
+          (type (;2;) (record (field "f" u8)))
+          (export (;3;) "stream-error" (type (eq 2)))
+          (type (;4;) u32)
+          (export (;5;) "input-stream" (type (eq 4)))
+          (type (;6;) u32)
+          (export (;7;) "output-stream" (type (eq 6)))
+        )
+      )
+      (import (interface "wasi:io/streams") (instance (;1;) (type 2)))
+      (alias export 1 "input-stream" (type (;3;)))
+      (alias export 1 "output-stream" (type (;4;)))
+      (type (;5;)
+        (instance
+          (alias outer 1 3 (type (;0;)))
+          (export (;1;) "input-stream" (type (eq 0)))
+          (alias outer 1 4 (type (;2;)))
+          (export (;3;) "output-stream" (type (eq 2)))
+          (alias outer 1 1 (type (;4;)))
+          (export (;5;) "pollable" (type (eq 4)))
+          (type (;6;) (variant (case "get") (case "head") (case "post") (case "put") (case "delete") (case "connect") (case "options") (case "trace") (case "patch") (case "other" string)))
+          (export (;7;) "method" (type (eq 6)))
+          (type (;8;) (variant (case "HTTP") (case "HTTPS") (case "other" string)))
+          (export (;9;) "scheme" (type (eq 8)))
+          (type (;10;) (variant (case "invalid-url" string) (case "timeout-error" string) (case "protocol-error" string) (case "unexpected-error" string)))
+          (export (;11;) "error" (type (eq 10)))
+          (type (;12;) u32)
+          (export (;13;) "fields" (type (eq 12)))
+          (export (;14;) "headers" (type (eq 13)))
+          (export (;15;) "trailers" (type (eq 13)))
+          (export (;16;) "incoming-stream" (type (eq 1)))
+          (export (;17;) "outgoing-stream" (type (eq 3)))
+          (type (;18;) u32)
+          (export (;19;) "incoming-request" (type (eq 18)))
+          (type (;20;) u32)
+          (export (;21;) "outgoing-request" (type (eq 20)))
+          (type (;22;) (option u32))
+          (type (;23;) (record (field "connect-timeout-ms" 22) (field "first-byte-timeout-ms" 22) (field "between-bytes-timeout-ms" 22)))
+          (export (;24;) "request-options" (type (eq 23)))
+          (type (;25;) u32)
+          (export (;26;) "response-outparam" (type (eq 25)))
+          (type (;27;) u16)
+          (export (;28;) "status-code" (type (eq 27)))
+          (type (;29;) u32)
+          (export (;30;) "incoming-response" (type (eq 29)))
+          (type (;31;) u32)
+          (export (;32;) "outgoing-response" (type (eq 31)))
+          (type (;33;) u32)
+          (export (;34;) "future-incoming-response" (type (eq 33)))
+        )
+      )
+      (import (interface "wasi:http/types") (instance (;2;) (type 5)))
+      (alias export 2 "outgoing-request" (type (;6;)))
+      (alias export 2 "request-options" (type (;7;)))
+      (alias export 2 "future-incoming-response" (type (;8;)))
+      (type (;9;)
         (instance
-          (alias outer 1 9 (type (;0;)))
+          (alias outer 1 6 (type (;0;)))
           (export (;1;) "outgoing-request" (type (eq 0)))
-          (alias outer 1 10 (type (;2;)))
+          (alias outer 1 7 (type (;2;)))
           (export (;3;) "request-options" (type (eq 2)))
-          (alias outer 1 11 (type (;4;)))
+          (alias outer 1 8 (type (;4;)))
           (export (;5;) "future-incoming-response" (type (eq 4)))
           (type (;6;) (option 3))
           (type (;7;) (func (param "request" 1) (param "options" 6) (result 5)))
           (export (;0;) "handle" (func (type 7)))
         )
       )
-      (export (;4;) (interface "wasi:http/outgoing-handler") (instance (type 12)))
-      (type (;13;)
+      (export (;3;) (interface "wasi:http/outgoing-handler") (instance (type 9)))
+    )
+  )
+  (export (;5;) "outgoing-handler" (type 4))
+  (type (;6;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -400,10 +541,10 @@
           (export (;6;) (interface "wasi:http/incoming-handler") (instance (type 14)))
         )
       )
-      (export (;0;) (interface "wasi:http/proxy") (component (type 13)))
+      (export (;0;) (interface "wasi:http/proxy") (component (type 0)))
     )
   )
-  (export (;1;) (interface "wasi:http/wit") (type 0))
+  (export (;7;) "proxy" (type 6))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/world-inline-interface.wat b/crates/wit-component/tests/interfaces/world-inline-interface.wat
index 77c67eb9..bfed860d 100644
--- a/crates/wit-component/tests/interfaces/world-inline-interface.wat
+++ b/crates/wit-component/tests/interfaces/world-inline-interface.wat
@@ -16,7 +16,7 @@
       (export (;0;) (interface "foo:foo/has-inline") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;1;) "has-inline" (type 0))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/world-pkg-conflict.wat b/crates/wit-component/tests/interfaces/world-pkg-conflict.wat
index fbd7e839..c0a4611c 100644
--- a/crates/wit-component/tests/interfaces/world-pkg-conflict.wat
+++ b/crates/wit-component/tests/interfaces/world-pkg-conflict.wat
@@ -8,6 +8,18 @@
         )
       )
       (export (;0;) (interface "foo:foo/a") (instance (type 0)))
+    )
+  )
+  (export (;1;) "a" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
+        (instance
+          (type (;0;) u32)
+          (export (;1;) "t" (type (eq 0)))
+        )
+      )
+      (import (interface "foo:foo/a") (instance (;0;) (type 0)))
       (alias export 0 "t" (type (;1;)))
       (type (;2;)
         (instance
@@ -16,13 +28,18 @@
         )
       )
       (export (;1;) (interface "foo:foo/foo") (instance (type 2)))
-      (type (;3;)
+    )
+  )
+  (export (;3;) "foo" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
         (component)
       )
-      (export (;0;) (interface "foo:foo/c") (component (type 3)))
+      (export (;0;) (interface "foo:foo/c") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;5;) "c" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/world-top-level.wat b/crates/wit-component/tests/interfaces/world-top-level.wat
index 901850f3..1bd285cf 100644
--- a/crates/wit-component/tests/interfaces/world-top-level.wat
+++ b/crates/wit-component/tests/interfaces/world-top-level.wat
@@ -21,23 +21,33 @@
         )
       )
       (export (;0;) (interface "foo:foo/foo") (component (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "foo" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;) (func))
           (import "foo" (func (;0;) (type 0)))
         )
       )
-      (export (;1;) (interface "foo:foo/just-import") (component (type 1)))
-      (type (;2;)
+      (export (;0;) (interface "foo:foo/just-import") (component (type 0)))
+    )
+  )
+  (export (;3;) "just-import" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
         (component
           (type (;0;) (func))
           (export (;0;) "foo" (func (type 0)))
         )
       )
-      (export (;2;) (interface "foo:foo/just-export") (component (type 2)))
+      (export (;0;) (interface "foo:foo/just-export") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;5;) "just-export" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )
diff --git a/crates/wit-component/tests/interfaces/worlds-with-types.wat b/crates/wit-component/tests/interfaces/worlds-with-types.wat
index 4175e4f4..4a983c2b 100644
--- a/crates/wit-component/tests/interfaces/worlds-with-types.wat
+++ b/crates/wit-component/tests/interfaces/worlds-with-types.wat
@@ -8,7 +8,12 @@
         )
       )
       (export (;0;) (interface "foo:foo/import-me") (instance (type 0)))
-      (type (;1;)
+    )
+  )
+  (export (;1;) "import-me" (type 0))
+  (type (;2;)
+    (component
+      (type (;0;)
         (component
           (type (;0;) (record (field "f" u8)))
           (import "foo" (type (;1;) (eq 0)))
@@ -18,8 +23,13 @@
           (export (;1;) "b" (func (type 3)))
         )
       )
-      (export (;0;) (interface "foo:foo/simple") (component (type 1)))
-      (type (;2;)
+      (export (;0;) (interface "foo:foo/simple") (component (type 0)))
+    )
+  )
+  (export (;3;) "simple" (type 2))
+  (type (;4;)
+    (component
+      (type (;0;)
         (component
           (type (;0;)
             (instance
@@ -35,10 +45,10 @@
           (export (;1;) "b" (func (type 3)))
         )
       )
-      (export (;1;) (interface "foo:foo/with-imports") (component (type 2)))
+      (export (;0;) (interface "foo:foo/with-imports") (component (type 0)))
     )
   )
-  (export (;1;) (interface "foo:foo/wit") (type 0))
+  (export (;5;) "with-imports" (type 4))
   (@producers
     (processed-by "wit-component" "$CARGO_PKG_VERSION")
   )