Repository: bytecodealliance/wasm-tools
Pull request #1992 (2025-02-02 16:50:57)

Fixed length list support
Implement fixed length list support as defined in https://github.com/WebAssembly/component-model/pull/384

 - [X] wit-parser
 - [X] wasm-encoder
 - [X] wasmparser
 - [X] wasmprinter
 - [X] wat
 - [X] wit-encoder
 - [X] wit-smith

cpetig: Fixed size lists became a separate type because they have a different ABI representation and map to different Rust/C types.
alexcrichton: Also, as a possible bikeshed, which you can take or leave, in Rust at least there's the term "slice" which is `&[T]` which is sort of like a WIT "list", and in Rust the term for `[T; N]` is "array" which could possibly be used here instead of "fixed size list". It's easy to confuse "list" and "array" though and harder to confuse "fixed sized list" and "list". The downside of "fixed size list" is that it's a bit of a mouthful to say and type
cpetig: @alexcrichton do you prefer me to resolve the ones I implemented or do you want to check first?

I will implement wat roundtrip tests later today (I didn't find them although I did one manually) and think about limiting on-stack elements.
cpetig: > Also with the new support in `wit-smith` (thanks!) mind running the fuzzer for a few minutes locally to ensure it doesn't turn up anything? (`FUZZER=roundtrip_wit cargo +nightly fuzz run -s none run -j30`)

It found something ;-) 
`Fixed size lists require the component model fixed size list feature (at offset 0x26)`
so I need to figure out where to activate this feature inside the fuzzer.
cpetig: > I need to figure out where to activate this feature inside the fuzzer.

The default Validator used for the component encoder has this feature disabled (as it is correctly disabled by default), I don't see an easy way to only activate it for the WIT fuzzing, is there a secret environment variable?
cpetig: > Thanks for this!

Thank you for your in-depth review!

>     * Tests for `list<ty, 10000000000000000>` (something out of the 64-bit range but still looks integer-like)

I tried but wasn't able to figure out the right way to set up this test: https://github.com/bytecodealliance/wasm-tools/pull/1992/files#diff-1532b9f29c0a59c8d44ce87b39476ec5242d1b2a2329e0b72bf7b2f23c2ae485R24-R38
alexcrichton: > do you prefer me to resolve the ones I implemented or do you want to check first?

Feel free to do so yourself, I'll give the code a once-over anyway once it's ready too.

> The default Validator used for the component encoder has this feature disabled (as it is correctly disabled by default), I don't see an easy way to only activate it for the WIT fuzzing, is there a secret environment variable?

For this I'd recommend in the various locations validation is performed for tests/etc to just enable the new feature unconditionally. Adding for example `Validator::new_with_features(WasmFeatures::all())` I think is reasonable since the validation in the tooling is mostly test assertions and we want to exercise it all during fuzzing anyway.

> I tried but wasn't able to figure out the right way to set up this test

Ah yeah it's a lexical error right in `*.wat` if the integer literal is out-of-bounds so I think it's reasonable to skip the `*.wat` test, but I think `*.wit` may want to be tested? It might also be reasonable to just leave the `*.wat` test around to ensure that some error message comes out, and it'd use `assert_malformed` I think or whatever directive supports `module quote ...`
alexcrichton: I've added a merge commit here which resolves the conflicts with https://github.com/bytecodealliance/wasm-tools/pull/2096, but feel free to discard that if you'd like.
cpetig: Oh, dear, I got a first hand impression on why I should get this merged soon … adding fixed size lists to wit-bindgen is moderate effort, but to run any runtime test you need to add support for the extension to wasm-component-ld (shipped with the Rust compiler), wac, and wasmtime.

And this is the improved situation after Alex simplified the runtime test to no longer require full support on the host (wasmtime) side.
cpetig: > > Thanks for this!
> 
> Thank you for your in-depth review!
> 
> > ```
> > * Tests for `list<ty, 10000000000000000>` (something out of the 64-bit range but still looks integer-like)
> > ```
> 
> I tried but wasn't able to figure out the right way to set up this test: https://github.com/bytecodealliance/wasm-tools/pull/1992/files#diff-1532b9f29c0a59c8d44ce87b39476ec5242d1b2a2329e0b72bf7b2f23c2ae485R24-R38

fixed now

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 37d28184..a540e3bf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2105,6 +2105,7 @@ dependencies = [
  "env_logger",
  "libfuzzer-sys",
  "log",
+ "rand",
  "tempfile",
  "wasm-encoder 0.229.0",
  "wasm-mutate",
diff --git a/Cargo.toml b/Cargo.toml
index 7ce17299..b0b1736a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -65,6 +65,8 @@ rust-2024-incompatible-pat = 'warn'
 missing-unsafe-on-extern = 'warn'
 unsafe-op-in-unsafe-fn = 'warn'
 
+unexpected_cfgs = { level = 'warn', check-cfg = ['cfg(fuzzing)'] }
+
 [workspace.lints.clippy]
 # The default set of lints in Clippy is viewed as "too noisy" right now so
 # they're all turned off by default. Selective lints are then enabled below as
diff --git a/crates/wasm-compose/src/encoding.rs b/crates/wasm-compose/src/encoding.rs
index 87a8d473..8fcf875c 100644
--- a/crates/wasm-compose/src/encoding.rs
+++ b/crates/wasm-compose/src/encoding.rs
@@ -649,6 +649,9 @@ impl<'a> TypeEncoder<'a> {
             ComponentDefinedType::Record(r) => self.record(state, r),
             ComponentDefinedType::Variant(v) => self.variant(state, v),
             ComponentDefinedType::List(ty) => self.list(state, *ty),
+            ComponentDefinedType::FixedSizeList(ty, elements) => {
+                self.fixed_size_list(state, *ty, *elements)
+            }
             ComponentDefinedType::Tuple(t) => self.tuple(state, t),
             ComponentDefinedType::Flags(names) => Self::flags(&mut state.cur.encodable, names),
             ComponentDefinedType::Enum(cases) => Self::enum_type(&mut state.cur.encodable, cases),
@@ -709,6 +712,23 @@ impl<'a> TypeEncoder<'a> {
         index
     }
 
+    fn fixed_size_list(
+        &self,
+        state: &mut TypeState<'a>,
+        ty: ct::ComponentValType,
+        elements: u32,
+    ) -> u32 {
+        let ty = self.component_val_type(state, ty);
+        let index = state.cur.encodable.type_count();
+        state
+            .cur
+            .encodable
+            .ty()
+            .defined_type()
+            .fixed_size_list(ty, elements);
+        index
+    }
+
     fn tuple(&self, state: &mut TypeState<'a>, tuple: &TupleType) -> u32 {
         let types = tuple
             .types
@@ -1228,7 +1248,9 @@ impl DependencyRegistrar<'_, '_> {
             ComponentDefinedType::Primitive(_)
             | ComponentDefinedType::Enum(_)
             | ComponentDefinedType::Flags(_) => {}
-            ComponentDefinedType::List(t) | ComponentDefinedType::Option(t) => self.val_type(*t),
+            ComponentDefinedType::List(t)
+            | ComponentDefinedType::FixedSizeList(t, _)
+            | ComponentDefinedType::Option(t) => self.val_type(*t),
             ComponentDefinedType::Own(r) | ComponentDefinedType::Borrow(r) => {
                 self.ty(ComponentAnyTypeId::Resource(*r))
             }
diff --git a/crates/wasm-encoder/src/component/canonicals.rs b/crates/wasm-encoder/src/component/canonicals.rs
index bd1c4ba0..acf2713b 100644
--- a/crates/wasm-encoder/src/component/canonicals.rs
+++ b/crates/wasm-encoder/src/component/canonicals.rs
@@ -212,7 +212,7 @@ impl CanonicalFunctionSection {
 
     /// Defines a function to acknowledge cancellation of the current task.
     pub fn task_cancel(&mut self) -> &mut Self {
-        self.bytes.push(0x25);
+        self.bytes.push(0x05);
         self.num_added += 1;
         self
     }
@@ -255,7 +255,7 @@ impl CanonicalFunctionSection {
 
     /// Defines a function to cancel an in-progress task.
     pub fn subtask_cancel(&mut self, async_: bool) -> &mut Self {
-        self.bytes.push(0x24);
+        self.bytes.push(0x06);
         self.bytes.push(if async_ { 1 } else { 0 });
         self.num_added += 1;
         self
diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs
index e32c75c4..6d6a8f7b 100644
--- a/crates/wasm-encoder/src/component/types.rs
+++ b/crates/wasm-encoder/src/component/types.rs
@@ -593,6 +593,13 @@ impl ComponentDefinedTypeEncoder<'_> {
         ty.into().encode(self.0);
     }
 
+    /// Define a fixed size list type.
+    pub fn fixed_size_list(self, ty: impl Into<ComponentValType>, elements: u32) {
+        self.0.push(0x67);
+        ty.into().encode(self.0);
+        elements.encode(self.0);
+    }
+
     /// Define a tuple type.
     pub fn tuple<I, T>(self, types: I)
     where
diff --git a/crates/wasm-encoder/src/reencode/component.rs b/crates/wasm-encoder/src/reencode/component.rs
index 3d50dfca..7fd3578d 100644
--- a/crates/wasm-encoder/src/reencode/component.rs
+++ b/crates/wasm-encoder/src/reencode/component.rs
@@ -767,6 +767,9 @@ pub mod component_utils {
             wasmparser::ComponentDefinedType::List(t) => {
                 defined.list(reencoder.component_val_type(t));
             }
+            wasmparser::ComponentDefinedType::FixedSizeList(t, elements) => {
+                defined.fixed_size_list(reencoder.component_val_type(t), elements);
+            }
             wasmparser::ComponentDefinedType::Tuple(t) => {
                 defined.tuple(t.iter().map(|t| reencoder.component_val_type(*t)));
             }
diff --git a/crates/wasm-wave/src/value/ty.rs b/crates/wasm-wave/src/value/ty.rs
index 8898892b..85205197 100644
--- a/crates/wasm-wave/src/value/ty.rs
+++ b/crates/wasm-wave/src/value/ty.rs
@@ -10,6 +10,7 @@ pub struct Type(pub(super) TypeEnum);
 pub(super) enum TypeEnum {
     Simple(SimpleType),
     List(Arc<ListType>),
+    FixedSizeList(Arc<ListType>, u32),
     Record(Arc<RecordType>),
     Tuple(Arc<TupleType>),
     Variant(Arc<VariantType>),
@@ -55,6 +56,15 @@ impl Type {
         Self(TypeEnum::List(Arc::new(ListType { element })))
     }
 
+    /// Returns a list type with the given element type.
+    pub fn fixed_size_list(element_type: impl Into<Self>, elements: u32) -> Self {
+        let element = element_type.into();
+        Self(TypeEnum::FixedSizeList(
+            Arc::new(ListType { element }),
+            elements,
+        ))
+    }
+
     /// Returns a record type with the given field types. Returns None if
     /// `fields` is empty.
     pub fn record<T: Into<Box<str>>>(
@@ -189,6 +199,7 @@ impl WasmType for Type {
         match self.0 {
             TypeEnum::Simple(simple) => simple.0,
             TypeEnum::List(_) => WasmTypeKind::List,
+            TypeEnum::FixedSizeList(_, _) => WasmTypeKind::FixedSizeList,
             TypeEnum::Record(_) => WasmTypeKind::Record,
             TypeEnum::Tuple(_) => WasmTypeKind::Tuple,
             TypeEnum::Variant(_) => WasmTypeKind::Variant,
diff --git a/crates/wasm-wave/src/value/wit.rs b/crates/wasm-wave/src/value/wit.rs
index 423090a6..d0822f97 100644
--- a/crates/wasm-wave/src/value/wit.rs
+++ b/crates/wasm-wave/src/value/wit.rs
@@ -70,6 +70,9 @@ impl<'a> TypeResolver<'a> {
             TypeDefKind::Option(some_type) => self.resolve_option(some_type),
             TypeDefKind::Result(result) => self.resolve_result(result),
             TypeDefKind::List(element_type) => self.resolve_list(element_type),
+            TypeDefKind::FixedSizeList(element_type, elements) => {
+                self.resolve_fixed_size_list(element_type, *elements)
+            }
             TypeDefKind::Type(Type::Bool) => Ok(value::Type::BOOL),
             TypeDefKind::Type(Type::U8) => Ok(value::Type::U8),
             TypeDefKind::Type(Type::U16) => Ok(value::Type::U16),
@@ -145,6 +148,11 @@ impl<'a> TypeResolver<'a> {
         let element_type = self.resolve_type(*element_type)?;
         Ok(value::Type::list(element_type))
     }
+
+    fn resolve_fixed_size_list(&self, element_type: &Type, elements: u32) -> ValueResult {
+        let element_type = self.resolve_type(*element_type)?;
+        Ok(value::Type::fixed_size_list(element_type, elements))
+    }
 }
 
 #[cfg(test)]
diff --git a/crates/wasm-wave/src/wasm/ty.rs b/crates/wasm-wave/src/wasm/ty.rs
index e131759c..499647a0 100644
--- a/crates/wasm-wave/src/wasm/ty.rs
+++ b/crates/wasm-wave/src/wasm/ty.rs
@@ -20,6 +20,7 @@ pub enum WasmTypeKind {
     Char,
     String,
     List,
+    FixedSizeList,
     Record,
     Tuple,
     Variant,
@@ -48,6 +49,7 @@ impl std::fmt::Display for WasmTypeKind {
             WasmTypeKind::Char => "char",
             WasmTypeKind::String => "string",
             WasmTypeKind::List => "list",
+            WasmTypeKind::FixedSizeList => "list<_,N>",
             WasmTypeKind::Record => "record",
             WasmTypeKind::Tuple => "tuple",
             WasmTypeKind::Variant => "variant",
diff --git a/crates/wasm-wave/src/writer.rs b/crates/wasm-wave/src/writer.rs
index eca4f37a..4233f359 100644
--- a/crates/wasm-wave/src/writer.rs
+++ b/crates/wasm-wave/src/writer.rs
@@ -75,6 +75,16 @@ impl<W: Write> Writer<W> {
                 }
                 self.write_str("]")
             }
+            WasmTypeKind::FixedSizeList => {
+                self.write_str("[")?;
+                for (idx, val) in val.unwrap_list().enumerate() {
+                    if idx != 0 {
+                        self.write_str(", ")?;
+                    }
+                    self.write_value(&*val)?;
+                }
+                self.write_str("]")
+            }
             WasmTypeKind::Record => {
                 self.write_str("{")?;
                 let mut first = true;
diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs
index fbe88a38..c0d5e8e0 100644
--- a/crates/wasmparser/src/features.rs
+++ b/crates/wasmparser/src/features.rs
@@ -254,6 +254,11 @@ define_wasm_features! {
         /// Corresponds to the 📝 character in
         /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
         pub cm_error_context: CM_ERROR_CONTEXT(1 << 30) = false;
+        /// Support for fixed size lists
+        ///
+        /// Corresponds to the 🔧 character in
+        /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
+        pub cm_fixed_size_list: CM_FIXED_SIZE_LIST(1 << 31) = false;
     }
 }
 
diff --git a/crates/wasmparser/src/readers/component/canonicals.rs b/crates/wasmparser/src/readers/component/canonicals.rs
index f7160544..083167cd 100644
--- a/crates/wasmparser/src/readers/component/canonicals.rs
+++ b/crates/wasmparser/src/readers/component/canonicals.rs
@@ -367,10 +367,10 @@ impl<'a> FromReader<'a> for CanonicalFunction {
             },
             0x22 => CanonicalFunction::WaitableSetDrop,
             0x23 => CanonicalFunction::WaitableJoin,
-            0x24 => CanonicalFunction::SubtaskCancel {
+            0x06 => CanonicalFunction::SubtaskCancel {
                 async_: reader.read()?,
             },
-            0x25 => CanonicalFunction::TaskCancel,
+            0x05 => CanonicalFunction::TaskCancel,
             0x40 => CanonicalFunction::ThreadSpawnRef {
                 func_ty_index: reader.read()?,
             },
diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs
index 0bdc1df9..888a977c 100644
--- a/crates/wasmparser/src/readers/component/types.rs
+++ b/crates/wasmparser/src/readers/component/types.rs
@@ -441,6 +441,8 @@ pub enum ComponentDefinedType<'a> {
     Variant(Box<[VariantCase<'a>]>),
     /// The type is a list of the given value type.
     List(ComponentValType),
+    /// The type is a fixed size list of the given value type.
+    FixedSizeList(ComponentValType, u32),
     /// The type is a tuple of the given value types.
     Tuple(Box<[ComponentValType]>),
     /// The type is flags with the given names.
@@ -503,8 +505,9 @@ impl<'a> ComponentDefinedType<'a> {
             },
             0x69 => ComponentDefinedType::Own(reader.read()?),
             0x68 => ComponentDefinedType::Borrow(reader.read()?),
-            0x65 => ComponentDefinedType::Future(reader.read()?),
+            0x67 => ComponentDefinedType::FixedSizeList(reader.read()?, reader.read_var_u32()?),
             0x66 => ComponentDefinedType::Stream(reader.read()?),
+            0x65 => ComponentDefinedType::Future(reader.read()?),
             x => return reader.invalid_leading_byte(x, "component defined type"),
         })
     }
diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs
index 514198af..aef3ca0d 100644
--- a/crates/wasmparser/src/validator/component.rs
+++ b/crates/wasmparser/src/validator/component.rs
@@ -724,9 +724,9 @@ impl ComponentState {
                         .map(|t| types.type_named_valtype(t, set))
                         .unwrap_or(true)
             }
-            ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => {
-                types.type_named_valtype(ty, set)
-            }
+            ComponentDefinedType::List(ty)
+            | ComponentDefinedType::FixedSizeList(ty, _)
+            | ComponentDefinedType::Option(ty) => types.type_named_valtype(ty, set),
 
             // The resource referred to by own/borrow must be named.
             ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => {
@@ -1268,7 +1268,7 @@ impl ComponentState {
         }
 
         self.core_funcs
-            .push(types.intern_func_type(FuncType::new([], []), offset));
+            .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
         Ok(())
     }
 
@@ -3475,6 +3475,21 @@ impl ComponentState {
             crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List(
                 self.create_component_val_type(ty, offset)?,
             )),
+            crate::ComponentDefinedType::FixedSizeList(ty, elements) => {
+                if !self.features.cm_fixed_size_list() {
+                    bail!(
+                        offset,
+                        "Fixed size lists require the component model fixed size list feature"
+                    )
+                }
+                if elements < 1 {
+                    bail!(offset, "Fixed size lists must have more than zero elements")
+                }
+                Ok(ComponentDefinedType::FixedSizeList(
+                    self.create_component_val_type(ty, offset)?,
+                    elements,
+                ))
+            }
             crate::ComponentDefinedType::Tuple(tys) => {
                 self.create_tuple_type(tys.as_ref(), types, offset)
             }
diff --git a/crates/wasmparser/src/validator/component_types.rs b/crates/wasmparser/src/validator/component_types.rs
index 271b850f..2f14b371 100644
--- a/crates/wasmparser/src/validator/component_types.rs
+++ b/crates/wasmparser/src/validator/component_types.rs
@@ -1084,6 +1084,8 @@ pub enum ComponentDefinedType {
     Variant(VariantType),
     /// The type is a list.
     List(ComponentValType),
+    /// The type is a fixed size list.
+    FixedSizeList(ComponentValType, u32),
     /// The type is a tuple.
     Tuple(TupleType),
     /// The type is a set of flags.
@@ -1124,7 +1126,7 @@ impl TypeData for ComponentDefinedType {
             Self::Record(r) => r.info,
             Self::Variant(v) => v.info,
             Self::Tuple(t) => t.info,
-            Self::List(ty) | Self::Option(ty) => ty.info(types),
+            Self::List(ty) | Self::FixedSizeList(ty, _) | Self::Option(ty) => ty.info(types),
             Self::Result { ok, err } => {
                 let default = TypeInfo::new();
                 let mut info = ok.map(|ty| ty.type_info(types)).unwrap_or(default);
@@ -1153,7 +1155,7 @@ impl ComponentDefinedType {
             | Self::Borrow(_)
             | Self::Future(_)
             | Self::Stream(_) => false,
-            Self::Option(ty) => ty.contains_ptr(types),
+            Self::Option(ty) | Self::FixedSizeList(ty, _) => ty.contains_ptr(types),
             Self::Result { ok, err } => {
                 ok.map(|ty| ty.contains_ptr(types)).unwrap_or(false)
                     || err.map(|ty| ty.contains_ptr(types)).unwrap_or(false)
@@ -1174,6 +1176,12 @@ impl ComponentDefinedType {
                 lowered_types,
             ),
             Self::List(_) => lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32),
+            Self::FixedSizeList(ty, length) => {
+                if *length as usize > lowered_types.max {
+                    return false;
+                }
+                (0..*length).all(|_n| ty.push_wasm_types(types, lowered_types))
+            }
             Self::Tuple(t) => t
                 .types
                 .iter()
@@ -1248,6 +1256,7 @@ impl ComponentDefinedType {
             ComponentDefinedType::Flags(_) => "flags",
             ComponentDefinedType::Option(_) => "option",
             ComponentDefinedType::List(_) => "list",
+            ComponentDefinedType::FixedSizeList(_, _) => "fixed size list",
             ComponentDefinedType::Result { .. } => "result",
             ComponentDefinedType::Own(_) => "own",
             ComponentDefinedType::Borrow(_) => "borrow",
@@ -1985,7 +1994,9 @@ impl TypeAlloc {
                     }
                 }
             }
-            ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => {
+            ComponentDefinedType::List(ty)
+            | ComponentDefinedType::FixedSizeList(ty, _)
+            | ComponentDefinedType::Option(ty) => {
                 self.free_variables_valtype(ty, set);
             }
             ComponentDefinedType::Result { ok, err } => {
@@ -2127,9 +2138,9 @@ impl TypeAlloc {
                         .map(|t| self.type_named_valtype(t, set))
                         .unwrap_or(true)
             }
-            ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => {
-                self.type_named_valtype(ty, set)
-            }
+            ComponentDefinedType::List(ty)
+            | ComponentDefinedType::FixedSizeList(ty, _)
+            | ComponentDefinedType::Option(ty) => self.type_named_valtype(ty, set),
 
             // own/borrow themselves don't have to be named, but the resource
             // they refer to must be named.
@@ -2314,7 +2325,9 @@ where
                     }
                 }
             }
-            ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => {
+            ComponentDefinedType::List(ty)
+            | ComponentDefinedType::FixedSizeList(ty, _)
+            | ComponentDefinedType::Option(ty) => {
                 any_changed |= self.remap_valtype(ty, map);
             }
             ComponentDefinedType::Result { ok, err } => {
@@ -3203,6 +3216,14 @@ impl<'a> SubtypeCx<'a> {
             (Variant(_), b) => bail!(offset, "expected {}, found variant", b.desc()),
             (List(a), List(b)) | (Option(a), Option(b)) => self.component_val_type(a, b, offset),
             (List(_), b) => bail!(offset, "expected {}, found list", b.desc()),
+            (FixedSizeList(a, asize), FixedSizeList(b, bsize)) => {
+                if asize != bsize {
+                    bail!(offset, "expected fixed size {bsize}, found size {asize}")
+                } else {
+                    self.component_val_type(a, b, offset)
+                }
+            }
+            (FixedSizeList(_, _), b) => bail!(offset, "expected {}, found list", b.desc()),
             (Option(_), b) => bail!(offset, "expected {}, found option", b.desc()),
             (Tuple(a), Tuple(b)) => {
                 if a.types.len() != b.types.len() {
diff --git a/crates/wasmprinter/src/component.rs b/crates/wasmprinter/src/component.rs
index f10591ea..a834a10c 100644
--- a/crates/wasmprinter/src/component.rs
+++ b/crates/wasmprinter/src/component.rs
@@ -169,6 +169,19 @@ impl Printer<'_, '_> {
         Ok(())
     }
 
+    pub(crate) fn print_fixed_size_list_type(
+        &mut self,
+        state: &State,
+        element_ty: &ComponentValType,
+        elements: u32,
+    ) -> Result<()> {
+        self.start_group("list ")?;
+        self.print_component_val_type(state, element_ty)?;
+        self.result.write_str(&format!(" {elements}"))?;
+        self.end_group()?;
+        Ok(())
+    }
+
     pub(crate) fn print_tuple_type(
         &mut self,
         state: &State,
@@ -265,6 +278,9 @@ impl Printer<'_, '_> {
             ComponentDefinedType::Record(fields) => self.print_record_type(state, fields)?,
             ComponentDefinedType::Variant(cases) => self.print_variant_type(state, cases)?,
             ComponentDefinedType::List(ty) => self.print_list_type(state, ty)?,
+            ComponentDefinedType::FixedSizeList(ty, elements) => {
+                self.print_fixed_size_list_type(state, ty, *elements)?
+            }
             ComponentDefinedType::Tuple(tys) => self.print_tuple_type(state, tys)?,
             ComponentDefinedType::Flags(names) => self.print_flag_or_enum_type("flags", names)?,
             ComponentDefinedType::Enum(cases) => self.print_flag_or_enum_type("enum", cases)?,
diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs
index 89d4f3fb..b80455f6 100644
--- a/crates/wast/src/component/binary.rs
+++ b/crates/wast/src/component/binary.rs
@@ -109,6 +109,9 @@ fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefin
         ComponentDefinedType::List(l) => {
             encoder.list(l.element.as_ref());
         }
+        ComponentDefinedType::FixedSizeList(l) => {
+            encoder.fixed_size_list(l.element.as_ref(), l.elements);
+        }
         ComponentDefinedType::Tuple(t) => {
             encoder.tuple(t.fields.iter());
         }
diff --git a/crates/wast/src/component/expand.rs b/crates/wast/src/component/expand.rs
index 01b00d70..0887fc42 100644
--- a/crates/wast/src/component/expand.rs
+++ b/crates/wast/src/component/expand.rs
@@ -532,8 +532,12 @@ impl<'a> Expander<'a> {
                     }
                 }
             }
-            ComponentDefinedType::List(t) => {
-                self.expand_component_val_ty(&mut t.element);
+            ComponentDefinedType::List(List { element: t })
+            | ComponentDefinedType::FixedSizeList(FixedSizeList {
+                element: t,
+                elements: _,
+            }) => {
+                self.expand_component_val_ty(t);
             }
             ComponentDefinedType::Tuple(t) => {
                 for field in t.fields.iter_mut() {
diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs
index 21c0e56b..95ef0ef6 100644
--- a/crates/wast/src/component/resolve.rs
+++ b/crates/wast/src/component/resolve.rs
@@ -547,8 +547,12 @@ impl<'a> Resolver<'a> {
                     }
                 }
             }
-            ComponentDefinedType::List(l) => {
-                self.component_val_type(&mut l.element)?;
+            ComponentDefinedType::List(List { element: t })
+            | ComponentDefinedType::FixedSizeList(FixedSizeList {
+                element: t,
+                elements: _,
+            }) => {
+                self.component_val_type(t)?;
             }
             ComponentDefinedType::Tuple(t) => {
                 for field in t.fields.iter_mut() {
diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs
index 648eb59d..a9ef3ba8 100644
--- a/crates/wast/src/component/types.rs
+++ b/crates/wast/src/component/types.rs
@@ -386,6 +386,7 @@ pub enum ComponentDefinedType<'a> {
     Record(Record<'a>),
     Variant(Variant<'a>),
     List(List<'a>),
+    FixedSizeList(FixedSizeList<'a>),
     Tuple(Tuple<'a>),
     Flags(Flags<'a>),
     Enum(Enum<'a>),
@@ -405,7 +406,7 @@ impl<'a> ComponentDefinedType<'a> {
         } else if l.peek::<kw::variant>()? {
             Ok(Self::Variant(parser.parse()?))
         } else if l.peek::<kw::list>()? {
-            Ok(Self::List(parser.parse()?))
+            parse_list(parser)
         } else if l.peek::<kw::tuple>()? {
             Ok(Self::Tuple(parser.parse()?))
         } else if l.peek::<kw::flags>()? {
@@ -586,12 +587,28 @@ pub struct List<'a> {
     pub element: Box<ComponentValType<'a>>,
 }
 
-impl<'a> Parse<'a> for List<'a> {
-    fn parse(parser: Parser<'a>) -> Result<Self> {
-        parser.parse::<kw::list>()?;
-        Ok(Self {
-            element: Box::new(parser.parse()?),
-        })
+/// A fixed size list type.
+#[derive(Debug)]
+pub struct FixedSizeList<'a> {
+    /// The element type of the array.
+    pub element: Box<ComponentValType<'a>>,
+    /// Number of Elements
+    pub elements: u32,
+}
+
+fn parse_list<'a>(parser: Parser<'a>) -> Result<ComponentDefinedType<'a>> {
+    parser.parse::<kw::list>()?;
+    let tp = parser.parse()?;
+    let elements = parser.parse::<Option<u32>>()?;
+    if let Some(elements) = elements {
+        Ok(ComponentDefinedType::FixedSizeList(FixedSizeList {
+            element: Box::new(tp),
+            elements,
+        }))
+    } else {
+        Ok(ComponentDefinedType::List(List {
+            element: Box::new(tp),
+        }))
     }
 }
 
diff --git a/crates/wit-component/src/dummy.rs b/crates/wit-component/src/dummy.rs
index 003bed34..0cccff00 100644
--- a/crates/wit-component/src/dummy.rs
+++ b/crates/wit-component/src/dummy.rs
@@ -379,7 +379,7 @@ fn push_root_async_intrinsics(dst: &mut String) {
 (import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32)))
 (import "$root" "[waitable-set-drop]" (func (param i32)))
 (import "$root" "[waitable-join]" (func (param i32 i32)))
-(import "$root" "[yield]" (func))
+(import "$root" "[yield]" (func (result i32)))
 (import "$root" "[subtask-drop]" (func (param i32)))
 (import "$root" "[subtask-cancel]" (func (param i32) (result i32)))
 (import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32)))
@@ -395,7 +395,7 @@ fn push_root_async_intrinsics(dst: &mut String) {
 ;; deferred behind 🚝 or 🚟 upstream
 ;;(import "$root" "[async-lower][waitable-set-wait]" (func (param i32 i32) (result i32)))
 ;;(import "$root" "[async-lower][waitable-set-poll]" (func (param i32 i32) (result i32)))
-;;(import "$root" "[async-lower][yield]" (func))
+;;(import "$root" "[async-lower][yield]" (func (result i32)))
 "#,
     );
 }
diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs
index ce255ede..f93d9a7a 100644
--- a/crates/wit-component/src/encoding.rs
+++ b/crates/wit-component/src/encoding.rs
@@ -320,6 +320,7 @@ impl TypeContents {
                 }
                 TypeDefKind::Enum(_) => Self::empty(),
                 TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::LIST,
+                TypeDefKind::FixedSizeList(t, _elements) => Self::for_type(resolve, t),
                 TypeDefKind::Type(t) => Self::for_type(resolve, t),
                 TypeDefKind::Future(_) => Self::empty(),
                 TypeDefKind::Stream(_) => Self::empty(),
diff --git a/crates/wit-component/src/encoding/types.rs b/crates/wit-component/src/encoding/types.rs
index 59d4330f..7b354dc6 100644
--- a/crates/wit-component/src/encoding/types.rs
+++ b/crates/wit-component/src/encoding/types.rs
@@ -144,6 +144,12 @@ pub trait ValtypeEncoder<'a> {
                         encoder.list(ty);
                         ComponentValType::Type(index)
                     }
+                    TypeDefKind::FixedSizeList(ty, elements) => {
+                        let ty = self.encode_valtype(resolve, ty)?;
+                        let (index, encoder) = self.defined_type();
+                        encoder.fixed_size_list(ty, *elements);
+                        ComponentValType::Type(index)
+                    }
                     TypeDefKind::Type(ty) => self.encode_valtype(resolve, ty)?,
                     TypeDefKind::Future(ty) => self.encode_future(resolve, ty)?,
                     TypeDefKind::Stream(ty) => self.encode_stream(resolve, ty)?,
diff --git a/crates/wit-component/src/encoding/wit.rs b/crates/wit-component/src/encoding/wit.rs
index 5e2b0b02..5c433724 100644
--- a/crates/wit-component/src/encoding/wit.rs
+++ b/crates/wit-component/src/encoding/wit.rs
@@ -71,30 +71,8 @@ pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentTyp
     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 | FunctionKind::AsyncFreestanding => 0,
-            _ => 1,
-        },
-        _ => 0,
-    });
-
     // Encode the imports
-    for (name, import) in imports {
+    for (name, import) in world.imports.iter() {
         let name = resolve.name_world_key(name);
         log::trace!("encoding import {name}");
         let ty = match import {
diff --git a/crates/wit-component/src/printing.rs b/crates/wit-component/src/printing.rs
index 3292fd05..3452ef66 100644
--- a/crates/wit-component/src/printing.rs
+++ b/crates/wit-component/src/printing.rs
@@ -383,12 +383,32 @@ impl<O: Output> WitPrinter<O> {
         Ok(())
     }
 
+    /// Prints the world `id` within `resolve`.
+    ///
+    /// This is a little tricky to preserve round-tripping that WIT wants. This
+    /// function inherently can't preserve ordering of imports because resource
+    /// functions aren't guaranteed to be all adjacent to the resource itself
+    /// they're attached to. That means that at the very least, when printing
+    /// resource functions, items may be printed out-of-order.
+    ///
+    /// To help solve this the printing here is kept in sync with WIT encoding
+    /// of worlds which is to print items in the order of:
+    ///
+    /// * Any imported interface. Ordering between interfaces is preserved.
+    /// * Any types, including resource functions on those types. Ordering
+    ///   between types is preserved.
+    /// * Any functions, which may refer to those types. Ordering between
+    ///   functions is preserved.
+    ///
+    /// This keeps things printed in a roughly topological fashion and makes
+    /// round-tripping a bit more reliable.
     fn print_world(&mut self, resolve: &Resolve, id: WorldId) -> Result<()> {
         let prev_items = mem::replace(&mut self.any_items, false);
         let world = &resolve.worlds[id];
         let pkgid = world.package.unwrap();
         let mut types = Vec::new();
         let mut resource_funcs = HashMap::new();
+        let mut function_imports_to_print = Vec::new();
         for (name, import) in world.imports.iter() {
             match import {
                 WorldItem::Type(t) => match name {
@@ -401,6 +421,8 @@ impl<O: Output> WitPrinter<O> {
                             resource_funcs.entry(id).or_insert(Vec::new()).push(f);
                             continue;
                         }
+                        function_imports_to_print.push((name, import));
+                        continue;
                     }
                     self.print_world_item(resolve, name, import, pkgid, "import")?;
                     // Don't put a blank line between imports, but count
@@ -416,6 +438,11 @@ impl<O: Output> WitPrinter<O> {
             types.into_iter(),
             &resource_funcs,
         )?;
+
+        for (name, import) in function_imports_to_print {
+            self.print_world_item(resolve, name, import, pkgid, "import")?;
+            self.any_items = true;
+        }
         if !world.exports.is_empty() {
             self.new_item();
         }
@@ -573,6 +600,13 @@ impl<O: Output> WitPrinter<O> {
                         self.print_type_name(resolve, ty)?;
                         self.output.generic_args_end();
                     }
+                    TypeDefKind::FixedSizeList(ty, size) => {
+                        self.output.ty("list", TypeKind::BuiltIn);
+                        self.output.generic_args_start();
+                        self.print_type_name(resolve, ty)?;
+                        self.output.push_str(&format!(", {}", *size));
+                        self.output.generic_args_end();
+                    }
                     TypeDefKind::Type(ty) => self.print_type_name(resolve, ty)?,
                     TypeDefKind::Future(ty) => {
                         if let Some(ty) = ty {
@@ -747,6 +781,9 @@ impl<O: Output> WitPrinter<O> {
                     TypeDefKind::List(inner) => {
                         self.declare_list(resolve, ty.name.as_deref(), inner)?
                     }
+                    TypeDefKind::FixedSizeList(inner, size) => {
+                        self.declare_fixed_size_list(resolve, ty.name.as_deref(), inner, *size)?
+                    }
                     TypeDefKind::Type(inner) => match ty.name.as_deref() {
                         Some(name) => {
                             self.output.keyword("type");
@@ -960,6 +997,30 @@ impl<O: Output> WitPrinter<O> {
         Ok(())
     }
 
+    fn declare_fixed_size_list(
+        &mut self,
+        resolve: &Resolve,
+        name: Option<&str>,
+        ty: &Type,
+        elements: u32,
+    ) -> Result<()> {
+        if let Some(name) = name {
+            self.output.keyword("type");
+            self.output.str(" ");
+            self.print_name_type(name, TypeKind::List);
+            self.output.str(" = ");
+            self.output.ty("list", TypeKind::BuiltIn);
+            self.output.str("<");
+            self.print_type_name(resolve, ty)?;
+            self.output.str(&format!(", {elements}"));
+            self.output.str(">");
+            self.output.semicolon();
+            return Ok(());
+        }
+
+        Ok(())
+    }
+
     fn declare_stream(
         &mut self,
         resolve: &Resolve,
diff --git a/crates/wit-component/src/validation.rs b/crates/wit-component/src/validation.rs
index 211a774a..8e2d81cf 100644
--- a/crates/wit-component/src/validation.rs
+++ b/crates/wit-component/src/validation.rs
@@ -607,7 +607,7 @@ impl ImportMap {
             }
 
             if Some(name) == names.yield_() {
-                let expected = FuncType::new([], []);
+                let expected = FuncType::new([], [ValType::I32]);
                 validate_func_sig(name, &expected, ty)?;
                 return Ok(Import::Yield { async_ });
             }
diff --git a/crates/wit-encoder/src/from_parser.rs b/crates/wit-encoder/src/from_parser.rs
index e8381d9b..c07da9c6 100644
--- a/crates/wit-encoder/src/from_parser.rs
+++ b/crates/wit-encoder/src/from_parser.rs
@@ -243,6 +243,10 @@ impl<'a> Converter<'a> {
                         let output = Type::list(self.convert_type(ty));
                         TypeDefKind::Type(output)
                     }
+                    wit_parser::TypeDefKind::FixedSizeList(ty, size) => {
+                        let output = Type::fixed_size_list(self.convert_type(ty), *size);
+                        TypeDefKind::Type(output)
+                    }
                     wit_parser::TypeDefKind::Handle(handle) => {
                         let output = self.handle_to_type(handle);
                         TypeDefKind::Type(output)
@@ -304,6 +308,9 @@ impl<'a> Converter<'a> {
                         wit_parser::TypeDefKind::List(type_) => {
                             Type::list(self.convert_type(type_))
                         }
+                        wit_parser::TypeDefKind::FixedSizeList(type_, size) => {
+                            Type::fixed_size_list(self.convert_type(type_), *size)
+                        }
                         wit_parser::TypeDefKind::Handle(handle) => self.handle_to_type(handle),
                         wit_parser::TypeDefKind::Future(type_) => {
                             Type::future(self.convert_option_type(type_))
diff --git a/crates/wit-encoder/src/ty.rs b/crates/wit-encoder/src/ty.rs
index 75b7e7c1..18513b53 100644
--- a/crates/wit-encoder/src/ty.rs
+++ b/crates/wit-encoder/src/ty.rs
@@ -26,6 +26,7 @@ pub enum Type {
     Option(Box<Type>),
     Result(Box<Result_>),
     List(Box<Type>),
+    FixedSizeList(Box<Type>, u32),
     Tuple(Tuple),
     Future(Option<Box<Type>>),
     Stream(Option<Box<Type>>),
@@ -58,6 +59,9 @@ impl Type {
     pub fn list(type_: Type) -> Self {
         Type::List(Box::new(type_))
     }
+    pub fn fixed_size_list(type_: Type, size: u32) -> Self {
+        Type::FixedSizeList(Box::new(type_), size)
+    }
     pub fn tuple(types: impl IntoIterator<Item = Type>) -> Self {
         Type::Tuple(Tuple {
             types: types.into_iter().collect(),
@@ -116,6 +120,9 @@ impl Display for Type {
             Type::List(type_) => {
                 write!(f, "list<{type_}>")
             }
+            Type::FixedSizeList(type_, size) => {
+                write!(f, "list<{type_}, {size}>")
+            }
             Type::Tuple(tuple) => tuple.fmt(f),
             Type::Future(None) => {
                 write!(f, "future")
diff --git a/crates/wit-parser/src/abi.rs b/crates/wit-parser/src/abi.rs
index 675feeb4..de1bb745 100644
--- a/crates/wit-parser/src/abi.rs
+++ b/crates/wit-parser/src/abi.rs
@@ -133,6 +133,9 @@ pub enum AbiVariant {
 }
 
 impl Resolve {
+    const MAX_FLAT_PARAMS: usize = 16;
+    const MAX_FLAT_RESULTS: usize = 1;
+
     /// Get the WebAssembly type signature for this interface function
     ///
     /// The first entry returned is the list of parameters and the second entry
@@ -147,16 +150,13 @@ impl Resolve {
             };
         }
 
-        const MAX_FLAT_PARAMS: usize = 16;
-        const MAX_FLAT_RESULTS: usize = 1;
-
         let mut params = Vec::new();
         let mut indirect_params = false;
         for (_, param) in func.params.iter() {
             self.push_flat(param, &mut params);
         }
 
-        if params.len() > MAX_FLAT_PARAMS {
+        if params.len() > Self::MAX_FLAT_PARAMS {
             params.truncate(0);
             params.push(WasmType::Pointer);
             indirect_params = true;
@@ -212,7 +212,7 @@ impl Resolve {
         // would have multiple results then instead truncate it. Imports take a
         // return pointer to write into and exports return a pointer they wrote
         // into.
-        if results.len() > MAX_FLAT_RESULTS {
+        if results.len() > Self::MAX_FLAT_RESULTS {
             retptr = true;
             results.truncate(0);
             match variant {
@@ -288,6 +288,15 @@ impl Resolve {
                     result.push(WasmType::Length);
                 }
 
+                TypeDefKind::FixedSizeList(ty, size) => {
+                    for _ in 0..usize::try_from(*size)
+                        .unwrap_or(Self::MAX_FLAT_PARAMS)
+                        .min(Self::MAX_FLAT_PARAMS)
+                    {
+                        self.push_flat(ty, result);
+                    }
+                }
+
                 TypeDefKind::Variant(v) => {
                     result.push(v.tag().into());
                     self.push_flat_variants(v.cases.iter().map(|c| c.ty.as_ref()), result);
diff --git a/crates/wit-parser/src/ast.rs b/crates/wit-parser/src/ast.rs
index 34556c3b..41186ab3 100644
--- a/crates/wit-parser/src/ast.rs
+++ b/crates/wit-parser/src/ast.rs
@@ -754,6 +754,7 @@ enum Type<'a> {
     String(Span),
     Name(Id<'a>),
     List(List<'a>),
+    FixedSizeList(FixedSizeList<'a>),
     Handle(Handle<'a>),
     Resource(Resource<'a>),
     Record(Record<'a>),
@@ -905,6 +906,12 @@ struct List<'a> {
     ty: Box<Type<'a>>,
 }
 
+struct FixedSizeList<'a> {
+    span: Span,
+    ty: Box<Type<'a>>,
+    size: u32,
+}
+
 struct Future<'a> {
     span: Span,
     ty: Option<Box<Type<'a>>>,
@@ -1363,14 +1370,34 @@ impl<'a> Type<'a> {
             Some((span, Token::String_)) => Ok(Type::String(span)),
 
             // list<T>
+            // list<T, N>
             Some((span, Token::List)) => {
                 tokens.expect(Token::LessThan)?;
                 let ty = Type::parse(tokens)?;
+                let size = if tokens.eat(Token::Comma)? {
+                    let number = tokens.next()?;
+                    if let Some((span, Token::Integer)) = number {
+                        let size: u32 = tokens.get_span(span).parse()?;
+                        Some(size)
+                    } else {
+                        return Err(err_expected(tokens, "fixed size", number).into());
+                    }
+                } else {
+                    None
+                };
                 tokens.expect(Token::GreaterThan)?;
-                Ok(Type::List(List {
-                    span,
-                    ty: Box::new(ty),
-                }))
+                if let Some(size) = size {
+                    Ok(Type::FixedSizeList(FixedSizeList {
+                        span,
+                        ty: Box::new(ty),
+                        size,
+                    }))
+                } else {
+                    Ok(Type::List(List {
+                        span,
+                        ty: Box::new(ty),
+                    }))
+                }
             }
 
             // option<T>
@@ -1483,6 +1510,7 @@ impl<'a> Type<'a> {
             | Type::ErrorContext(span) => *span,
             Type::Name(id) => id.span,
             Type::List(l) => l.span,
+            Type::FixedSizeList(l) => l.span,
             Type::Handle(h) => h.span(),
             Type::Resource(r) => r.span,
             Type::Record(r) => r.span,
diff --git a/crates/wit-parser/src/ast/resolve.rs b/crates/wit-parser/src/ast/resolve.rs
index e1b7016b..0e626d87 100644
--- a/crates/wit-parser/src/ast/resolve.rs
+++ b/crates/wit-parser/src/ast/resolve.rs
@@ -92,6 +92,7 @@ enum Key {
     Tuple(Vec<Type>),
     Enum(Vec<String>),
     List(Type),
+    FixedSizeList(Type, u32),
     Option(Type),
     Result(Option<Type>, Option<Type>),
     Future(Option<Type>),
@@ -1174,6 +1175,10 @@ impl<'a> Resolver<'a> {
                 let ty = self.resolve_type(&list.ty, stability)?;
                 TypeDefKind::List(ty)
             }
+            ast::Type::FixedSizeList(list) => {
+                let ty = self.resolve_type(&list.ty, stability)?;
+                TypeDefKind::FixedSizeList(ty, list.size)
+            }
             ast::Type::Handle(handle) => TypeDefKind::Handle(match handle {
                 ast::Handle::Own { resource } => Handle::Own(self.validate_resource(resource)?),
                 ast::Handle::Borrow { resource } => {
@@ -1351,7 +1356,9 @@ impl<'a> Resolver<'a> {
                     find_in_type(types, Type::Id(*id))
                 }
                 TypeDefKind::Tuple(t) => t.types.iter().find_map(|ty| find_in_type(types, *ty)),
-                TypeDefKind::List(ty) | TypeDefKind::Option(ty) => find_in_type(types, *ty),
+                TypeDefKind::List(ty)
+                | TypeDefKind::FixedSizeList(ty, _)
+                | TypeDefKind::Option(ty) => find_in_type(types, *ty),
                 TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => {
                     ty.as_ref().and_then(|ty| find_in_type(types, *ty))
                 }
@@ -1443,6 +1450,7 @@ impl<'a> Resolver<'a> {
                 Key::Enum(r.cases.iter().map(|f| f.name.clone()).collect::<Vec<_>>())
             }
             TypeDefKind::List(ty) => Key::List(*ty),
+            TypeDefKind::FixedSizeList(ty, size) => Key::FixedSizeList(*ty, *size),
             TypeDefKind::Option(t) => Key::Option(*t),
             TypeDefKind::Result(r) => Key::Result(r.ok, r.err),
             TypeDefKind::Future(ty) => Key::Future(*ty),
@@ -1678,9 +1686,9 @@ fn collect_deps<'a>(ty: &ast::Type<'a>, deps: &mut Vec<ast::Id<'a>>) {
                 }
             }
         }
-        ast::Type::Option(ast::Option_ { ty, .. }) | ast::Type::List(ast::List { ty, .. }) => {
-            collect_deps(ty, deps)
-        }
+        ast::Type::Option(ast::Option_ { ty, .. })
+        | ast::Type::List(ast::List { ty, .. })
+        | ast::Type::FixedSizeList(ast::FixedSizeList { ty, .. }) => collect_deps(ty, deps),
         ast::Type::Result(r) => {
             if let Some(ty) = &r.ok {
                 collect_deps(ty, deps);
diff --git a/crates/wit-parser/src/decoding.rs b/crates/wit-parser/src/decoding.rs
index 26c7e93e..7dce0d1c 100644
--- a/crates/wit-parser/src/decoding.rs
+++ b/crates/wit-parser/src/decoding.rs
@@ -1254,6 +1254,7 @@ impl WitPackageDecoder<'_> {
         match &kind {
             TypeDefKind::Type(_)
             | TypeDefKind::List(_)
+            | TypeDefKind::FixedSizeList(..)
             | TypeDefKind::Tuple(_)
             | TypeDefKind::Option(_)
             | TypeDefKind::Result(_)
@@ -1294,6 +1295,11 @@ impl WitPackageDecoder<'_> {
                 Ok(TypeDefKind::List(t))
             }
 
+            ComponentDefinedType::FixedSizeList(t, size) => {
+                let t = self.convert_valtype(t)?;
+                Ok(TypeDefKind::FixedSizeList(t, *size))
+            }
+
             ComponentDefinedType::Tuple(t) => {
                 let types = t
                     .types
@@ -1586,6 +1592,15 @@ impl Registrar<'_> {
                 self.valtype(t, ty)
             }
 
+            ComponentDefinedType::FixedSizeList(t, elements) => {
+                let ty = match &self.resolve.types[id].kind {
+                    TypeDefKind::FixedSizeList(r, elements2) if elements2 == elements => r,
+                    TypeDefKind::Type(Type::Id(_)) => return Ok(()),
+                    _ => bail!("expected a fixed size {elements} list"),
+                };
+                self.valtype(t, ty)
+            }
+
             ComponentDefinedType::Tuple(t) => {
                 let ty = match &self.resolve.types[id].kind {
                     TypeDefKind::Tuple(r) => r,
diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs
index d8551db1..5f8aa6c9 100644
--- a/crates/wit-parser/src/lib.rs
+++ b/crates/wit-parser/src/lib.rs
@@ -569,6 +569,7 @@ pub enum TypeDefKind {
     Option(Type),
     Result(Result_),
     List(Type),
+    FixedSizeList(Type, u32),
     Future(Option<Type>),
     Stream(Option<Type>),
     Type(Type),
@@ -597,6 +598,7 @@ impl TypeDefKind {
             TypeDefKind::Option(_) => "option",
             TypeDefKind::Result(_) => "result",
             TypeDefKind::List(_) => "list",
+            TypeDefKind::FixedSizeList(..) => "fixed size list",
             TypeDefKind::Future(_) => "future",
             TypeDefKind::Stream(_) => "stream",
             TypeDefKind::Type(_) => "type",
@@ -1153,7 +1155,10 @@ fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec<TypeI
                 }
             }
         }
-        TypeDefKind::Option(ty) | TypeDefKind::List(ty) | TypeDefKind::Type(ty) => {
+        TypeDefKind::Option(ty)
+        | TypeDefKind::List(ty)
+        | TypeDefKind::FixedSizeList(ty, ..)
+        | TypeDefKind::Type(ty) => {
             find_futures_and_streams(resolve, *ty, results);
         }
         TypeDefKind::Result(r) => {
diff --git a/crates/wit-parser/src/live.rs b/crates/wit-parser/src/live.rs
index 27a769b0..48637f54 100644
--- a/crates/wit-parser/src/live.rs
+++ b/crates/wit-parser/src/live.rs
@@ -132,6 +132,7 @@ pub trait TypeIdVisitor {
         match &ty.kind {
             TypeDefKind::Type(t)
             | TypeDefKind::List(t)
+            | TypeDefKind::FixedSizeList(t, ..)
             | TypeDefKind::Option(t)
             | TypeDefKind::Future(Some(t))
             | TypeDefKind::Stream(Some(t)) => self.visit_type(resolve, t),
diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs
index 8950dcd1..a4ff8a15 100644
--- a/crates/wit-parser/src/resolve.rs
+++ b/crates/wit-parser/src/resolve.rs
@@ -573,7 +573,7 @@ package {name} is defined in two different locations:\n\
                 | TypeDefKind::Result(_)
                 | TypeDefKind::Future(_)
                 | TypeDefKind::Stream(_) => false,
-                TypeDefKind::Type(t) => self.all_bits_valid(t),
+                TypeDefKind::Type(t) | TypeDefKind::FixedSizeList(t, ..) => self.all_bits_valid(t),
 
                 TypeDefKind::Handle(h) => match h {
                     crate::Handle::Own(_) => true,
@@ -1931,7 +1931,52 @@ package {name} is defined in two different locations:\n\
         // topological order between them.
         let mut new_imports = IndexMap::new();
         let world = &self.worlds[world_id];
-        for (name, item) in world.imports.iter() {
+
+        // Sort the imports by "class" to ensure that this matches the order
+        // that items are printed and that items are in topological order.
+        //
+        // When printing worlds in WIT:
+        //
+        // * interfaces come first
+        // * types are next
+        //   * type imports are first
+        //   * type definitions are next
+        //   * resource definitions have methods printed inline
+        // * freestanding functions are last
+        //
+        // This reflects the topological order between items where types
+        // can refer to imports and functions can refer to these types. Ordering
+        // within a single class (e.g. imports depending on each other, types
+        // referring to each other) is already preserved by other passes in this
+        // file and general AST resolution. That means that a stable sort here
+        // can be used to ensure that each class is in the right location
+        // relative to the others.
+        //
+        // Overall this ensures that round-trips of WIT through wasm should
+        // always produce the same result.
+        let sort_key = |resolve: &Resolve, item: &WorldItem| match item {
+            WorldItem::Interface { .. } => 0,
+            WorldItem::Type(ty) => {
+                let ty = &resolve.types[*ty];
+                match ty.kind {
+                    TypeDefKind::Type(Type::Id(t)) if resolve.types[t].owner != ty.owner => 1,
+                    _ => 2,
+                }
+            }
+            WorldItem::Function(f) => {
+                if f.kind.resource().is_none() {
+                    3
+                } else {
+                    4
+                }
+            }
+        };
+
+        // Sort world items when we start to elaborate the world to start with a
+        // topological view of items.
+        let mut world_imports = world.imports.iter().collect::<Vec<_>>();
+        world_imports.sort_by_key(|(_name, import)| sort_key(self, import));
+        for (name, item) in world_imports {
             match item {
                 // Interfaces get their dependencies added first followed by the
                 // interface itself.
@@ -1987,6 +2032,11 @@ package {name} is defined in two different locations:\n\
 
         self.elaborate_world_exports(&export_interfaces, &mut new_imports, &mut new_exports)?;
 
+        // In addition to sorting at the start of elaboration also sort here at
+        // the end of elaboration to handle types being interspersed with
+        // interfaces as they're found.
+        new_imports.sort_by_cached_key(|_name, import| sort_key(self, import));
+
         // And with all that done the world is updated in-place with
         // imports/exports.
         log::trace!("imports = {:?}", new_imports);
@@ -3135,7 +3185,7 @@ impl Remap {
                     }
                 }
             }
-            Option(t) | List(t) | Future(Some(t)) | Stream(Some(t)) => {
+            Option(t) | List(t, ..) | FixedSizeList(t, ..) | Future(Some(t)) | Stream(Some(t)) => {
                 self.update_ty(resolve, t, span)?
             }
             Result(r) => {
@@ -3522,6 +3572,7 @@ impl Remap {
             TypeDefKind::Tuple(t) => t.types.iter().any(|t| self.type_has_borrow(resolve, t)),
             TypeDefKind::Enum(_) => false,
             TypeDefKind::List(ty)
+            | TypeDefKind::FixedSizeList(ty, ..)
             | TypeDefKind::Future(Some(ty))
             | TypeDefKind::Stream(Some(ty))
             | TypeDefKind::Option(ty) => self.type_has_borrow(resolve, ty),
diff --git a/crates/wit-parser/src/resolve/clone.rs b/crates/wit-parser/src/resolve/clone.rs
index 5554826f..32bc5bc2 100644
--- a/crates/wit-parser/src/resolve/clone.rs
+++ b/crates/wit-parser/src/resolve/clone.rs
@@ -109,7 +109,9 @@ impl<'a> Cloner<'a> {
             TypeDefKind::Handle(Handle::Own(ty) | Handle::Borrow(ty)) => {
                 self.type_id(ty);
             }
-            TypeDefKind::Option(ty) | TypeDefKind::List(ty) => {
+            TypeDefKind::Option(ty)
+            | TypeDefKind::List(ty)
+            | TypeDefKind::FixedSizeList(ty, ..) => {
                 self.ty(ty);
             }
             TypeDefKind::Tuple(list) => {
diff --git a/crates/wit-parser/src/sizealign.rs b/crates/wit-parser/src/sizealign.rs
index 5e0f0e0d..a9b96dc0 100644
--- a/crates/wit-parser/src/sizealign.rs
+++ b/crates/wit-parser/src/sizealign.rs
@@ -260,6 +260,17 @@ impl SizeAlign {
     fn calculate(&self, ty: &TypeDef) -> ElementInfo {
         match &ty.kind {
             TypeDefKind::Type(t) => ElementInfo::new(self.size(t), self.align(t)),
+            TypeDefKind::FixedSizeList(t, size) => {
+                let field_align = self.align(t);
+                let field_size = self.size(t);
+                ElementInfo::new(
+                    ArchitectureSize::new(
+                        field_size.bytes.checked_mul(*size as usize).unwrap(),
+                        field_size.pointers.checked_mul(*size as usize).unwrap(),
+                    ),
+                    field_align,
+                )
+            }
             TypeDefKind::List(_) => {
                 ElementInfo::new(ArchitectureSize::new(0, 2), Alignment::Pointer)
             }
diff --git a/crates/wit-smith/src/generate.rs b/crates/wit-smith/src/generate.rs
index d02edc41..a6fbca80 100644
--- a/crates/wit-smith/src/generate.rs
+++ b/crates/wit-smith/src/generate.rs
@@ -1,30 +1,27 @@
 use crate::config::Config;
 use arbitrary::{Arbitrary, Result, Unstructured};
-use indexmap::IndexMap;
+use indexmap::{IndexMap, IndexSet};
 use semver::Version;
 use std::collections::hash_map::{Entry, HashMap};
 use std::collections::HashSet;
 use std::fmt::Write;
+use std::mem;
 use std::rc::Rc;
 use std::str;
 use wit_parser::*;
 
 pub struct Generator {
     config: Config,
-    packages: PackageList,
+    packages: Packages,
     next_interface_id: u32,
 }
 
-type TypeList = Vec<Type>;
-type InterfaceList = IndexMap<String, FileInterface>;
-type PackageList = Vec<(PackageName, InterfaceList)>;
-
 struct InterfaceGenerator<'a> {
     generator: &'a Generator,
     file: &'a mut File,
     config: &'a Config,
     unique_names: HashSet<String>,
-    types_in_interface: TypeList,
+    types_in_interface: Vec<Type>,
 }
 
 #[derive(Clone)]
@@ -34,9 +31,17 @@ struct Type {
     is_resource: bool,
 }
 
+#[derive(Default)]
+struct Packages {
+    list: Vec<Package>,
+    packages_with_interfaces: Vec<usize>,
+    packages_with_worlds: Vec<usize>,
+}
+
 pub struct Package {
     pub name: PackageName,
     pub sources: SourceMap,
+    file: File,
 }
 
 #[derive(Clone)]
@@ -56,23 +61,26 @@ impl Generator {
     }
 
     pub fn generate(&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() {
-            let (pkg, interfaces) = self.gen_package(u, &mut names)?;
-            if interfaces.len() > 0 {
-                self.packages.push((pkg.name.clone(), interfaces));
+        while self.packages.list.len() < self.config.max_packages && self.packages.list.is_empty() {
+            let pkg = self.gen_package(u, &mut names)?;
+            let i = self.packages.list.len();
+            if pkg.file.interfaces.len() > 0 {
+                self.packages.packages_with_interfaces.push(i);
+            }
+            if pkg.file.worlds.len() > 0 {
+                self.packages.packages_with_worlds.push(i);
             }
-            packages.push(pkg);
+            self.packages.list.push(pkg);
         }
-        Ok(packages)
+        Ok(mem::take(&mut self.packages.list))
     }
 
     fn gen_package(
         &mut self,
         u: &mut Unstructured<'_>,
         names: &mut HashSet<String>,
-    ) -> Result<(Package, InterfaceList)> {
+    ) -> Result<Package> {
         let namespace = gen_unique_name(u, names)?;
         let name = gen_unique_name(u, names)?;
         let version = if u.arbitrary()? {
@@ -86,6 +94,7 @@ impl Generator {
                 name,
                 version,
             },
+            file: File::default(),
             sources: SourceMap::new(),
         };
 
@@ -101,7 +110,6 @@ impl Generator {
         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 {
             items += 1;
@@ -114,15 +122,7 @@ impl Generator {
             let file = match files.get_mut(i) {
                 Some(file) => file,
                 None => {
-                    files.push(File {
-                        items: Vec::new(),
-                        namespace: package
-                            .interfaces
-                            .iter()
-                            .map(|(k, _)| (k.clone(), Definition::Package))
-                            .collect(),
-                        interfaces: package.interfaces.clone(),
-                    });
+                    files.push(ret.file.clone());
                     files.last_mut().unwrap()
                 }
             };
@@ -137,15 +137,37 @@ impl Generator {
 
             match generate {
                 Generate::World => {
-                    let name = file.gen_unique_package_name(u, &mut package_names)?;
+                    let name =
+                        file.gen_unique_package_name(u, &mut package_names, DefinitionKind::World)?;
                     log::debug!("new world `{name}` in {i}");
                     let world = self.gen_world(u, &name, file)?;
                     file.items.push(world);
 
+                    // Insert the world at the package and file level, asserting
+                    // uniqueness.
+                    assert!(ret.file.worlds.insert(name.clone()));
+                    assert!(file.worlds.insert(name.clone()));
+                    let prev = ret.file.namespace.insert(
+                        name.clone(),
+                        (DefinitionLevel::Package, DefinitionKind::World),
+                    );
+                    assert!(prev.is_none());
+
+                    // Insert the definition into all other files as well.
+                    for file in files.iter_mut() {
+                        if file.insert_definition(&name, DefinitionKind::World) {
+                            assert!(file.worlds.insert(name.clone()));
+                        }
+                    }
+
                     empty = false;
                 }
                 Generate::Interface => {
-                    let name = file.gen_unique_package_name(u, &mut package_names)?;
+                    let name = file.gen_unique_package_name(
+                        u,
+                        &mut package_names,
+                        DefinitionKind::Interface,
+                    )?;
                     log::debug!("new interface `{name}` in {i}");
                     let id = self.next_interface_id;
                     self.next_interface_id += 1;
@@ -162,10 +184,16 @@ impl Generator {
 
                     // This interface is defined at the package level, and it
                     // must be unique.
-                    let prev = package
+                    let prev = ret
+                        .file
                         .interfaces
                         .insert(interface.name.clone(), interface.clone());
                     assert!(prev.is_none());
+                    let prev = ret.file.namespace.insert(
+                        interface.name.clone(),
+                        (DefinitionLevel::Package, DefinitionKind::Interface),
+                    );
+                    assert!(prev.is_none());
 
                     // This is also defined at the file level, and it must be
                     // unique here too.
@@ -176,7 +204,12 @@ impl Generator {
 
                     // Insert the definition into all other files as well.
                     for file in files.iter_mut() {
-                        file.insert_definition(interface.clone());
+                        if file.insert_definition(&interface.name, DefinitionKind::Interface) {
+                            let prev = file
+                                .interfaces
+                                .insert(interface.name.clone(), interface.clone());
+                            assert!(prev.is_none());
+                        }
                     }
 
                     empty = false;
@@ -184,24 +217,38 @@ impl Generator {
                 Generate::Use => {
                     let mut piece = String::new();
                     piece.push_str("use ");
-                    let (name, id, types) = match self.gen_path(u, &mut package, &mut piece)? {
-                        Some(i) => i,
-                        None => continue,
-                    };
+                    let (name, id, types) =
+                        match self.gen_interface_path(u, &mut ret.file, &mut piece)? {
+                            Some(i) => i,
+                            None => continue,
+                        };
                     let name = name.to_string();
                     let types = types.clone();
+                    // If this interface's name already exist within this `file`
+                    // then this must be renamed with `as`. If the name exists
+                    // only at the package level then it's ok to replace it with
+                    // something else.
+                    //
+                    // If the name doesn't exist then use the fuzz input to
+                    // determine whether a rename should happen.
                     let name =
-                        if file.namespace.get(&name) == Some(&Definition::File) || u.arbitrary()? {
-                            let name = file.gen_unique_file_name(u)?;
+                        if matches!(file.namespace.get(&name), Some((DefinitionLevel::File, _)))
+                            || u.arbitrary()?
+                        {
+                            let name = file.gen_unique_file_name(u, DefinitionKind::Interface)?;
                             piece.push_str(" as %");
                             piece.push_str(&name);
                             name
                         } else {
-                            file.namespace.insert(name.clone(), Definition::File);
+                            file.namespace.insert(
+                                name.clone(),
+                                (DefinitionLevel::File, DefinitionKind::Interface),
+                            );
                             name
                         };
                     piece.push_str(";");
                     log::debug!("new use `{name}` in {i}");
+                    file.worlds.swap_remove(&name);
                     file.interfaces
                         .insert(name.clone(), FileInterface { name, id, types });
                     file.items.push(piece)
@@ -240,7 +287,7 @@ impl Generator {
             log::trace!("{s}");
             ret.sources.push(format!("wit{i}.wit").as_ref(), &s);
         }
-        Ok((ret, package.interfaces))
+        Ok(ret)
     }
 
     fn gen_world(
@@ -257,18 +304,18 @@ impl Generator {
         u: &mut Unstructured<'_>,
         name: Option<&str>,
         file: &mut File,
-    ) -> Result<(String, TypeList)> {
+    ) -> Result<(String, Vec<Type>)> {
         let mut generator = InterfaceGenerator::new(self, file);
         let ret = generator.gen_interface(u, name)?;
         Ok((ret, generator.types_in_interface))
     }
 
-    fn gen_path<'a>(
+    fn gen_interface_path<'a>(
         &'a self,
         u: &mut Unstructured<'_>,
         file: &'a mut File,
         dst: &mut String,
-    ) -> Result<Option<(&'a str, u32, &'a Rc<TypeList>)>> {
+    ) -> Result<Option<(&'a str, u32, &'a Rc<Vec<Type>>)>> {
         enum Choice {
             Interfaces,
             Packages,
@@ -277,9 +324,10 @@ impl Generator {
         if !file.interfaces.is_empty() {
             choices.push(Choice::Interfaces);
         }
-        if !self.packages.is_empty() {
+        if !self.packages.packages_with_interfaces.is_empty() {
             choices.push(Choice::Packages);
         }
+
         if choices.is_empty() {
             return Ok(None);
         }
@@ -290,30 +338,90 @@ impl Generator {
                 // Once a name is used from a file's local namespace then it
                 // can't be overridden in that namespace so switch it to a file
                 // definition from whatever it previously was.
-                file.namespace.insert(name.clone(), Definition::File);
+                file.namespace.insert(
+                    name.clone(),
+                    (DefinitionLevel::File, DefinitionKind::Interface),
+                );
+                file.worlds.swap_remove(name);
                 dst.push_str("%");
                 dst.push_str(&i.name);
                 Some((&i.name, i.id, &i.types))
             }
             Choice::Packages => {
-                let (pkg, ifaces) = u.choose(&self.packages)?;
+                let pkg = u.choose(&self.packages.packages_with_interfaces)?;
+                let pkg = &self.packages.list[*pkg];
                 dst.push_str("%");
-                dst.push_str(&pkg.namespace);
+                dst.push_str(&pkg.name.namespace);
                 dst.push_str(":");
                 dst.push_str("%");
-                dst.push_str(&pkg.name);
+                dst.push_str(&pkg.name.name);
                 dst.push_str("/");
-                let i = u.int_in_range(0..=ifaces.len() - 1)?;
-                let i = &ifaces[i];
+                let i = u.int_in_range(0..=pkg.file.interfaces.len() - 1)?;
+                let i = &pkg.file.interfaces[i];
                 dst.push_str("%");
                 dst.push_str(&i.name);
-                if let Some(version) = &pkg.version {
+                if let Some(version) = &pkg.name.version {
                     dst.push_str(&format!("@{version}"));
                 }
                 Some((&i.name, i.id, &i.types))
             }
         })
     }
+
+    fn gen_world_path<'a>(
+        &'a self,
+        u: &mut Unstructured<'_>,
+        file: &'a mut File,
+        dst: &mut String,
+    ) -> Result<Option<&'a str>> {
+        enum Choice {
+            Worlds,
+            Packages,
+        }
+        let mut choices = Vec::new();
+        if !file.worlds.is_empty() {
+            choices.push(Choice::Worlds);
+        }
+        if !self.packages.packages_with_worlds.is_empty() {
+            choices.push(Choice::Packages);
+        }
+
+        if choices.is_empty() {
+            return Ok(None);
+        }
+        Ok(match u.choose(&choices)? {
+            Choice::Worlds => {
+                let i = u.int_in_range(0..=file.worlds.len() - 1)?;
+                let name = &file.worlds[i];
+                dst.push_str("%");
+                dst.push_str(&name);
+                // Same as `gen_interface_path`, once a name is used as a world
+                // it's forced to always be a world so update its definition to
+                // be a file-level world.
+                file.namespace
+                    .insert(name.clone(), (DefinitionLevel::File, DefinitionKind::World));
+                Some(name)
+            }
+            Choice::Packages => {
+                let pkg = u.choose(&self.packages.packages_with_worlds)?;
+                let pkg = &self.packages.list[*pkg];
+                dst.push_str("%");
+                dst.push_str(&pkg.name.namespace);
+                dst.push_str(":");
+                dst.push_str("%");
+                dst.push_str(&pkg.name.name);
+                dst.push_str("/");
+                let i = u.int_in_range(0..=pkg.file.worlds.len() - 1)?;
+                let w = &pkg.file.worlds[i];
+                dst.push_str("%");
+                dst.push_str(&w);
+                if let Some(version) = &pkg.name.version {
+                    dst.push_str(&format!("@{version}"));
+                }
+                Some(w)
+            }
+        })
+    }
 }
 
 impl<'a> InterfaceGenerator<'a> {
@@ -406,6 +514,7 @@ impl<'a> InterfaceGenerator<'a> {
             AnonInterface(Direction),
             Type,
             Use,
+            Include,
         }
 
         let mut parts = Vec::new();
@@ -423,6 +532,7 @@ impl<'a> InterfaceGenerator<'a> {
                 ItemKind::Interface(dir) => (Some(dir), false),
                 ItemKind::Type => (None, true),
                 ItemKind::Use => (None, false),
+                ItemKind::Include => (None, false),
             };
 
             let mut part = String::new();
@@ -454,7 +564,7 @@ impl<'a> InterfaceGenerator<'a> {
                     self.gen_func_sig(u, &mut part, false)?;
                 }
                 ItemKind::Interface(dir) => {
-                    let id = match self.generator.gen_path(u, self.file, &mut part)? {
+                    let id = match self.generator.gen_interface_path(u, self.file, &mut part)? {
                         Some((_name, id, _types)) => id,
                         // If an interface couldn't be chosen or wasn't
                         // chosen then skip this import. A unique name was
@@ -506,6 +616,20 @@ impl<'a> InterfaceGenerator<'a> {
                         continue;
                     }
                 }
+
+                ItemKind::Include => {
+                    part.push_str("include ");
+                    if self
+                        .generator
+                        .gen_world_path(u, self.file, &mut part)?
+                        .is_none()
+                    {
+                        // If an interface couldn't be chosen or wasn't
+                        // chosen then skip this include.
+                        continue;
+                    }
+                    part.push_str(";");
+                }
             }
             parts.push(part);
         }
@@ -578,10 +702,11 @@ impl<'a> InterfaceGenerator<'a> {
 
     fn gen_use(&mut self, u: &mut Unstructured<'_>, part: &mut String) -> Result<bool> {
         let mut path = String::new();
-        let (_name, _id, types) = match self.generator.gen_path(u, self.file, &mut path)? {
-            Some(types) => types,
-            None => return Ok(false),
-        };
+        let (_name, _id, types) =
+            match self.generator.gen_interface_path(u, self.file, &mut path)? {
+                Some(types) => types,
+                None => return Ok(false),
+            };
         part.push_str("use ");
         part.push_str(&path);
         part.push_str(".{");
@@ -722,6 +847,7 @@ impl<'a> InterfaceGenerator<'a> {
             Option,
             Result,
             List,
+            FixedSizeList,
             Stream,
             Future,
             ErrorContext,
@@ -803,6 +929,16 @@ impl<'a> InterfaceGenerator<'a> {
                     self.gen_type(u, fuel, dst)?;
                     dst.push_str(">");
                 }
+                Kind::FixedSizeList => {
+                    *fuel = match fuel.checked_sub(1) {
+                        Some(fuel) => fuel,
+                        None => continue,
+                    };
+                    let elements = u.int_in_range(1..=self.config.max_type_parts as u32)?;
+                    dst.push_str("list<");
+                    self.gen_type(u, fuel, dst)?;
+                    dst.push_str(&format!(", {elements}>"));
+                }
                 Kind::Result => {
                     *fuel = match fuel.checked_sub(2) {
                         Some(fuel) => fuel,
@@ -963,31 +1099,39 @@ fn shuffle<T>(u: &mut Unstructured<'_>, mut slice: &mut [T]) -> Result<()> {
     Ok(())
 }
 
-#[derive(Default)]
+#[derive(Clone, Default)]
 struct File {
     items: Vec<String>,
-    namespace: HashMap<String, Definition>,
+    namespace: HashMap<String, (DefinitionLevel, DefinitionKind)>,
     interfaces: IndexMap<String, FileInterface>,
+    worlds: IndexSet<String>,
 }
 
 #[derive(Clone)]
 struct FileInterface {
     name: String,
     id: u32,
-    types: Rc<TypeList>,
+    types: Rc<Vec<Type>>,
 }
 
-#[derive(PartialEq)]
-enum Definition {
+#[derive(Debug, Copy, Clone, PartialEq)]
+enum DefinitionLevel {
     Package,
     File,
 }
 
+#[derive(Debug, Copy, Clone, PartialEq)]
+enum DefinitionKind {
+    World,
+    Interface,
+}
+
 impl File {
     fn gen_unique_package_name(
         &mut self,
         u: &mut Unstructured<'_>,
         names: &mut HashSet<String>,
+        kind: DefinitionKind,
     ) -> Result<String> {
         let mut name = gen_name(u)?;
         loop {
@@ -998,32 +1142,36 @@ impl File {
             }
 
             // Then make sure it's file-unique too
-            if self.claim_file_name(&mut name) {
+            if self.claim_file_name(&mut name, kind) {
                 break;
             }
         }
         Ok(name)
     }
 
-    fn gen_unique_file_name(&mut self, u: &mut Unstructured<'_>) -> Result<String> {
+    fn gen_unique_file_name(
+        &mut self,
+        u: &mut Unstructured<'_>,
+        kind: DefinitionKind,
+    ) -> Result<String> {
         let mut name = gen_name(u)?;
-        while !self.claim_file_name(&mut name) {
+        while !self.claim_file_name(&mut name, kind) {
             // try again on the next iteration
         }
         Ok(name)
     }
 
-    fn claim_file_name(&mut self, name: &mut String) -> bool {
+    fn claim_file_name(&mut self, name: &mut String, kind: DefinitionKind) -> bool {
         match self.namespace.entry(name.clone()) {
-            Entry::Occupied(mut e) => match e.get() {
+            Entry::Occupied(mut e) => match e.get().0 {
                 // If this name is already claimed elsewhere in the package
                 // then that's ok as we're going to shadow it, so switch it
                 // to a file definition.
-                Definition::Package => *e.get_mut() = Definition::File,
+                DefinitionLevel::Package => *e.get_mut() = (DefinitionLevel::File, kind),
 
                 // If it's already defined in the file try to add more stuff
                 // to the name to make the next try not collide.
-                Definition::File => {
+                DefinitionLevel::File => {
                     name.push_str("y");
                     write!(name, "{}", self.namespace.len()).unwrap();
                     return false;
@@ -1032,22 +1180,26 @@ impl File {
 
             // Not defined? Claim it.
             Entry::Vacant(v) => {
-                v.insert(Definition::File);
+                v.insert((DefinitionLevel::File, kind));
             }
         }
         true
     }
 
-    fn insert_definition(&mut self, def: FileInterface) {
-        match self.namespace.get(&def.name) {
-            Some(Definition::File) => return,
-            Some(Definition::Package) => unreachable!(),
+    fn insert_definition(&mut self, name: &str, kind: DefinitionKind) -> bool {
+        match self.namespace.get(name) {
+            // This name is already defined, so it can't be inserted.
+            Some((DefinitionLevel::File, _)) => return false,
+            Some(other) => {
+                panic!("found duplicate definition when should be package-unique: {other:?}")
+            }
             None => {}
         }
-        let prev = self.namespace.insert(def.name.clone(), Definition::Package);
-        assert!(prev.is_none());
-        let prev = self.interfaces.insert(def.name.clone(), def);
+        let prev = self
+            .namespace
+            .insert(name.to_string(), (DefinitionLevel::Package, kind));
         assert!(prev.is_none());
+        true
     }
 }
 
diff --git a/crates/wit-smith/src/lib.rs b/crates/wit-smith/src/lib.rs
index 73e6df68..b29ab4b2 100644
--- a/crates/wit-smith/src/lib.rs
+++ b/crates/wit-smith/src/lib.rs
@@ -28,6 +28,9 @@ pub fn smith(config: &Config, u: &mut Unstructured<'_>) -> Result<Vec<u8>> {
                 if e.is::<InvalidTransitiveDependency>() {
                     return Err(arbitrary::Error::IncorrectFormat);
                 }
+                if e.to_string().contains("shadows previously") {
+                    return Err(arbitrary::Error::IncorrectFormat);
+                }
                 panic!("bad wit parse: {e:?}")
             }
         };
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 658c2015..f5152552 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -14,7 +14,6 @@ workspace = true
 anyhow = { workspace = true }
 arbitrary = { workspace = true }
 env_logger = { workspace = true }
-libfuzzer-sys = { workspace = true }
 log = { workspace = true }
 tempfile = "3.0"
 wasm-encoder = { workspace = true }
@@ -37,8 +36,13 @@ version = '0.214.0'
 package = 'wit-component'
 version = '0.214.0'
 
+[target.'cfg(fuzzing)'.dependencies]
+libfuzzer-sys = { workspace = true }
+
+[dev-dependencies]
+rand = { workspace = true }
+
 [lib]
-test = false
 doctest = false
 
 [[bin]]
diff --git a/fuzz/fuzz_targets/run.rs b/fuzz/fuzz_targets/run.rs
index 45275329..b9e08a8b 100644
--- a/fuzz/fuzz_targets/run.rs
+++ b/fuzz/fuzz_targets/run.rs
@@ -1,9 +1,19 @@
-#![no_main]
+#![cfg_attr(fuzzing, no_main)]
 
 use arbitrary::Unstructured;
-use libfuzzer_sys::fuzz_target;
 use std::sync::OnceLock;
 
+#[cfg(fuzzing)]
+use libfuzzer_sys::fuzz_target;
+#[cfg(not(fuzzing))]
+macro_rules! fuzz_target {
+    ($e:expr) => {
+        fn main() {
+            let _ = $e(&[]);
+        }
+    };
+}
+
 // Helper macro which takes a static list of fuzzers as input which are then
 // delegated to internally based on the fuzz target selected.
 //
diff --git a/fuzz/src/incremental_parse.rs b/fuzz/src/incremental_parse.rs
index 42fc2461..5817cf0f 100644
--- a/fuzz/src/incremental_parse.rs
+++ b/fuzz/src/incremental_parse.rs
@@ -217,3 +217,8 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
     }
     Ok(())
 }
+
+#[test]
+fn smoke() {
+    super::test::test_n_times(100, run);
+}
diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs
index ff0af0a2..6f34f68b 100644
--- a/fuzz/src/lib.rs
+++ b/fuzz/src/lib.rs
@@ -1,4 +1,4 @@
-use libfuzzer_sys::arbitrary::{Result, Unstructured};
+use arbitrary::{Result, Unstructured};
 use std::fmt::Debug;
 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
 use wasm_smith::{Component, Config, Module};
@@ -105,3 +105,39 @@ pub fn log_wasm(wasm: &[u8], config: impl Debug) {
         drop(std::fs::remove_file(&wat_file));
     }
 }
+#[cfg(test)]
+mod test {
+    use arbitrary::{Result, Unstructured};
+    use rand::{rngs::SmallRng, RngCore, SeedableRng};
+
+    fn gen_until_pass(mut f: impl FnMut(&mut Unstructured<'_>) -> Result<bool>) -> bool {
+        let mut rng = SmallRng::seed_from_u64(0);
+        let mut buf = vec![0; 2048];
+        let n = 3000;
+        for _ in 0..n {
+            rng.fill_bytes(&mut buf);
+            let mut u = Unstructured::new(&buf);
+
+            if f(&mut u).unwrap() {
+                return true;
+            }
+        }
+        false
+    }
+
+    /// Runs `f` with random data until it returns `Ok(())` `iters` times.
+    pub fn test_n_times(
+        iters: u32,
+        mut f: impl FnMut(&mut Unstructured<'_>) -> arbitrary::Result<()>,
+    ) {
+        let mut to_test = 0..iters;
+        let ok = gen_until_pass(|b| {
+            if f(b).is_ok() {
+                Ok(to_test.next().is_none())
+            } else {
+                Ok(false)
+            }
+        });
+        assert!(ok);
+    }
+}
diff --git a/fuzz/src/mutate.rs b/fuzz/src/mutate.rs
index 88d37902..c0c295b4 100644
--- a/fuzz/src/mutate.rs
+++ b/fuzz/src/mutate.rs
@@ -329,3 +329,8 @@ mod eval {
         }
     }
 }
+
+#[test]
+fn smoke() {
+    super::test::test_n_times(100, run);
+}
diff --git a/fuzz/src/no_traps.rs b/fuzz/src/no_traps.rs
index b3d7d81a..9f6f5df4 100644
--- a/fuzz/src/no_traps.rs
+++ b/fuzz/src/no_traps.rs
@@ -122,3 +122,8 @@ fn validate_module(wasm_bytes: &Vec<u8>) {
         panic!("Invalid module: {e}");
     }
 }
+
+#[test]
+fn smoke() {
+    super::test::test_n_times(100, run);
+}
diff --git a/fuzz/src/print.rs b/fuzz/src/print.rs
index 1e549f32..6723d4c6 100644
--- a/fuzz/src/print.rs
+++ b/fuzz/src/print.rs
@@ -13,3 +13,8 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
     let _ = cfg.print(&data, &mut wasmprinter::PrintFmtWrite(&mut dst));
     Ok(())
 }
+
+#[test]
+fn smoke() {
+    super::test::test_n_times(100, run);
+}
diff --git a/fuzz/src/reencode.rs b/fuzz/src/reencode.rs
index 7e27dbb3..692ef23f 100644
--- a/fuzz/src/reencode.rs
+++ b/fuzz/src/reencode.rs
@@ -19,3 +19,8 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
 
     Ok(())
 }
+
+#[test]
+fn smoke() {
+    super::test::test_n_times(100, run);
+}
diff --git a/fuzz/src/roundtrip_wit.rs b/fuzz/src/roundtrip_wit.rs
index 6f5e3c41..b1eb5ba8 100644
--- a/fuzz/src/roundtrip_wit.rs
+++ b/fuzz/src/roundtrip_wit.rs
@@ -188,3 +188,8 @@ impl Reencode for RemoveImports<'_, '_> {
         }
     }
 }
+
+#[test]
+fn smoke() {
+    super::test::test_n_times(100, run);
+}
diff --git a/fuzz/src/validate.rs b/fuzz/src/validate.rs
index ff14c187..2b87023b 100644
--- a/fuzz/src/validate.rs
+++ b/fuzz/src/validate.rs
@@ -109,3 +109,8 @@ fn validate_all(u: &mut Unstructured<'_>, mut validator: Validator, wasm: &[u8])
 
     Ok(())
 }
+
+#[test]
+fn smoke() {
+    super::test::test_n_times(100, run);
+}
diff --git a/fuzz/src/validate_valid_module.rs b/fuzz/src/validate_valid_module.rs
index ff23e336..dc471673 100644
--- a/fuzz/src/validate_valid_module.rs
+++ b/fuzz/src/validate_valid_module.rs
@@ -66,3 +66,8 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
     }
     Ok(())
 }
+
+#[test]
+fn smoke() {
+    super::test::test_n_times(100, run);
+}
diff --git a/fuzz/src/wit64.rs b/fuzz/src/wit64.rs
index 6060b754..cbaa7012 100644
--- a/fuzz/src/wit64.rs
+++ b/fuzz/src/wit64.rs
@@ -118,3 +118,8 @@ fn write_file(path: &str, contents: impl AsRef<[u8]>) {
         std::fs::write(path, wasmprinter::print_bytes(&contents).unwrap()).unwrap();
     }
 }
+
+#[test]
+fn smoke() {
+    super::test::test_n_times(100, run);
+}


Test patch:
diff --git a/crates/wit-component/tests/components/async-builtins/component.wat b/crates/wit-component/tests/components/async-builtins/component.wat
index ff4caf87..e84346ac 100644
--- a/crates/wit-component/tests/components/async-builtins/component.wat
+++ b/crates/wit-component/tests/components/async-builtins/component.wat
@@ -16,7 +16,7 @@
     (import "$root" "[waitable-set-poll]" (func (;6;) (type 4)))
     (import "$root" "[waitable-set-drop]" (func (;7;) (type 0)))
     (import "$root" "[waitable-join]" (func (;8;) (type 2)))
-    (import "$root" "[yield]" (func (;9;) (type 1)))
+    (import "$root" "[yield]" (func (;9;) (type 3)))
     (import "$root" "[subtask-drop]" (func (;10;) (type 0)))
     (import "$root" "[subtask-cancel]" (func (;11;) (type 5)))
     (import "$root" "[error-context-new-utf8]" (func (;12;) (type 4)))
diff --git a/crates/wit-component/tests/components/async-builtins/module.wat b/crates/wit-component/tests/components/async-builtins/module.wat
index ba3fadc7..adb7a582 100644
--- a/crates/wit-component/tests/components/async-builtins/module.wat
+++ b/crates/wit-component/tests/components/async-builtins/module.wat
@@ -8,7 +8,7 @@
   (import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32)))
   (import "$root" "[waitable-set-drop]" (func (param i32)))
   (import "$root" "[waitable-join]" (func (param i32 i32)))
-  (import "$root" "[yield]" (func))
+  (import "$root" "[yield]" (func (result i32)))
   (import "$root" "[subtask-drop]" (func (param i32)))
   (import "$root" "[subtask-cancel]" (func (param i32) (result i32)))
   (import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32)))
diff --git a/crates/wit-component/tests/interfaces/doc-comments/foo.wit.print b/crates/wit-component/tests/interfaces/doc-comments/foo.wit.print
index 3ef196c3..7f31dbf9 100644
--- a/crates/wit-component/tests/interfaces/doc-comments/foo.wit.print
+++ b/crates/wit-component/tests/interfaces/doc-comments/foo.wit.print
@@ -60,11 +60,10 @@ interface other-comment-forms {
 
 /// world docs
 world coverage-world {
-  /// world func import docs
-  import imp: func();
-
   /// world typedef docs
   type t = u32;
+  /// world func import docs
+  import imp: func();
 
   /// world func export docs
   export exp: func();
diff --git a/crates/wit-component/tests/interfaces/resources.wat b/crates/wit-component/tests/interfaces/resources.wat
index 3d07b806..c4a8a9d3 100644
--- a/crates/wit-component/tests/interfaces/resources.wat
+++ b/crates/wit-component/tests/interfaces/resources.wat
@@ -100,6 +100,20 @@
       (type (;0;)
         (component
           (type (;0;)
+            (instance
+              (export (;0;) "a" (type (sub resource)))
+              (type (;1;) (own 0))
+              (type (;2;) (func (result 1)))
+              (export (;0;) "[constructor]a" (func (type 2)))
+              (type (;3;) (func))
+              (export (;1;) "[static]a.b" (func (type 3)))
+              (type (;4;) (borrow 0))
+              (type (;5;) (func (param "self" 4)))
+              (export (;2;) "[method]a.c" (func (type 5)))
+            )
+          )
+          (import "anon" (instance (;0;) (type 0)))
+          (type (;1;)
             (instance
               (export (;0;) "bar" (type (sub resource)))
               (export (;1;) "t" (type (eq 0)))
@@ -117,14 +131,14 @@
               (export (;3;) "a" (func (type 9)))
             )
           )
-          (import "foo:bar/foo" (instance (;0;) (type 0)))
-          (alias export 0 "bar" (type (;1;)))
-          (alias export 0 "t" (type (;2;)))
-          (type (;3;)
+          (import "foo:bar/foo" (instance (;1;) (type 1)))
+          (alias export 1 "bar" (type (;2;)))
+          (alias export 1 "t" (type (;3;)))
+          (type (;4;)
             (instance
-              (alias outer 1 1 (type (;0;)))
+              (alias outer 1 2 (type (;0;)))
               (export (;1;) "bar" (type (eq 0)))
-              (alias outer 1 2 (type (;2;)))
+              (alias outer 1 3 (type (;2;)))
               (export (;3;) "t" (type (eq 2)))
               (type (;4;) (own 1))
               (type (;5;) (func (param "x" 4) (result 4)))
@@ -134,29 +148,15 @@
               (export (;1;) "b" (func (type 7)))
             )
           )
-          (import "foo:bar/baz" (instance (;1;) (type 3)))
-          (alias export 1 "bar" (type (;4;)))
-          (import "bar" (type (;5;) (eq 4)))
-          (import "a" (type (;6;) (sub resource)))
-          (type (;7;)
-            (instance
-              (export (;0;) "a" (type (sub resource)))
-              (type (;1;) (own 0))
-              (type (;2;) (func (result 1)))
-              (export (;0;) "[constructor]a" (func (type 2)))
-              (type (;3;) (func))
-              (export (;1;) "[static]a.b" (func (type 3)))
-              (type (;4;) (borrow 0))
-              (type (;5;) (func (param "self" 4)))
-              (export (;2;) "[method]a.c" (func (type 5)))
-            )
-          )
-          (import "anon" (instance (;2;) (type 7)))
-          (type (;8;) (own 6))
+          (import "foo:bar/baz" (instance (;2;) (type 4)))
+          (alias export 2 "bar" (type (;5;)))
+          (import "bar" (type (;6;) (eq 5)))
+          (import "a" (type (;7;) (sub resource)))
+          (type (;8;) (own 7))
           (type (;9;) (func (result 8)))
           (import "[constructor]a" (func (;0;) (type 9)))
           (export (;1;) "x" (func (type 9)))
-          (type (;10;) (own 5))
+          (type (;10;) (own 6))
           (type (;11;) (func (result 10)))
           (export (;2;) "y" (func (type 11)))
         )
diff --git a/crates/wit-component/tests/interfaces/resources.wit.print b/crates/wit-component/tests/interfaces/resources.wit.print
index 6f386b6d..c52d6744 100644
--- a/crates/wit-component/tests/interfaces/resources.wit.print
+++ b/crates/wit-component/tests/interfaces/resources.wit.print
@@ -50,8 +50,6 @@ interface implicit-own-handles2 {
 }
 
 world some-world {
-  import foo;
-  import baz;
   import anon: interface {
     resource a {
       constructor();
@@ -59,6 +57,8 @@ world some-world {
       c: func();
     }
   }
+  import foo;
+  import baz;
   use baz.{bar};
 
   resource a {
diff --git a/crates/wit-component/tests/interfaces/world-top-level.wat b/crates/wit-component/tests/interfaces/world-top-level.wat
index 347066ec..4afcebfc 100644
--- a/crates/wit-component/tests/interfaces/world-top-level.wat
+++ b/crates/wit-component/tests/interfaces/world-top-level.wat
@@ -3,15 +3,15 @@
     (component
       (type (;0;)
         (component
-          (type (;0;) (func))
-          (import "foo" (func (;0;) (type 0)))
-          (type (;1;) (func (param "arg" u32)))
-          (import "bar" (func (;1;) (type 1)))
-          (type (;2;)
+          (type (;0;)
             (instance)
           )
-          (import "some-interface" (instance (;0;) (type 2)))
-          (export (;2;) "foo2" (func (type 0)))
+          (import "some-interface" (instance (;0;) (type 0)))
+          (type (;1;) (func))
+          (import "foo" (func (;0;) (type 1)))
+          (type (;2;) (func (param "arg" u32)))
+          (import "bar" (func (;1;) (type 2)))
+          (export (;2;) "foo2" (func (type 1)))
           (type (;3;) (func (result u32)))
           (export (;3;) "bar2" (func (type 3)))
           (type (;4;)
diff --git a/crates/wit-component/tests/interfaces/world-top-level.wit.print b/crates/wit-component/tests/interfaces/world-top-level.wit.print
index 5308f654..b28325ef 100644
--- a/crates/wit-component/tests/interfaces/world-top-level.wit.print
+++ b/crates/wit-component/tests/interfaces/world-top-level.wit.print
@@ -1,10 +1,10 @@
 package foo:foo;
 
 world foo {
-  import foo: func();
-  import bar: func(arg: u32);
   import some-interface: interface {
   }
+  import foo: func();
+  import bar: func(arg: u32);
 
   export foo2: func();
   export bar2: func() -> u32;
diff --git a/crates/wit-component/tests/interfaces/worlds-with-types.wit.print b/crates/wit-component/tests/interfaces/worlds-with-types.wit.print
index 147e1219..1c4d0e3d 100644
--- a/crates/wit-component/tests/interfaces/worlds-with-types.wit.print
+++ b/crates/wit-component/tests/interfaces/worlds-with-types.wit.print
@@ -5,20 +5,19 @@ interface import-me {
 }
 
 world simple {
-  import a: func(a: foo) -> bar;
-
   record foo {
     f: u8,
   }
 
   type bar = foo;
+  import a: func(a: foo) -> bar;
 
   export b: func(a: foo) -> bar;
 }
 world with-imports {
   import import-me;
-  import a: func(a: foo);
   use import-me.{foo};
+  import a: func(a: foo);
 
   export b: func(a: foo);
 }
diff --git a/crates/wit-parser/tests/ui/gated-include-use-with-stable.wit.json b/crates/wit-parser/tests/ui/gated-include-use-with-stable.wit.json
index 471d6b4c..b7f857b1 100644
--- a/crates/wit-parser/tests/ui/gated-include-use-with-stable.wit.json
+++ b/crates/wit-parser/tests/ui/gated-include-use-with-stable.wit.json
@@ -106,9 +106,6 @@
             }
           }
         },
-        "stable-resource": {
-          "type": 3
-        },
         "interface-1": {
           "interface": {
             "id": 1,
@@ -119,9 +116,6 @@
             }
           }
         },
-        "unversioned-resource": {
-          "type": 4
-        },
         "interface-0": {
           "interface": {
             "id": 0,
@@ -132,6 +126,12 @@
             }
           }
         },
+        "stable-resource": {
+          "type": 3
+        },
+        "unversioned-resource": {
+          "type": 4
+        },
         "unstable-resource": {
           "type": 5
         }
@@ -157,9 +157,6 @@
             }
           }
         },
-        "stable-resource": {
-          "type": 3
-        },
         "interface-1": {
           "interface": {
             "id": 1,
@@ -170,9 +167,6 @@
             }
           }
         },
-        "unversioned-resource": {
-          "type": 4
-        },
         "interface-0": {
           "interface": {
             "id": 0,
@@ -183,6 +177,12 @@
             }
           }
         },
+        "stable-resource": {
+          "type": 3
+        },
+        "unversioned-resource": {
+          "type": 4
+        },
         "unstable-resource": {
           "type": 5
         }
diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list2.wit b/crates/wit-parser/tests/ui/parse-fail/bad-list2.wit
new file mode 100644
index 00000000..4313c549
--- /dev/null
+++ b/crates/wit-parser/tests/ui/parse-fail/bad-list2.wit
@@ -0,0 +1,7 @@
+// parse-fail
+
+interface foo {
+  type z = list<u32,
+
+  type y = u32
+}
diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list2.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-list2.wit.result
new file mode 100644
index 00000000..94b02e2a
--- /dev/null
+++ b/crates/wit-parser/tests/ui/parse-fail/bad-list2.wit.result
@@ -0,0 +1,5 @@
+expected fixed size, found keyword `type`
+     --> tests/ui/parse-fail/bad-list2.wit:6:3
+      |
+    6 |   type y = u32
+      |   ^---
\ No newline at end of file
diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit b/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit
new file mode 100644
index 00000000..1f0238ea
--- /dev/null
+++ b/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit
@@ -0,0 +1,7 @@
+// parse-fail
+
+interface foo {
+  type a = list<u32,>
+
+  type y = u32
+}
diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit.result
new file mode 100644
index 00000000..4f48238f
--- /dev/null
+++ b/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit.result
@@ -0,0 +1,5 @@
+expected fixed size, found '>'
+     --> tests/ui/parse-fail/bad-list3.wit:4:21
+      |
+    4 |   type a = list<u32,>
+      |                     ^
\ No newline at end of file
diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit b/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit
new file mode 100644
index 00000000..14fa344d
--- /dev/null
+++ b/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit
@@ -0,0 +1,7 @@
+// parse-fail
+
+interface foo {
+  type b = list<u32, u32>
+
+  type y = u32
+}
diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit.result
new file mode 100644
index 00000000..c2aae207
--- /dev/null
+++ b/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit.result
@@ -0,0 +1,5 @@
+expected fixed size, found keyword `u32`
+     --> tests/ui/parse-fail/bad-list4.wit:4:22
+      |
+    4 |   type b = list<u32, u32>
+      |                      ^--
\ No newline at end of file
diff --git a/crates/wit-parser/tests/ui/since-and-unstable.wit.json b/crates/wit-parser/tests/ui/since-and-unstable.wit.json
index ad483746..851694ac 100644
--- a/crates/wit-parser/tests/ui/since-and-unstable.wit.json
+++ b/crates/wit-parser/tests/ui/since-and-unstable.wit.json
@@ -25,6 +25,26 @@
     {
       "name": "in-a-world",
       "imports": {
+        "y": {
+          "interface": {
+            "id": 6,
+            "stability": {
+              "stable": {
+                "since": "1.0.0"
+              }
+            }
+          }
+        },
+        "interface-4": {
+          "interface": {
+            "id": 4,
+            "stability": {
+              "stable": {
+                "since": "1.0.0"
+              }
+            }
+          }
+        },
         "t1": {
           "type": 11
         },
@@ -58,26 +78,6 @@
             }
           }
         },
-        "y": {
-          "interface": {
-            "id": 6,
-            "stability": {
-              "stable": {
-                "since": "1.0.0"
-              }
-            }
-          }
-        },
-        "interface-4": {
-          "interface": {
-            "id": 4,
-            "stability": {
-              "stable": {
-                "since": "1.0.0"
-              }
-            }
-          }
-        },
         "[constructor]t7": {
           "function": {
             "name": "[constructor]t7",
diff --git a/crates/wit-parser/tests/ui/types.wit b/crates/wit-parser/tests/ui/types.wit
index d6793979..5a644f30 100644
--- a/crates/wit-parser/tests/ui/types.wit
+++ b/crates/wit-parser/tests/ui/types.wit
@@ -50,6 +50,8 @@ interface types {
   type t48 = stream<u32>;
   type t49 = future<u32>;
   type t50 = future;
+  type t51a = list<u32, 4>;
+  type t51b = list<list<u32, 4>, 2>;
 
   /// type order doesn't matter
   type foo = bar;
diff --git a/crates/wit-parser/tests/ui/types.wit.json b/crates/wit-parser/tests/ui/types.wit.json
index 1b5e70e5..a8dfbc81 100644
--- a/crates/wit-parser/tests/ui/types.wit.json
+++ b/crates/wit-parser/tests/ui/types.wit.json
@@ -53,8 +53,10 @@
         "t48": 49,
         "t49": 50,
         "t50": 51,
-        "bar": 52,
-        "foo": 53
+        "t51a": 52,
+        "t51b": 54,
+        "bar": 55,
+        "foo": 56
       },
       "functions": {},
       "package": 0
@@ -698,6 +700,40 @@
         "interface": 0
       }
     },
+    {
+      "name": "t51a",
+      "kind": {
+        "fixed-size-list": [
+          "u32",
+          4
+        ]
+      },
+      "owner": {
+        "interface": 0
+      }
+    },
+    {
+      "name": null,
+      "kind": {
+        "fixed-size-list": [
+          "u32",
+          4
+        ]
+      },
+      "owner": null
+    },
+    {
+      "name": "t51b",
+      "kind": {
+        "fixed-size-list": [
+          53,
+          2
+        ]
+      },
+      "owner": {
+        "interface": 0
+      }
+    },
     {
       "name": "bar",
       "kind": {
@@ -710,7 +746,7 @@
     {
       "name": "foo",
       "kind": {
-        "type": 52
+        "type": 55
       },
       "owner": {
         "interface": 0
diff --git a/tests/cli/component-model-async/task-builtins.wast b/tests/cli/component-model-async/task-builtins.wast
index f1bca5d9..2cb8ed64 100644
--- a/tests/cli/component-model-async/task-builtins.wast
+++ b/tests/cli/component-model-async/task-builtins.wast
@@ -182,7 +182,7 @@
 ;; yield
 (component
   (core module $m
-    (import "" "yield" (func $yield))
+    (import "" "yield" (func $yield (result i32)))
   )
   (core func $yield (canon yield async))
   (core instance $i (instantiate $m (with "" (instance (export "yield" (func $yield))))))
diff --git a/tests/cli/component-model/fixed-size-list.wast b/tests/cli/component-model/fixed-size-list.wast
new file mode 100644
index 00000000..63b8943f
--- /dev/null
+++ b/tests/cli/component-model/fixed-size-list.wast
@@ -0,0 +1,79 @@
+;; RUN: wast % --assert default --snapshot tests/snapshots -f cm-fixed-size-list
+
+(component
+  (core module $m
+    (memory (export "memory") 1)
+    (func (export "ret-list") (result i32) unreachable)
+  )
+  (core instance $i (instantiate $m))
+
+  (func (export "ret-list") (result (list u32 4))
+    (canon lift (core func $i "ret-list") (memory $i "memory"))
+  )
+)
+
+(component
+  (core module $m
+    (func (export "param-list") (param i32 i32 i32 i32) unreachable)
+  )
+  (core instance $i (instantiate $m))
+
+  (func (export "param-list") (param "l" (list u32 4))
+    (canon lift (core func $i "param-list"))
+  )
+)
+
+(assert_invalid
+  (component
+    (core module $m
+      (memory (export "memory") 1)
+      (func (export "ret-list") (result i32) unreachable)
+    )
+    (core instance $i (instantiate $m))
+
+    (func (export "ret-list") (result (list u32 0))
+      (canon lift (core func $i "ret-list") (memory $i "memory"))
+    )
+  )
+  "Fixed size lists must have more than zero elements (at offset 0x54)"
+)
+
+(assert_malformed
+  (component quote
+    "(core module $m"
+      "(memory (export \"memory\") 1)"
+      "(func (export \"ret-list\") (result i32) unreachable)"
+    ")"
+    "(core instance $i (instantiate $m))"
+
+    "(func (export \"ret-list\") (result (list u32 10000000000))"
+      "(canon lift (core func $i \"ret-list\") (memory $i \"memory\"))"
+    ")"
+  )
+  "invalid u32 number: constant out of range"
+)
+
+(assert_invalid
+  (component
+    (import "y" (component $c
+      (type $t (list s32 10))
+      (import "x" (type (eq $t)))
+    ))
+
+    (type $x (list u32 9))
+    (instance (instantiate $c (with "x" (type $x))))
+  )
+  "type mismatch for import `x`")
+
+
+(assert_invalid
+  (component
+    (import "y" (component $c
+      (type $t (list s32 10))
+      (import "x" (type (eq $t)))
+    ))
+
+    (type $x (list u32))
+    (instance (instantiate $c (with "x" (type $x))))
+  )
+  "type mismatch for import `x`")
diff --git a/tests/cli/importize.wit.simple-rename.stdout b/tests/cli/importize.wit.simple-rename.stdout
index 64612e20..1514dbe8 100644
--- a/tests/cli/importize.wit.simple-rename.stdout
+++ b/tests/cli/importize.wit.simple-rename.stdout
@@ -78,11 +78,11 @@ world fail1 {
 }
 world trim-imports {
   import a;
-  import foo: func();
   import bar: interface {
   }
 
   type t = u32;
+  import foo: func();
 
   export b;
 }
diff --git a/tests/cli/importize.wit.simple-toplevel.stdout b/tests/cli/importize.wit.simple-toplevel.stdout
index 10aff4d9..47994748 100644
--- a/tests/cli/importize.wit.simple-toplevel.stdout
+++ b/tests/cli/importize.wit.simple-toplevel.stdout
@@ -75,11 +75,11 @@ world fail1 {
 }
 world trim-imports {
   import a;
-  import foo: func();
   import bar: interface {
   }
 
   type t = u32;
+  import foo: func();
 
   export b;
 }
@@ -90,8 +90,8 @@ world tricky-import {
   export f: func() -> t;
 }
 world simple-toplevel-importized {
-  import foo: func();
   import something: interface {
     foo: func();
   }
+  import foo: func();
 }
diff --git a/tests/cli/importize.wit.simple.stdout b/tests/cli/importize.wit.simple.stdout
index 1bdb5c80..7e13e853 100644
--- a/tests/cli/importize.wit.simple.stdout
+++ b/tests/cli/importize.wit.simple.stdout
@@ -78,11 +78,11 @@ world fail1 {
 }
 world trim-imports {
   import a;
-  import foo: func();
   import bar: interface {
   }
 
   type t = u32;
+  import foo: func();
 
   export b;
 }
diff --git a/tests/cli/importize.wit.toplevel-deps.stdout b/tests/cli/importize.wit.toplevel-deps.stdout
index e187bd06..f9247fc1 100644
--- a/tests/cli/importize.wit.toplevel-deps.stdout
+++ b/tests/cli/importize.wit.toplevel-deps.stdout
@@ -69,11 +69,11 @@ world fail1 {
 }
 world trim-imports {
   import a;
-  import foo: func();
   import bar: interface {
   }
 
   type t = u32;
+  import foo: func();
 
   export b;
 }
@@ -84,7 +84,6 @@ world tricky-import {
   export f: func() -> t;
 }
 world toplevel-deps-importized {
-  import bar: func() -> s;
   import something-else-dep;
   import something-else: interface {
     use something-else-dep.{t};
@@ -93,4 +92,5 @@ world toplevel-deps-importized {
   }
 
   type s = u32;
+  import bar: func() -> s;
 }
diff --git a/tests/cli/importize.wit.tricky-import.stdout b/tests/cli/importize.wit.tricky-import.stdout
index 08d2d563..c89d0acf 100644
--- a/tests/cli/importize.wit.tricky-import.stdout
+++ b/tests/cli/importize.wit.tricky-import.stdout
@@ -81,16 +81,16 @@ world fail1 {
 }
 world trim-imports {
   import a;
-  import foo: func();
   import bar: interface {
   }
 
   type t = u32;
+  import foo: func();
 
   export b;
 }
 world tricky-import-importized {
   import with-dep;
-  import f: func() -> t;
   use with-dep.{t};
+  import f: func() -> t;
 }
diff --git a/tests/cli/importize.wit.with-deps.stdout b/tests/cli/importize.wit.with-deps.stdout
index 9b567ad3..97bef88d 100644
--- a/tests/cli/importize.wit.with-deps.stdout
+++ b/tests/cli/importize.wit.with-deps.stdout
@@ -75,11 +75,11 @@ world fail1 {
 }
 world trim-imports {
   import a;
-  import foo: func();
   import bar: interface {
   }
 
   type t = u32;
+  import foo: func();
 
   export b;
 }
diff --git a/tests/cli/missing-features/component-model/fixed-size-list.wast b/tests/cli/missing-features/component-model/fixed-size-list.wast
new file mode 100644
index 00000000..b6a92ada
--- /dev/null
+++ b/tests/cli/missing-features/component-model/fixed-size-list.wast
@@ -0,0 +1,30 @@
+;; RUN: wast % --assert default --snapshot tests/snapshots
+
+(assert_invalid
+  (component
+    (core module $m
+      (memory (export "memory") 1)
+      (func (export "ret-list") (result i32) unreachable)
+    )
+    (core instance $i (instantiate $m))
+
+    (func (export "ret-list") (result (list u32 4))
+      (canon lift (core func $i "ret-list") (memory $i "memory"))
+    )
+  )
+  "Fixed size lists require the component model fixed size list feature (at offset 0x54)"
+)
+
+(assert_invalid
+  (component
+    (core module $m
+      (func (export "param-list") (param i32 i32 i32 i32) unreachable)
+    )
+    (core instance $i (instantiate $m))
+
+    (func (export "param-list") (param "l" (list u32 4))
+      (canon lift (core func $i "param-list"))
+    )
+  )
+  "Fixed size lists require the component model fixed size list feature"
+)
diff --git a/tests/cli/validate-unknown-features.wat.stderr b/tests/cli/validate-unknown-features.wat.stderr
index 1c6e4539..6c52f3ea 100644
--- a/tests/cli/validate-unknown-features.wat.stderr
+++ b/tests/cli/validate-unknown-features.wat.stderr
@@ -1,4 +1,4 @@
 error: invalid value 'unknown' for '--features <FEATURES>': unknown feature `unknown`
-Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, legacy-exceptions, gc-types, stack-switching, wide-arithmetic, cm-values, cm-nested-names, cm-async, cm-async-stackful, cm-async-builtins, cm-error-context, mvp, wasm1, wasm2, wasm3, all
+Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, legacy-exceptions, gc-types, stack-switching, wide-arithmetic, cm-values, cm-nested-names, cm-async, cm-async-stackful, cm-async-builtins, cm-error-context, cm-fixed-size-list, mvp, wasm1, wasm2, wasm3, all
 
 For more information, try '--help'.
diff --git a/tests/cli/wit-stability-in-binary-format.wit.stdout b/tests/cli/wit-stability-in-binary-format.wit.stdout
index 45db6e8b..54a0a939 100644
--- a/tests/cli/wit-stability-in-binary-format.wit.stdout
+++ b/tests/cli/wit-stability-in-binary-format.wit.stdout
@@ -25,13 +25,13 @@ world w {
   @since(version = 1.0.0)
   import foo;
   @since(version = 1.0.0)
-  import f: func();
-  @since(version = 1.0.0)
   import a: interface {
   }
 
   @since(version = 1.0.0)
   type t = u32;
+  @since(version = 1.0.0)
+  import f: func();
 
   @since(version = 1.0.0)
   export f: func();
diff --git a/tests/cli/wit-with-features.wit.stdout b/tests/cli/wit-with-features.wit.stdout
index b402b6aa..f188b45e 100644
--- a/tests/cli/wit-with-features.wit.stdout
+++ b/tests/cli/wit-with-features.wit.stdout
@@ -39,14 +39,14 @@ interface another-interface {
 world the-world {
   @unstable(feature = foo)
   import foo;
-  @unstable(feature = foo)
-  import x: func();
 
   @unstable(feature = foo)
   resource thing {
     @unstable(feature = foo)
     constructor();
   }
+  @unstable(feature = foo)
+  import x: func();
 
   @unstable(feature = foo)
   export y: func();
diff --git a/tests/cli/world-merging-add-imports.wit.stdout b/tests/cli/world-merging-add-imports.wit.stdout
index 6f0064d4..80d325e6 100644
--- a/tests/cli/world-merging-add-imports.wit.stdout
+++ b/tests/cli/world-merging-add-imports.wit.stdout
@@ -1,11 +1,11 @@
 package root:root;
 
 world root {
-  import a:b/b;
   import a: interface {
   }
-  import c: func() -> t;
+  import a:b/b;
   use a:b/b.{t};
+  import c: func() -> t;
 }
 package a:b {
   interface b {
@@ -14,10 +14,10 @@ package a:b {
   world into {
   }
   world %from {
-    import b;
     import a: interface {
     }
-    import c: func() -> t;
+    import b;
     use b.{t};
+    import c: func() -> t;
   }
 }
diff --git a/tests/cli/world-merging-same-imports.wit.stdout b/tests/cli/world-merging-same-imports.wit.stdout
index 90090844..e5c366b4 100644
--- a/tests/cli/world-merging-same-imports.wit.stdout
+++ b/tests/cli/world-merging-same-imports.wit.stdout
@@ -1,28 +1,28 @@
 package root:root;
 
 world root {
-  import a:b/b;
   import a: interface {
   }
-  import c: func();
+  import a:b/b;
   use a:b/b.{t};
+  import c: func();
 }
 package a:b {
   interface b {
     type t = u32;
   }
   world into {
-    import b;
     import a: interface {
     }
-    import c: func();
+    import b;
     use b.{t};
+    import c: func();
   }
   world %from {
-    import b;
     import a: interface {
     }
-    import c: func();
+    import b;
     use b.{t};
+    import c: func();
   }
 }
diff --git a/tests/cli/world-merging.wit.stdout b/tests/cli/world-merging.wit.stdout
index abcfaefc..d18e6f53 100644
--- a/tests/cli/world-merging.wit.stdout
+++ b/tests/cli/world-merging.wit.stdout
@@ -2,8 +2,8 @@ package root:root;
 
 world root {
   import a:b/x;
-  import a: func() -> t;
   use a:b/x.{t};
+  import a: func() -> t;
 
   export y: func();
   export a:b/x;
@@ -16,8 +16,8 @@ package a:b {
   }
   world foo {
     import x;
-    import a: func() -> t;
     use x.{t};
+    import a: func() -> t;
 
     export y: func();
     export x;
diff --git a/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print b/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print
index 7034e8c4..d99f410b 100644
--- a/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print
+++ b/tests/snapshots/cli/component-model-async/task-builtins.wast/19.print
@@ -1,6 +1,6 @@
 (component
   (core module $m (;0;)
-    (type (;0;) (func))
+    (type (;0;) (func (result i32)))
     (import "" "yield" (func $yield (;0;) (type 0)))
   )
   (core func $yield (;0;) (canon yield async))
diff --git a/tests/snapshots/cli/component-model/fixed-size-list.wast.json b/tests/snapshots/cli/component-model/fixed-size-list.wast.json
new file mode 100644
index 00000000..2d7c8c44
--- /dev/null
+++ b/tests/snapshots/cli/component-model/fixed-size-list.wast.json
@@ -0,0 +1,45 @@
+{
+  "source_filename": "tests/cli/component-model/fixed-size-list.wast",
+  "commands": [
+    {
+      "type": "module",
+      "line": 3,
+      "filename": "fixed-size-list.0.wasm",
+      "module_type": "binary"
+    },
+    {
+      "type": "module",
+      "line": 15,
+      "filename": "fixed-size-list.1.wasm",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 27,
+      "filename": "fixed-size-list.2.wasm",
+      "module_type": "binary",
+      "text": "Fixed size lists must have more than zero elements (at offset 0x54)"
+    },
+    {
+      "type": "assert_malformed",
+      "line": 42,
+      "filename": "fixed-size-list.3.wat",
+      "module_type": "text",
+      "text": "invalid u32 number: constant out of range"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 57,
+      "filename": "fixed-size-list.4.wasm",
+      "module_type": "binary",
+      "text": "type mismatch for import `x`"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 70,
+      "filename": "fixed-size-list.5.wasm",
+      "module_type": "binary",
+      "text": "type mismatch for import `x`"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/snapshots/cli/component-model/fixed-size-list.wast/0.print b/tests/snapshots/cli/component-model/fixed-size-list.wast/0.print
new file mode 100644
index 00000000..79848d67
--- /dev/null
+++ b/tests/snapshots/cli/component-model/fixed-size-list.wast/0.print
@@ -0,0 +1,18 @@
+(component
+  (core module $m (;0;)
+    (type (;0;) (func (result i32)))
+    (memory (;0;) 1)
+    (export "memory" (memory 0))
+    (export "ret-list" (func 0))
+    (func (;0;) (type 0) (result i32)
+      unreachable
+    )
+  )
+  (core instance $i (;0;) (instantiate $m))
+  (type (;0;) (list u32 4))
+  (type (;1;) (func (result 0)))
+  (alias core export $i "ret-list" (core func (;0;)))
+  (alias core export $i "memory" (core memory (;0;)))
+  (func (;0;) (type 1) (canon lift (core func 0) (memory 0)))
+  (export (;1;) "ret-list" (func 0))
+)
diff --git a/tests/snapshots/cli/component-model/fixed-size-list.wast/1.print b/tests/snapshots/cli/component-model/fixed-size-list.wast/1.print
new file mode 100644
index 00000000..ee75456d
--- /dev/null
+++ b/tests/snapshots/cli/component-model/fixed-size-list.wast/1.print
@@ -0,0 +1,15 @@
+(component
+  (core module $m (;0;)
+    (type (;0;) (func (param i32 i32 i32 i32)))
+    (export "param-list" (func 0))
+    (func (;0;) (type 0) (param i32 i32 i32 i32)
+      unreachable
+    )
+  )
+  (core instance $i (;0;) (instantiate $m))
+  (type (;0;) (list u32 4))
+  (type (;1;) (func (param "l" 0)))
+  (alias core export $i "param-list" (core func (;0;)))
+  (func (;0;) (type 1) (canon lift (core func 0)))
+  (export (;1;) "param-list" (func 0))
+)
diff --git a/tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json b/tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json
new file mode 100644
index 00000000..d9123336
--- /dev/null
+++ b/tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json
@@ -0,0 +1,19 @@
+{
+  "source_filename": "tests/cli/missing-features/component-model/fixed-size-list.wast",
+  "commands": [
+    {
+      "type": "assert_invalid",
+      "line": 4,
+      "filename": "fixed-size-list.0.wasm",
+      "module_type": "binary",
+      "text": "Fixed size lists require the component model fixed size list feature (at offset 0x54)"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 19,
+      "filename": "fixed-size-list.1.wasm",
+      "module_type": "binary",
+      "text": "Fixed size lists require the component model fixed size list feature"
+    }
+  ]
+}
\ No newline at end of file