Repository: bytecodealliance/wasm-tools
Pull request #1360 (2024-01-08 22:22:04)

`wasm-smith`: Generate GC types
Doesn't add support for generating GC instructions yet.

Also doesn't add support for non-nullable references yet, as there are various places where we expect a type to be defaultable and/or have a value of the type we can construct immediately and nullability is a good short hand for that. Eventually we should properly support non-nullable references though.

alexcrichton: Before I get too deep into this I figured I'd throw it at the fuzzing and see what happened. This pops out with a number of crashes which the one I glanced at was related to printing so perhaps preexisting. Want to take it for a spin locally though and see if we can turn this on by default in the `validate-valid-module.rs` fuzzer?
fitzgen: Oh interesting, I did fuzz for like half an hour and it didn't come back with anything. Will try again
alexcrichton: Oh you'll need to apply this diff b/c gc is off-by-default:

```diff
diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs
index e22b03b7..bcc794c1 100644
--- a/fuzz/src/lib.rs
+++ b/fuzz/src/lib.rs
@@ -27,6 +27,7 @@ pub fn generate_valid_module(
     config.exceptions_enabled = u.arbitrary()?;
     config.canonicalize_nans = u.arbitrary()?;
     config.tail_call_enabled = u.arbitrary()?;
+    config.gc_enabled = u.arbitrary()?;

     configure(&mut config, u)?;

diff --git a/fuzz/src/mutate.rs b/fuzz/src/mutate.rs
index a735a515..4b201e27 100644
--- a/fuzz/src/mutate.rs
+++ b/fuzz/src/mutate.rs
@@ -13,6 +13,7 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
     let mut preserve_semantics = false;
     let (wasm, config) = crate::generate_valid_module(u, |config, u| {
         config.exceptions_enabled = false;
+        config.gc_enabled = false;
         seed = u.arbitrary()?;
         preserve_semantics = u.arbitrary()?;
         Ok(())
diff --git a/fuzz/src/no_traps.rs b/fuzz/src/no_traps.rs
index ba5d4983..e9a622f0 100644
--- a/fuzz/src/no_traps.rs
+++ b/fuzz/src/no_traps.rs
@@ -14,6 +14,7 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
         config.disallow_traps = true;
         config.threads_enabled = false;
         config.exceptions_enabled = false;
+        config.gc_enabled = false;
         config.max_memory32_pages = config.max_memory32_pages.min(100);
         config.max_memory64_pages = config.max_memory64_pages.min(100);
         Ok(())
diff --git a/fuzz/src/validate_valid_module.rs b/fuzz/src/validate_valid_module.rs
index 7f3cd21f..d8185c4e 100644
--- a/fuzz/src/validate_valid_module.rs
+++ b/fuzz/src/validate_valid_module.rs
@@ -36,6 +36,7 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
         memory64: config.memory64_enabled,
         threads: config.threads_enabled,
         exceptions: config.exceptions_enabled,
+        gc: config.gc_enabled,
         ..wasmparser::WasmFeatures::default()
     });
     if let Err(e) = validator.validate_all(&wasm_bytes) {
```

After that I ran:

```
$ FUZZER=validate_valid_module cargo +nightly fuzz run -s none run
```

and got

<details>

```
   Compiling wasm-smith v0.13.1 (/Users/alex/code/wasm-tools/crates/wasm-smith)
   Compiling wasm-tools-fuzz v0.0.1 (/Users/alex/code/wasm-tools/fuzz)
    Finished release [optimized] target(s) in 13.02s
    Finished release [optimized] target(s) in 0.04s
     Running `target/aarch64-apple-darwin/release/run -artifact_prefix=/Users/alex/code/wasm-tools/fuzz/artifacts/run/ /Users/alex/code/wasm-tools/fuzz/corpus/run`
WARNING: Failed to find function "__sanitizer_acquire_crash_state". Reason dlsym(RTLD_DEFAULT, __sanitizer_acquire_crash_state): symbol not found.
WARNING: Failed to find function "__sanitizer_print_stack_trace". Reason dlsym(RTLD_DEFAULT, __sanitizer_print_stack_trace): symbol not found.
WARNING: Failed to find function "__sanitizer_set_death_callback". Reason dlsym(RTLD_DEFAULT, __sanitizer_set_death_callback): symbol not found.
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2721570090
INFO: Loaded 1 modules   (391772 inline 8-bit counters): 391772 [0x10271bca8, 0x10277b704),
INFO: Loaded 1 PC tables (391772 PCs): 391772 [0x10277b708,0x102d75cc8),
INFO:    29543 files found in /Users/alex/code/wasm-tools/fuzz/corpus/run
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: seed corpus: files: 29543 min: 1b max: 794b total: 8206262b rss: 37Mb
thread '<unnamed>' panicked at fuzz/src/validate_valid_module.rs:73:9:
failed to roundtrip valid module
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
==67547== ERROR: libFuzzer: deadly signal
NOTE: libFuzzer has rudimentary signal handlers.
      Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
MS: 0 ; base unit: 0000000000000000000000000000000000000000
0x1,0x65,0x0,0x15,0xb7,0x4c,0xb7,0x1,0x1,0x1,0x63,0x63,0x63,0x63,0x63,0xb7,0x7,0x7,0x7,0x63,0x63,0x63,0x63,0xc2,0x23,0x63,0x63,0x63,0x63,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x63,0x63,0x63,0x63,0x63,0x63,0x11,0x3f,0x42,0xf,0x0,0x1,0xf7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0xb7,0x5b,0x29,
\001e\000\025\267L\267\001\001\001ccccc\267\007\007\007cccc\302#cccc\000\000\006\000\000\000\000\000\000\000\000\000\000cccccc\021?B\017\000\001\367\267\267\267\267\267\267\267\267[)
artifact_prefix='/Users/alex/code/wasm-tools/fuzz/artifacts/run/'; Test unit written to /Users/alex/code/wasm-tools/fuzz/artifacts/run/crash-f09783ab5d23af0cada5a0101d5be75eff691b2f
Base64: AWUAFbdMtwEBAWNjY2NjtwcHB2NjY2PCI2NjY2MAAAYAAAAAAAAAAAAAY2NjY2NjET9CDwAB97e3t7e3t7e3Wyk=

────────────────────────────────────────────────────────────────────────────────

Failing input:

        fuzz/artifacts/run/crash-f09783ab5d23af0cada5a0101d5be75eff691b2f

Output of `std::fmt::Debug`:

        [1, 101, 0, 21, 183, 76, 183, 1, 1, 1, 99, 99, 99, 99, 99, 183, 7, 7, 7, 99, 99, 99, 99, 194, 35, 99, 99, 99, 99, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 99, 99, 99, 99, 99, 17, 63, 66, 15, 0, 1, 247, 183, 183, 183, 183, 183, 183, 183, 183, 91, 41]

Reproduce with:

        cargo fuzz run --sanitizer=none run fuzz/artifacts/run/crash-f09783ab5d23af0cada5a0101d5be75eff691b2f

Minimize test case with:

        cargo fuzz tmin --sanitizer=none run fuzz/artifacts/run/crash-f09783ab5d23af0cada5a0101d5be75eff691b2f

────────────────────────────────────────────────────────────────────────────────

Error: Fuzz target exited with exit status: 77
```

</details>

pretty quickly

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index bd68f90a..d29094a7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1702,7 +1702,7 @@ checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
 
 [[package]]
 name = "wasm-compose"
-version = "0.4.16"
+version = "0.5.0"
 dependencies = [
  "anyhow",
  "glob",
@@ -1716,9 +1716,9 @@ dependencies = [
  "serde_derive",
  "serde_yaml",
  "smallvec",
- "wasm-encoder 0.38.1",
- "wasmparser 0.118.1",
- "wasmprinter 0.2.75",
+ "wasm-encoder 0.39.0",
+ "wasmparser 0.119.0",
+ "wasmprinter 0.2.76",
  "wat",
  "wit-component",
 ]
@@ -1734,17 +1734,17 @@ dependencies = [
 
 [[package]]
 name = "wasm-encoder"
-version = "0.38.1"
+version = "0.39.0"
 dependencies = [
  "anyhow",
  "leb128",
  "tempfile",
- "wasmparser 0.118.1",
+ "wasmparser 0.119.0",
 ]
 
 [[package]]
 name = "wasm-metadata"
-version = "0.10.14"
+version = "0.10.15"
 dependencies = [
  "anyhow",
  "clap 4.4.8",
@@ -1753,14 +1753,14 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "spdx",
- "wasm-encoder 0.38.1",
- "wasmparser 0.118.1",
+ "wasm-encoder 0.39.0",
+ "wasmparser 0.119.0",
  "wat",
 ]
 
 [[package]]
 name = "wasm-mutate"
-version = "0.2.43"
+version = "0.2.44"
 dependencies = [
  "anyhow",
  "clap 4.4.8",
@@ -1769,9 +1769,9 @@ dependencies = [
  "log",
  "rand",
  "thiserror",
- "wasm-encoder 0.38.1",
- "wasmparser 0.118.1",
- "wasmprinter 0.2.75",
+ "wasm-encoder 0.39.0",
+ "wasmparser 0.119.0",
+ "wasmprinter 0.2.76",
  "wat",
 ]
 
@@ -1788,14 +1788,14 @@ dependencies = [
  "num_cpus",
  "rand",
  "wasm-mutate",
- "wasmparser 0.118.1",
- "wasmprinter 0.2.75",
+ "wasmparser 0.119.0",
+ "wasmprinter 0.2.76",
  "wasmtime",
 ]
 
 [[package]]
 name = "wasm-shrink"
-version = "0.1.44"
+version = "0.1.45"
 dependencies = [
  "anyhow",
  "blake3",
@@ -1804,14 +1804,14 @@ dependencies = [
  "log",
  "rand",
  "wasm-mutate",
- "wasmparser 0.118.1",
- "wasmprinter 0.2.75",
+ "wasmparser 0.119.0",
+ "wasmprinter 0.2.76",
  "wat",
 ]
 
 [[package]]
 name = "wasm-smith"
-version = "0.13.1"
+version = "0.14.0"
 dependencies = [
  "anyhow",
  "arbitrary",
@@ -1824,15 +1824,15 @@ dependencies = [
  "rand",
  "serde",
  "serde_derive",
- "wasm-encoder 0.38.1",
- "wasmparser 0.118.1",
- "wasmprinter 0.2.75",
+ "wasm-encoder 0.39.0",
+ "wasmparser 0.119.0",
+ "wasmprinter 0.2.76",
  "wat",
 ]
 
 [[package]]
 name = "wasm-tools"
-version = "1.0.54"
+version = "1.0.55"
 dependencies = [
  "addr2line 0.21.0",
  "anyhow",
@@ -1854,17 +1854,17 @@ dependencies = [
  "tempfile",
  "termcolor",
  "wasm-compose",
- "wasm-encoder 0.38.1",
+ "wasm-encoder 0.39.0",
  "wasm-metadata",
  "wasm-mutate",
  "wasm-shrink",
  "wasm-smith",
- "wasmparser 0.118.1",
- "wasmprinter 0.2.75",
+ "wasmparser 0.119.0",
+ "wasmprinter 0.2.76",
  "wast",
  "wat",
  "wit-component",
- "wit-parser 0.13.0",
+ "wit-parser 0.13.1",
  "wit-smith",
 ]
 
@@ -1876,8 +1876,8 @@ dependencies = [
  "wasm-mutate",
  "wasm-shrink",
  "wasm-smith",
- "wasmparser 0.118.1",
- "wasmprinter 0.2.75",
+ "wasmparser 0.119.0",
+ "wasmprinter 0.2.76",
  "wast",
  "wat",
 ]
@@ -1892,16 +1892,16 @@ dependencies = [
  "libfuzzer-sys",
  "log",
  "tempfile",
- "wasm-encoder 0.38.1",
+ "wasm-encoder 0.39.0",
  "wasm-mutate",
  "wasm-smith",
- "wasmparser 0.118.1",
- "wasmprinter 0.2.75",
+ "wasmparser 0.119.0",
+ "wasmprinter 0.2.76",
  "wasmtime",
  "wast",
  "wat",
  "wit-component",
- "wit-parser 0.13.0",
+ "wit-parser 0.13.1",
  "wit-smith",
 ]
 
@@ -1927,7 +1927,7 @@ dependencies = [
 
 [[package]]
 name = "wasmparser"
-version = "0.118.1"
+version = "0.119.0"
 dependencies = [
  "anyhow",
  "bitflags 2.4.1",
@@ -1938,7 +1938,7 @@ dependencies = [
  "once_cell",
  "rayon",
  "semver",
- "wasm-encoder 0.38.1",
+ "wasm-encoder 0.39.0",
  "wast",
  "wat",
 ]
@@ -1955,13 +1955,13 @@ dependencies = [
 
 [[package]]
 name = "wasmprinter"
-version = "0.2.75"
+version = "0.2.76"
 dependencies = [
  "anyhow",
  "diff",
  "rayon",
  "tempfile",
- "wasmparser 0.118.1",
+ "wasmparser 0.119.0",
  "wast",
  "wat",
 ]
@@ -2219,21 +2219,21 @@ dependencies = [
 
 [[package]]
 name = "wast"
-version = "69.0.1"
+version = "70.0.0"
 dependencies = [
  "anyhow",
  "leb128",
  "memchr",
  "rayon",
  "unicode-width",
- "wasm-encoder 0.38.1",
- "wasmparser 0.118.1",
+ "wasm-encoder 0.39.0",
+ "wasmparser 0.119.0",
  "wat",
 ]
 
 [[package]]
 name = "wat"
-version = "1.0.82"
+version = "1.0.83"
 dependencies = [
  "wast",
 ]
@@ -2363,7 +2363,7 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "wit-component"
-version = "0.19.0"
+version = "0.19.1"
 dependencies = [
  "anyhow",
  "bitflags 2.4.1",
@@ -2375,14 +2375,14 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "wasm-encoder 0.38.1",
+ "wasm-encoder 0.39.0",
  "wasm-metadata",
- "wasmparser 0.118.1",
- "wasmprinter 0.2.75",
+ "wasmparser 0.119.0",
+ "wasmprinter 0.2.76",
  "wasmtime",
  "wast",
  "wat",
- "wit-parser 0.13.0",
+ "wit-parser 0.13.1",
 ]
 
 [[package]]
@@ -2403,7 +2403,7 @@ dependencies = [
 
 [[package]]
 name = "wit-parser"
-version = "0.13.0"
+version = "0.13.1"
 dependencies = [
  "anyhow",
  "env_logger",
@@ -2427,13 +2427,13 @@ dependencies = [
  "env_logger",
  "libfuzzer-sys",
  "log",
- "wasmprinter 0.2.75",
- "wit-parser 0.13.0",
+ "wasmprinter 0.2.76",
+ "wit-parser 0.13.1",
 ]
 
 [[package]]
 name = "wit-smith"
-version = "0.1.24"
+version = "0.1.25"
 dependencies = [
  "arbitrary",
  "clap 4.4.8",
@@ -2441,7 +2441,7 @@ dependencies = [
  "log",
  "semver",
  "wit-component",
- "wit-parser 0.13.0",
+ "wit-parser 0.13.1",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index dad0bd26..c2f3105f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasm-tools"
-version = "1.0.54"
+version = "1.0.55"
 authors = ["The Wasmtime Project Developers"]
 edition.workspace = true
 description = "CLI tools for interoperating with WebAssembly files"
@@ -46,19 +46,19 @@ pretty_assertions = "1.3.0"
 semver = "1.0.0"
 smallvec = "1.11.1"
 
-wasm-compose = { version = "0.4.16", path = "crates/wasm-compose" }
-wasm-encoder = { version = "0.38.1", path = "crates/wasm-encoder" }
-wasm-metadata = { version = "0.10.14", path = "crates/wasm-metadata" }
-wasm-mutate = { version = "0.2.43", path = "crates/wasm-mutate" }
-wasm-shrink = { version = "0.1.44", path = "crates/wasm-shrink" }
-wasm-smith = { version = "0.13.1", path = "crates/wasm-smith" }
-wasmparser = { version = "0.118.1", path = "crates/wasmparser" }
-wasmprinter = { version = "0.2.75", path = "crates/wasmprinter" }
-wast = { version = "69.0.1", path = "crates/wast" }
-wat = { version = "1.0.82", path = "crates/wat" }
-wit-component = { version = "0.19.0", path = "crates/wit-component" }
-wit-parser = { version = "0.13.0", path = "crates/wit-parser" }
-wit-smith = { version = "0.1.24", path = "crates/wit-smith" }
+wasm-compose = { version = "0.5.0", path = "crates/wasm-compose" }
+wasm-encoder = { version = "0.39.0", path = "crates/wasm-encoder" }
+wasm-metadata = { version = "0.10.15", path = "crates/wasm-metadata" }
+wasm-mutate = { version = "0.2.44", path = "crates/wasm-mutate" }
+wasm-shrink = { version = "0.1.45", path = "crates/wasm-shrink" }
+wasm-smith = { version = "0.14.0", path = "crates/wasm-smith" }
+wasmparser = { version = "0.119.0", path = "crates/wasmparser" }
+wasmprinter = { version = "0.2.76", path = "crates/wasmprinter" }
+wast = { version = "70.0.0", path = "crates/wast" }
+wat = { version = "1.0.83", path = "crates/wat" }
+wit-component = { version = "0.19.1", path = "crates/wit-component" }
+wit-parser = { version = "0.13.1", path = "crates/wit-parser" }
+wit-smith = { version = "0.1.25", path = "crates/wit-smith" }
 
 [dependencies]
 anyhow = { workspace = true }
diff --git a/crates/wasm-compose/Cargo.toml b/crates/wasm-compose/Cargo.toml
index a9e0cea2..82679094 100644
--- a/crates/wasm-compose/Cargo.toml
+++ b/crates/wasm-compose/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasm-compose"
-version = "0.4.16"
+version = "0.5.0"
 edition.workspace = true
 authors = ["Peter Huene <peter@huene.dev>"]
 license = "Apache-2.0 WITH LLVM-exception"
diff --git a/crates/wasm-encoder/Cargo.toml b/crates/wasm-encoder/Cargo.toml
index 9f81d75f..b1ce7b1c 100644
--- a/crates/wasm-encoder/Cargo.toml
+++ b/crates/wasm-encoder/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasm-encoder"
-version = "0.38.1"
+version = "0.39.0"
 authors = ["Nick Fitzgerald <fitzgen@gmail.com>"]
 edition.workspace = true
 license = "Apache-2.0 WITH LLVM-exception"
diff --git a/crates/wasm-metadata/Cargo.toml b/crates/wasm-metadata/Cargo.toml
index 43bbb573..6e72f803 100644
--- a/crates/wasm-metadata/Cargo.toml
+++ b/crates/wasm-metadata/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasm-metadata"
-version = "0.10.14"
+version = "0.10.15"
 edition.workspace = true
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-metadata"
diff --git a/crates/wasm-mutate/Cargo.toml b/crates/wasm-mutate/Cargo.toml
index 816483ac..e53ad1a7 100644
--- a/crates/wasm-mutate/Cargo.toml
+++ b/crates/wasm-mutate/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasm-mutate"
-version = "0.2.43"
+version = "0.2.44"
 edition.workspace = true
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-mutate"
diff --git a/crates/wasm-shrink/Cargo.toml b/crates/wasm-shrink/Cargo.toml
index 17fd9754..d08378a5 100644
--- a/crates/wasm-shrink/Cargo.toml
+++ b/crates/wasm-shrink/Cargo.toml
@@ -8,7 +8,7 @@ license = "Apache-2.0 WITH LLVM-exception"
 readme = "./README.md"
 repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-shrink"
 name = "wasm-shrink"
-version = "0.1.44"
+version = "0.1.45"
 
 [dependencies]
 anyhow = { workspace = true }
diff --git a/crates/wasm-smith/Cargo.toml b/crates/wasm-smith/Cargo.toml
index 89e739d6..0c6092ca 100644
--- a/crates/wasm-smith/Cargo.toml
+++ b/crates/wasm-smith/Cargo.toml
@@ -8,7 +8,7 @@ license = "Apache-2.0 WITH LLVM-exception"
 name = "wasm-smith"
 readme = "./README.md"
 repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-smith"
-version = "0.13.1"
+version = "0.14.0"
 exclude = ["/benches/corpus"]
 
 [[bench]]
diff --git a/crates/wasm-smith/src/component.rs b/crates/wasm-smith/src/component.rs
index 5a077554..e18373b4 100644
--- a/crates/wasm-smith/src/component.rs
+++ b/crates/wasm-smith/src/component.rs
@@ -542,12 +542,14 @@ impl ComponentBuilder {
         let ty = match u.int_in_range::<u8>(0..=1)? {
             0 => CoreType::Func(crate::core::arbitrary_func_type(
                 u,
+                &self.config,
                 &self.core_valtypes,
                 if self.config.multi_value_enabled {
                     None
                 } else {
                     Some(1)
                 },
+                0,
             )?),
             1 => CoreType::Module(self.arbitrary_module_type(u, type_fuel)?),
             _ => unreachable!(),
@@ -711,7 +713,7 @@ impl ComponentBuilder {
             });
             let ty_idx = u32::try_from(types.len()).unwrap();
             types.push(realloc_ty.clone());
-            defs.push(ModuleTypeDef::TypeDef(crate::core::Type::Func(
+            defs.push(ModuleTypeDef::TypeDef(crate::core::CompositeType::Func(
                 realloc_ty.clone(),
             )));
             defs.push(ModuleTypeDef::Export(
@@ -734,7 +736,7 @@ impl ComponentBuilder {
             });
             let ty_idx = u32::try_from(types.len()).unwrap();
             types.push(free_ty.clone());
-            defs.push(ModuleTypeDef::TypeDef(crate::core::Type::Func(
+            defs.push(ModuleTypeDef::TypeDef(crate::core::CompositeType::Func(
                 free_ty.clone(),
             )));
             defs.push(ModuleTypeDef::Export(
@@ -819,15 +821,17 @@ impl ComponentBuilder {
                 2 => {
                     let ty = crate::core::arbitrary_func_type(
                         u,
+                        &self.config,
                         &self.core_valtypes,
                         if self.config.multi_value_enabled {
                             None
                         } else {
                             Some(1)
                         },
+                        0,
                     )?;
                     types.push(ty.clone());
-                    defs.push(ModuleTypeDef::TypeDef(crate::core::Type::Func(ty)));
+                    defs.push(ModuleTypeDef::TypeDef(crate::core::CompositeType::Func(ty)));
                 }
 
                 // Alias
@@ -1900,7 +1904,7 @@ struct ModuleType {
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 enum ModuleTypeDef {
-    TypeDef(crate::core::Type),
+    TypeDef(crate::core::CompositeType),
     Import(crate::core::Import),
     OuterAlias {
         count: u32,
diff --git a/crates/wasm-smith/src/component/encode.rs b/crates/wasm-smith/src/component/encode.rs
index bcb6efd2..7963ecfa 100644
--- a/crates/wasm-smith/src/component/encode.rs
+++ b/crates/wasm-smith/src/component/encode.rs
@@ -124,12 +124,15 @@ impl CoreType {
                 let mut enc_mod_ty = wasm_encoder::ModuleType::new();
                 for def in &mod_ty.defs {
                     match def {
-                        ModuleTypeDef::TypeDef(crate::core::Type::Func(func_ty)) => {
+                        ModuleTypeDef::TypeDef(crate::core::CompositeType::Func(func_ty)) => {
                             enc_mod_ty.ty().function(
                                 func_ty.params.iter().copied(),
                                 func_ty.results.iter().copied(),
                             );
                         }
+                        ModuleTypeDef::TypeDef(_) => {
+                            unimplemented!("non-func types in a component's module type")
+                        }
                         ModuleTypeDef::OuterAlias { count, i, kind } => match kind {
                             CoreOuterAliasKind::Type(_) => {
                                 enc_mod_ty.alias_outer_core_type(*count, *i);
diff --git a/crates/wasm-smith/src/config.rs b/crates/wasm-smith/src/config.rs
index 1e2e7e9b..b183530e 100644
--- a/crates/wasm-smith/src/config.rs
+++ b/crates/wasm-smith/src/config.rs
@@ -221,6 +221,12 @@ define_config! {
         /// This overrides [`Config::min_exports`] and [`Config::max_exports`].
         pub export_everything: bool = false,
 
+        /// Determines whether the GC proposal is enabled when generating a Wasm
+        /// module.
+        ///
+        /// Defaults to `false`.
+        pub gc_enabled: bool = false,
+
         /// Returns whether we should generate custom sections or not. Defaults
         /// to false.
         pub generate_custom_sections: bool = false,
@@ -609,6 +615,7 @@ impl<'a> Arbitrary<'a> for Config {
             export_everything: false,
             disallow_traps: false,
             tail_call_enabled: false,
+            gc_enabled: false,
             generate_custom_sections: false,
         })
     }
diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs
index 659d80b0..39255c0f 100644
--- a/crates/wasm-smith/src/core.rs
+++ b/crates/wasm-smith/src/core.rs
@@ -8,12 +8,15 @@ use crate::{arbitrary_loop, limited_string, unique_string, Config};
 use arbitrary::{Arbitrary, Result, Unstructured};
 use code_builder::CodeBuilderAllocations;
 use flagset::{flags, FlagSet};
-use std::collections::HashSet;
+use std::collections::{HashMap, HashSet};
 use std::convert::TryFrom;
 use std::ops::Range;
 use std::rc::Rc;
 use std::str::{self, FromStr};
-use wasm_encoder::{BlockType, ConstExpr, ExportKind, HeapType, RefType, ValType};
+use wasm_encoder::{
+    ArrayType, BlockType, ConstExpr, ExportKind, FieldType, HeapType, RefType, StorageType,
+    StructType, ValType,
+};
 pub(crate) use wasm_encoder::{GlobalType, MemoryType, TableType};
 
 // NB: these constants are used to control the rate at which various events
@@ -47,7 +50,18 @@ pub struct Module {
 
     /// All types locally defined in this module (available in the type index
     /// space).
-    types: Vec<Type>,
+    types: Vec<SubType>,
+
+    /// Non-overlapping ranges within `types` that belong to the same rec
+    /// group. All of `types` is covered by these ranges. When GC is not
+    /// enabled, these are all single-element ranges.
+    rec_groups: Vec<Range<usize>>,
+
+    /// A map from a super type to all of its sub types.
+    super_to_sub_types: HashMap<u32, Vec<u32>>,
+
+    /// Indices within `types` that are not final types.
+    can_subtype: Vec<u32>,
 
     /// Whether we should encode a types section, even if `self.types` is empty.
     should_encode_types: bool,
@@ -61,9 +75,15 @@ pub struct Module {
     /// empty.
     should_encode_imports: bool,
 
+    /// Indices within `types` that are array types.
+    array_types: Vec<u32>,
+
     /// Indices within `types` that are function types.
     func_types: Vec<u32>,
 
+    /// Indices within `types that are struct types.
+    struct_types: Vec<u32>,
+
     /// Number of imported items into this module.
     num_imports: usize,
 
@@ -162,10 +182,15 @@ impl Module {
             duplicate_imports_behavior,
             valtypes: Vec::new(),
             types: Vec::new(),
+            rec_groups: Vec::new(),
+            can_subtype: Vec::new(),
+            super_to_sub_types: HashMap::new(),
             should_encode_types: false,
             imports: Vec::new(),
             should_encode_imports: false,
+            array_types: Vec::new(),
             func_types: Vec::new(),
+            struct_types: Vec::new(),
             num_imports: 0,
             num_defined_tags: 0,
             num_defined_funcs: 0,
@@ -213,8 +238,22 @@ impl<'a> Arbitrary<'a> for MaybeInvalidModule {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub(crate) enum Type {
+pub(crate) struct RecGroup {
+    pub(crate) types: Vec<SubType>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub(crate) struct SubType {
+    pub(crate) is_final: bool,
+    pub(crate) supertype: Option<u32>,
+    pub(crate) composite_type: CompositeType,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub(crate) enum CompositeType {
+    Array(ArrayType),
     Func(Rc<FuncType>),
+    Struct(StructType),
 }
 
 /// A function signature.
@@ -354,40 +393,488 @@ impl Module {
     }
 
     fn arbitrary_types(&mut self, u: &mut Unstructured) -> Result<()> {
-        // NB: It isn't guaranteed that `self.types.is_empty()` because when
-        // available imports are configured, we may add eagerly specigfic types
-        // for the available imports before generating arbitrary types here.
-        let min = self.config.min_types.saturating_sub(self.types.len());
-        let max = self.config.max_types.saturating_sub(self.types.len());
-        arbitrary_loop(u, min, max, |u| {
-            let ty = self.arbitrary_type(u)?;
-            self.record_type(&ty);
-            self.types.push(ty);
-            Ok(true)
-        })?;
+        assert!(self.config.min_types <= self.config.max_types);
+        while self.types.len() < self.config.min_types {
+            self.arbitrary_rec_group(u)?;
+        }
+        while self.types.len() < self.config.max_types {
+            let keep_going = u.arbitrary().unwrap_or(false);
+            if !keep_going {
+                break;
+            }
+            self.arbitrary_rec_group(u)?;
+        }
         Ok(())
     }
 
-    fn record_type(&mut self, ty: &Type) {
-        let list = match &ty {
-            Type::Func(_) => &mut self.func_types,
+    fn add_type(&mut self, ty: SubType) -> u32 {
+        let index = u32::try_from(self.types.len()).unwrap();
+
+        if let Some(supertype) = ty.supertype {
+            self.super_to_sub_types
+                .entry(supertype)
+                .or_default()
+                .push(index);
+        }
+
+        let list = match &ty.composite_type {
+            CompositeType::Array(_) => &mut self.array_types,
+            CompositeType::Func(_) => &mut self.func_types,
+            CompositeType::Struct(_) => &mut self.struct_types,
         };
-        list.push(self.types.len() as u32);
+        list.push(index);
+
+        if !ty.is_final {
+            self.can_subtype.push(index);
+        }
+
+        self.types.push(ty);
+        index
     }
 
-    fn arbitrary_type(&mut self, u: &mut Unstructured) -> Result<Type> {
-        Ok(Type::Func(self.arbitrary_func_type(u)?))
+    fn arbitrary_rec_group(&mut self, u: &mut Unstructured) -> Result<()> {
+        let rec_group_start = self.types.len();
+
+        if self.config.gc_enabled {
+            // With small probability, clone an existing rec group.
+            if self.clonable_rec_groups().next().is_some() && u.ratio(1, u8::MAX)? {
+                return self.clone_rec_group(u);
+            }
+
+            // Otherwise, create a new rec group with multiple types inside.
+            let max_rec_group_size = self.config.max_types - self.types.len();
+            let rec_group_size = u.int_in_range(0..=max_rec_group_size)?;
+            let type_ref_limit = u32::try_from(self.types.len() + rec_group_size).unwrap();
+            for _ in 0..rec_group_size {
+                let ty = self.arbitrary_sub_type(u, type_ref_limit)?;
+                self.add_type(ty);
+            }
+        } else {
+            let type_ref_limit = u32::try_from(self.types.len()).unwrap();
+            let ty = self.arbitrary_sub_type(u, type_ref_limit)?;
+            self.add_type(ty);
+        }
+
+        self.rec_groups.push(rec_group_start..self.types.len());
+        Ok(())
+    }
+
+    /// Returns an iterator of rec groups that we could currently clone while
+    /// still staying within the max types limit.
+    fn clonable_rec_groups(&self) -> impl Iterator<Item = Range<usize>> + '_ {
+        self.rec_groups
+            .iter()
+            .filter(|r| r.end - r.start <= self.config.max_types.saturating_sub(self.types.len()))
+            .cloned()
     }
 
-    fn arbitrary_func_type(&mut self, u: &mut Unstructured) -> Result<Rc<FuncType>> {
+    fn clone_rec_group(&mut self, u: &mut Unstructured) -> Result<()> {
+        // NB: this does *not* guarantee that the cloned rec group will
+        // canonicalize the same as the original rec group and be
+        // deduplicated. That would reqiure a second pass over the cloned types
+        // to rewrite references within the original rec group to be references
+        // into the new rec group. That might make sense to do one day, but for
+        // now we don't do it. That also means that we can't mark the new types
+        // as "subtypes" of the old types and vice versa.
+        let candidates: Vec<_> = self.clonable_rec_groups().collect();
+        let group = u.choose(&candidates)?.clone();
+        let new_rec_group_start = self.types.len();
+        for index in group {
+            let orig_ty_index = u32::try_from(index).unwrap();
+            let ty = self.ty(orig_ty_index).clone();
+            self.add_type(ty);
+        }
+        self.rec_groups.push(new_rec_group_start..self.types.len());
+        Ok(())
+    }
+
+    fn arbitrary_sub_type(
+        &mut self,
+        u: &mut Unstructured,
+        // NB: Types can be referenced up to (but not including)
+        // `type_ref_limit`. It is an exclusive bound to avoid an option: to
+        // disallow any reference to a concrete type (e.g. `(ref $type)`) you
+        // can simply pass `0` here.
+        type_ref_limit: u32,
+    ) -> Result<SubType> {
+        if !self.config.gc_enabled {
+            debug_assert_eq!(type_ref_limit, u32::try_from(self.types.len()).unwrap());
+            return Ok(SubType {
+                is_final: true,
+                supertype: None,
+                composite_type: CompositeType::Func(self.arbitrary_func_type(u, type_ref_limit)?),
+            });
+        }
+
+        if !self.can_subtype.is_empty() && u.ratio(1, 32_u8)? {
+            self.arbitrary_sub_type_of_super_type(u, type_ref_limit)
+        } else {
+            Ok(SubType {
+                is_final: u.arbitrary()?,
+                supertype: None,
+                composite_type: self.arbitrary_composite_type(u, type_ref_limit)?,
+            })
+        }
+    }
+
+    fn arbitrary_sub_type_of_super_type(
+        &mut self,
+        u: &mut Unstructured,
+        type_ref_limit: u32,
+    ) -> Result<SubType> {
+        let supertype = *u.choose(&self.can_subtype)?;
+        let mut composite_type = self.types[usize::try_from(supertype).unwrap()]
+            .composite_type
+            .clone();
+        match &mut composite_type {
+            CompositeType::Array(a) => {
+                a.0 = self.arbitrary_matching_field_type(u, a.0)?;
+            }
+            CompositeType::Func(f) => {
+                *f = self.arbitrary_matching_func_type(u, f)?;
+            }
+            CompositeType::Struct(s) => {
+                *s = self.arbitrary_matching_struct_type(u, s, type_ref_limit)?;
+            }
+        }
+        Ok(SubType {
+            is_final: u.arbitrary()?,
+            supertype: Some(supertype),
+            composite_type,
+        })
+    }
+
+    fn arbitrary_matching_struct_type(
+        &mut self,
+        u: &mut Unstructured,
+        ty: &StructType,
+        type_ref_limit: u32,
+    ) -> Result<StructType> {
+        let len_extra_fields = u.int_in_range(0..=5)?;
+        let mut fields = Vec::with_capacity(ty.fields.len() + len_extra_fields);
+        for field in ty.fields.iter() {
+            fields.push(self.arbitrary_matching_field_type(u, *field)?);
+        }
+        for _ in 0..len_extra_fields {
+            fields.push(self.arbitrary_field_type(u, type_ref_limit)?);
+        }
+        Ok(StructType {
+            fields: fields.into_boxed_slice(),
+        })
+    }
+
+    fn arbitrary_matching_field_type(
+        &mut self,
+        u: &mut Unstructured,
+        ty: FieldType,
+    ) -> Result<FieldType> {
+        Ok(FieldType {
+            element_type: self.arbitrary_matching_storage_type(u, ty.element_type)?,
+            mutable: if ty.mutable { u.arbitrary()? } else { false },
+        })
+    }
+
+    fn arbitrary_matching_storage_type(
+        &mut self,
+        u: &mut Unstructured,
+        ty: StorageType,
+    ) -> Result<StorageType> {
+        match ty {
+            StorageType::I8 => Ok(StorageType::I8),
+            StorageType::I16 => Ok(StorageType::I16),
+            StorageType::Val(ty) => Ok(StorageType::Val(self.arbitrary_matching_val_type(u, ty)?)),
+        }
+    }
+
+    fn arbitrary_matching_val_type(
+        &mut self,
+        u: &mut Unstructured,
+        ty: ValType,
+    ) -> Result<ValType> {
+        match ty {
+            ValType::I32 => Ok(ValType::I32),
+            ValType::I64 => Ok(ValType::I64),
+            ValType::F32 => Ok(ValType::F32),
+            ValType::F64 => Ok(ValType::F64),
+            ValType::V128 => Ok(ValType::V128),
+            ValType::Ref(ty) => Ok(ValType::Ref(self.arbitrary_matching_ref_type(u, ty)?)),
+        }
+    }
+
+    fn arbitrary_matching_ref_type(
+        &mut self,
+        u: &mut Unstructured,
+        ty: RefType,
+    ) -> Result<RefType> {
+        Ok(RefType {
+            // TODO: For now, only create allow nullable reference
+            // types. Eventually we should support non-nullable reference types,
+            // but this means that we will also need to recognize when it is
+            // impossible to create an instance of the reference (eg `(ref
+            // nofunc)` has no instances, and self-referential types that
+            // contain a non-null self-reference are also impossible to create).
+            nullable: true,
+            heap_type: self.arbitrary_matching_heap_type(u, ty.heap_type)?,
+        })
+    }
+
+    fn arbitrary_matching_heap_type(
+        &mut self,
+        u: &mut Unstructured,
+        ty: HeapType,
+    ) -> Result<HeapType> {
+        use HeapType as HT;
+        let mut choices = vec![ty];
+        match ty {
+            HT::Any => {
+                choices.extend([HT::Eq, HT::Struct, HT::Array, HT::I31, HT::None]);
+                choices.extend(self.array_types.iter().copied().map(HT::Concrete));
+                choices.extend(self.struct_types.iter().copied().map(HT::Concrete));
+            }
+            HT::Eq => {
+                choices.extend([HT::Struct, HT::Array, HT::I31, HT::None]);
+                choices.extend(self.array_types.iter().copied().map(HT::Concrete));
+                choices.extend(self.struct_types.iter().copied().map(HT::Concrete));
+            }
+            HT::Struct => {
+                choices.extend([HT::Struct, HT::None]);
+                choices.extend(self.struct_types.iter().copied().map(HT::Concrete));
+            }
+            HT::Array => {
+                choices.extend([HT::Array, HT::None]);
+                choices.extend(self.array_types.iter().copied().map(HT::Concrete));
+            }
+            HT::I31 => {
+                choices.push(HT::None);
+            }
+            HT::Concrete(idx) => {
+                if let Some(subs) = self.super_to_sub_types.get(&idx) {
+                    choices.extend(subs.iter().copied().map(HT::Concrete));
+                }
+                match self
+                    .types
+                    .get(usize::try_from(idx).unwrap())
+                    .map(|ty| &ty.composite_type)
+                {
+                    Some(CompositeType::Array(_)) | Some(CompositeType::Struct(_)) => {
+                        choices.push(HT::None)
+                    }
+                    Some(CompositeType::Func(_)) => choices.push(HT::NoFunc),
+                    None => {
+                        // The referenced type might be part of this same rec
+                        // group we are currently generating, but not generated
+                        // yet. In this case, leave `choices` as it is, and we
+                        // will just end up choosing the original type again
+                        // down below, which is fine.
+                    }
+                }
+            }
+            HT::Func => {
+                choices.extend(self.func_types.iter().copied().map(HT::Concrete));
+                choices.push(HT::NoFunc);
+            }
+            HT::Extern => {
+                choices.push(HT::NoExtern);
+            }
+            HT::Exn | HT::None | HT::NoExtern | HT::NoFunc => {}
+        }
+        Ok(*u.choose(&choices)?)
+    }
+
+    fn arbitrary_matching_func_type(
+        &mut self,
+        u: &mut Unstructured,
+        ty: &FuncType,
+    ) -> Result<Rc<FuncType>> {
+        // Note: parameters are contravariant, results are covariant. See
+        // https://github.com/bytecodealliance/wasm-tools/blob/0616ef196a183cf137ee06b4a5993b7d590088bf/crates/wasmparser/src/readers/core/types/matches.rs#L137-L174
+        // for details.
+        let mut params = Vec::with_capacity(ty.params.len());
+        for param in &ty.params {
+            params.push(self.arbitrary_super_type_of_val_type(u, *param)?);
+        }
+        let mut results = Vec::with_capacity(ty.results.len());
+        for result in &ty.results {
+            results.push(self.arbitrary_matching_val_type(u, *result)?);
+        }
+        Ok(Rc::new(FuncType { params, results }))
+    }
+
+    fn arbitrary_super_type_of_val_type(
+        &mut self,
+        u: &mut Unstructured,
+        ty: ValType,
+    ) -> Result<ValType> {
+        match ty {
+            ValType::I32 => Ok(ValType::I32),
+            ValType::I64 => Ok(ValType::I64),
+            ValType::F32 => Ok(ValType::F32),
+            ValType::F64 => Ok(ValType::F64),
+            ValType::V128 => Ok(ValType::V128),
+            ValType::Ref(ty) => Ok(ValType::Ref(self.arbitrary_super_type_of_ref_type(u, ty)?)),
+        }
+    }
+
+    fn arbitrary_super_type_of_ref_type(
+        &mut self,
+        u: &mut Unstructured,
+        ty: RefType,
+    ) -> Result<RefType> {
+        Ok(RefType {
+            // TODO: For now, only create allow nullable reference
+            // types. Eventually we should support non-nullable reference types,
+            // but this means that we will also need to recognize when it is
+            // impossible to create an instance of the reference (eg `(ref
+            // nofunc)` has no instances, and self-referential types that
+            // contain a non-null self-reference are also impossible to create).
+            nullable: true,
+            heap_type: self.arbitrary_super_type_of_heap_type(u, ty.heap_type)?,
+        })
+    }
+
+    fn arbitrary_super_type_of_heap_type(
+        &mut self,
+        u: &mut Unstructured,
+        ty: HeapType,
+    ) -> Result<HeapType> {
+        use HeapType as HT;
+        let mut choices = vec![ty];
+        match ty {
+            HT::None => {
+                choices.extend([HT::Any, HT::Eq, HT::Struct, HT::Array, HT::I31]);
+                choices.extend(self.array_types.iter().copied().map(HT::Concrete));
+                choices.extend(self.struct_types.iter().copied().map(HT::Concrete));
+            }
+            HT::NoExtern => {
+                choices.push(HT::Extern);
+            }
+            HT::NoFunc => {
+                choices.extend(self.func_types.iter().copied().map(HT::Concrete));
+                choices.push(HT::Func);
+            }
+            HT::Concrete(mut idx) => {
+                match &self
+                    .types
+                    .get(usize::try_from(idx).unwrap())
+                    .map(|ty| &ty.composite_type)
+                {
+                    Some(CompositeType::Array(_)) => {
+                        choices.extend([HT::Any, HT::Eq, HT::Array]);
+                    }
+                    Some(CompositeType::Func(_)) => {
+                        choices.push(HT::Func);
+                    }
+                    Some(CompositeType::Struct(_)) => {
+                        choices.extend([HT::Any, HT::Eq, HT::Struct]);
+                    }
+                    None => {
+                        // Same as in `arbitrary_matching_heap_type`: this was a
+                        // forward reference to a concrete type that is part of
+                        // this same rec group we are generating right now, and
+                        // therefore we haven't generated that type yet. Just
+                        // leave `choices` as it is and we will choose the
+                        // original type again down below.
+                    }
+                }
+                while let Some(supertype) = self
+                    .types
+                    .get(usize::try_from(idx).unwrap())
+                    .and_then(|ty| ty.supertype)
+                {
+                    choices.push(HT::Concrete(supertype));
+                    idx = supertype;
+                }
+            }
+            HT::Struct | HT::Array | HT::I31 => {
+                choices.extend([HT::Any, HT::Eq]);
+            }
+            HT::Eq => {
+                choices.push(HT::Any);
+            }
+            HT::Exn | HT::Any | HT::Func | HT::Extern => {}
+        }
+        Ok(*u.choose(&choices)?)
+    }
+
+    fn arbitrary_composite_type(
+        &mut self,
+        u: &mut Unstructured,
+        type_ref_limit: u32,
+    ) -> Result<CompositeType> {
+        if !self.config.gc_enabled {
+            return Ok(CompositeType::Func(
+                self.arbitrary_func_type(u, type_ref_limit)?,
+            ));
+        }
+
+        match u.int_in_range(0..=2)? {
+            0 => Ok(CompositeType::Array(ArrayType(
+                self.arbitrary_field_type(u, type_ref_limit)?,
+            ))),
+            1 => Ok(CompositeType::Func(
+                self.arbitrary_func_type(u, type_ref_limit)?,
+            )),
+            2 => Ok(CompositeType::Struct(
+                self.arbitrary_struct_type(u, type_ref_limit)?,
+            )),
+            _ => unreachable!(),
+        }
+    }
+
+    fn arbitrary_struct_type(
+        &mut self,
+        u: &mut Unstructured,
+        type_ref_limit: u32,
+    ) -> Result<StructType> {
+        let len = u.int_in_range(0..=20)?;
+        let mut fields = Vec::with_capacity(len);
+        for _ in 0..len {
+            fields.push(self.arbitrary_field_type(u, type_ref_limit)?);
+        }
+        Ok(StructType {
+            fields: fields.into_boxed_slice(),
+        })
+    }
+
+    fn arbitrary_field_type(
+        &mut self,
+        u: &mut Unstructured,
+        type_ref_limit: u32,
+    ) -> Result<FieldType> {
+        Ok(FieldType {
+            element_type: self.arbitrary_storage_type(u, type_ref_limit)?,
+            mutable: u.arbitrary()?,
+        })
+    }
+
+    fn arbitrary_storage_type(
+        &mut self,
+        u: &mut Unstructured,
+        type_ref_limit: u32,
+    ) -> Result<StorageType> {
+        match u.int_in_range(0..=2)? {
+            0 => Ok(StorageType::I8),
+            1 => Ok(StorageType::I16),
+            2 => Ok(StorageType::Val(self.arbitrary_valtype(u, type_ref_limit)?)),
+            _ => unreachable!(),
+        }
+    }
+
+    fn arbitrary_func_type(
+        &mut self,
+        u: &mut Unstructured,
+        type_ref_limit: u32,
+    ) -> Result<Rc<FuncType>> {
         arbitrary_func_type(
             u,
+            &self.config,
             &self.valtypes,
             if !self.config.multi_value_enabled {
                 Some(1)
             } else {
                 None
             },
+            type_ref_limit,
         )
     }
 
@@ -510,8 +997,9 @@ impl Module {
 
     /// Generate some arbitrary imports from the list of available imports.
     ///
-    /// Returns `true` if there was a list of available imports configured. Otherwise `false` and
-    /// the caller should generate arbitrary imports.
+    /// Returns `true` if there was a list of available imports
+    /// configured. Otherwise `false` and the caller should generate arbitrary
+    /// imports.
     fn arbitrary_imports_from_available(&mut self, u: &mut Unstructured) -> Result<bool> {
         let example_module = if let Some(wasm) = self.config.available_imports.take() {
             wasm
@@ -576,7 +1064,7 @@ impl Module {
         let multi_value_enabled = self.config.multi_value_enabled;
         let mut new_imports = Vec::with_capacity(available_imports.len());
         let first_type_index = self.types.len();
-        let mut new_types = Vec::<Type>::new();
+        let mut new_types = Vec::<SubType>::new();
 
         // Returns the index to the translated type in the to-be type section, and the reference to
         // the type itself.
@@ -603,12 +1091,17 @@ impl Module {
                             .collect(),
                     });
                     index_store.replace(new_index as u32);
-                    new_types.push(Type::Func(Rc::clone(&func_type)));
+                    new_types.push(SubType {
+                        is_final: true,
+                        supertype: None,
+                        composite_type: CompositeType::Func(Rc::clone(&func_type)),
+                    });
                     new_index
                 }
             };
-            match &new_types[serialized_sig_idx - first_type_index] {
-                Type::Func(f) => Some((serialized_sig_idx as u32, Rc::clone(f))),
+            match &new_types[serialized_sig_idx - first_type_index].composite_type {
+                CompositeType::Func(f) => Some((serialized_sig_idx as u32, Rc::clone(f))),
+                _ => unimplemented!(),
             }
         };
 
@@ -695,7 +1188,10 @@ impl Module {
         }
 
         // Finally, add the entities we just generated.
-        self.types.extend(new_types);
+        for ty in new_types {
+            self.rec_groups.push(self.types.len()..self.types.len() + 1);
+            self.add_type(ty);
+        }
         self.imports.extend(new_imports);
 
         Ok(())
@@ -714,7 +1210,7 @@ impl Module {
         }
     }
 
-    fn ty(&self, idx: u32) -> &Type {
+    fn ty(&self, idx: u32) -> &SubType {
         &self.types[idx as usize]
     }
 
@@ -726,8 +1222,9 @@ impl Module {
     }
 
     fn func_type(&self, idx: u32) -> &Rc<FuncType> {
-        match self.ty(idx) {
-            Type::Func(f) => f,
+        match &self.ty(idx).composite_type {
+            CompositeType::Func(f) => f,
+            _ => panic!("types[{idx}] is not a func type"),
         }
     }
 
@@ -756,13 +1253,13 @@ impl Module {
             .filter(move |i| self.func_type(*i).results.is_empty())
     }
 
-    fn arbitrary_valtype(&self, u: &mut Unstructured) -> Result<ValType> {
-        Ok(*u.choose(&self.valtypes)?)
+    fn arbitrary_valtype(&self, u: &mut Unstructured, type_ref_limit: u32) -> Result<ValType> {
+        arbitrary_valtype(u, &self.config, &self.valtypes, type_ref_limit)
     }
 
     fn arbitrary_global_type(&self, u: &mut Unstructured) -> Result<GlobalType> {
         Ok(GlobalType {
-            val_type: self.arbitrary_valtype(u)?,
+            val_type: self.arbitrary_valtype(u, u32::try_from(self.types.len()).unwrap())?,
             mutable: u.arbitrary()?,
         })
     }
@@ -1175,7 +1672,7 @@ impl Module {
     fn arbitrary_locals(&self, u: &mut Unstructured) -> Result<Vec<ValType>> {
         let mut ret = Vec::new();
         arbitrary_loop(u, 0, 100, |u| {
-            ret.push(self.arbitrary_valtype(u)?);
+            ret.push(self.arbitrary_valtype(u, u32::try_from(self.types.len()).unwrap())?);
             Ok(true)
         })?;
         Ok(ret)
@@ -1346,7 +1843,7 @@ pub(crate) fn arbitrary_limits64(
 }
 
 pub(crate) fn configured_valtypes(config: &Config) -> Vec<ValType> {
-    let mut valtypes = Vec::with_capacity(7);
+    let mut valtypes = Vec::with_capacity(25);
     valtypes.push(ValType::I32);
     valtypes.push(ValType::I64);
     valtypes.push(ValType::F32);
@@ -1354,7 +1851,35 @@ pub(crate) fn configured_valtypes(config: &Config) -> Vec<ValType> {
     if config.simd_enabled {
         valtypes.push(ValType::V128);
     }
-    if config.reference_types_enabled {
+    if config.gc_enabled {
+        for nullable in [
+            // TODO: For now, only create allow nullable reference
+            // types. Eventually we should support non-nullable reference types,
+            // but this means that we will also need to recognize when it is
+            // impossible to create an instance of the reference (eg `(ref
+            // nofunc)` has no instances, and self-referential types that
+            // contain a non-null self-reference are also impossible to create).
+            true,
+        ] {
+            for heap_type in [
+                HeapType::Any,
+                HeapType::Eq,
+                HeapType::I31,
+                HeapType::Array,
+                HeapType::Struct,
+                HeapType::None,
+                HeapType::Func,
+                HeapType::NoFunc,
+                HeapType::Extern,
+                HeapType::NoExtern,
+            ] {
+                valtypes.push(ValType::Ref(RefType {
+                    nullable,
+                    heap_type,
+                }));
+            }
+        }
+    } else if config.reference_types_enabled {
         valtypes.push(ValType::EXTERNREF);
         valtypes.push(ValType::FUNCREF);
     }
@@ -1363,24 +1888,44 @@ pub(crate) fn configured_valtypes(config: &Config) -> Vec<ValType> {
 
 pub(crate) fn arbitrary_func_type(
     u: &mut Unstructured,
+    config: &Config,
     valtypes: &[ValType],
     max_results: Option<usize>,
+    type_ref_limit: u32,
 ) -> Result<Rc<FuncType>> {
     let mut params = vec![];
     let mut results = vec![];
     arbitrary_loop(u, 0, 20, |u| {
-        params.push(arbitrary_valtype(u, valtypes)?);
+        params.push(arbitrary_valtype(u, config, valtypes, type_ref_limit)?);
         Ok(true)
     })?;
     arbitrary_loop(u, 0, max_results.unwrap_or(20), |u| {
-        results.push(arbitrary_valtype(u, valtypes)?);
+        results.push(arbitrary_valtype(u, config, valtypes, type_ref_limit)?);
         Ok(true)
     })?;
     Ok(Rc::new(FuncType { params, results }))
 }
 
-fn arbitrary_valtype(u: &mut Unstructured, valtypes: &[ValType]) -> Result<ValType> {
-    Ok(*u.choose(valtypes)?)
+fn arbitrary_valtype(
+    u: &mut Unstructured,
+    config: &Config,
+    valtypes: &[ValType],
+    type_ref_limit: u32,
+) -> Result<ValType> {
+    if config.gc_enabled && type_ref_limit > 0 && u.ratio(1, 20)? {
+        Ok(ValType::Ref(RefType {
+            // TODO: For now, only create allow nullable reference
+            // types. Eventually we should support non-nullable reference types,
+            // but this means that we will also need to recognize when it is
+            // impossible to create an instance of the reference (eg `(ref
+            // nofunc)` has no instances, and self-referential types that
+            // contain a non-null self-reference are also impossible to create).
+            nullable: true,
+            heap_type: HeapType::Concrete(u.int_in_range(0..=type_ref_limit - 1)?),
+        }))
+    } else {
+        Ok(*u.choose(valtypes)?)
+    }
 }
 
 pub(crate) fn arbitrary_table_type(u: &mut Unstructured, config: &Config) -> Result<TableType> {
diff --git a/crates/wasm-smith/src/core/code_builder.rs b/crates/wasm-smith/src/core/code_builder.rs
index 56250386..27a3a73b 100644
--- a/crates/wasm-smith/src/core/code_builder.rs
+++ b/crates/wasm-smith/src/core/code_builder.rs
@@ -859,7 +859,12 @@ impl CodeBuilder<'_> {
     fn arbitrary_block_type(&self, u: &mut Unstructured, module: &Module) -> Result<BlockType> {
         let mut options: Vec<Box<dyn Fn(&mut Unstructured) -> Result<BlockType>>> = vec![
             Box::new(|_| Ok(BlockType::Empty)),
-            Box::new(|u| Ok(BlockType::Result(module.arbitrary_valtype(u)?))),
+            Box::new(|u| {
+                Ok(BlockType::Result(module.arbitrary_valtype(
+                    u,
+                    u32::try_from(module.types.len()).unwrap(),
+                )?))
+            }),
         ];
         if module.config.multi_value_enabled {
             for (i, ty) in module.func_types() {
diff --git a/crates/wasm-smith/src/core/encode.rs b/crates/wasm-smith/src/core/encode.rs
index b359f121..7c781dc7 100644
--- a/crates/wasm-smith/src/core/encode.rs
+++ b/crates/wasm-smith/src/core/encode.rs
@@ -33,13 +33,50 @@ impl Module {
         }
 
         let mut section = wasm_encoder::TypeSection::new();
-        for ty in &self.types {
-            match ty {
-                Type::Func(ty) => {
-                    section.function(ty.params.iter().cloned(), ty.results.iter().cloned());
-                }
+
+        for group in &self.rec_groups {
+            if group.end - group.start == 1 {
+                let ty = &self.types[group.start];
+                section.subtype(&wasm_encoder::SubType {
+                    is_final: ty.is_final,
+                    supertype_idx: ty.supertype,
+                    composite_type: match &ty.composite_type {
+                        CompositeType::Array(a) => wasm_encoder::CompositeType::Array(a.clone()),
+                        CompositeType::Func(f) => {
+                            wasm_encoder::CompositeType::Func(wasm_encoder::FuncType::new(
+                                f.params.iter().cloned(),
+                                f.results.iter().cloned(),
+                            ))
+                        }
+                        CompositeType::Struct(s) => wasm_encoder::CompositeType::Struct(s.clone()),
+                    },
+                });
+            } else {
+                section.rec(
+                    self.types[group.clone()]
+                        .iter()
+                        .map(|ty| wasm_encoder::SubType {
+                            is_final: ty.is_final,
+                            supertype_idx: ty.supertype,
+                            composite_type: match &ty.composite_type {
+                                CompositeType::Array(a) => {
+                                    wasm_encoder::CompositeType::Array(a.clone())
+                                }
+                                CompositeType::Func(f) => {
+                                    wasm_encoder::CompositeType::Func(wasm_encoder::FuncType::new(
+                                        f.params.iter().cloned(),
+                                        f.results.iter().cloned(),
+                                    ))
+                                }
+                                CompositeType::Struct(s) => {
+                                    wasm_encoder::CompositeType::Struct(s.clone())
+                                }
+                            },
+                        }),
+                );
             }
         }
+
         module.section(&section);
     }
 
diff --git a/crates/wasmparser/Cargo.toml b/crates/wasmparser/Cargo.toml
index 00031a80..8b6dfae5 100644
--- a/crates/wasmparser/Cargo.toml
+++ b/crates/wasmparser/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmparser"
-version = "0.118.1"
+version = "0.119.0"
 authors = ["Yury Delendik <ydelendik@mozilla.com>"]
 license = "Apache-2.0 WITH LLVM-exception"
 repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser"
diff --git a/crates/wasmprinter/Cargo.toml b/crates/wasmprinter/Cargo.toml
index e59fb811..f5e5979f 100644
--- a/crates/wasmprinter/Cargo.toml
+++ b/crates/wasmprinter/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wasmprinter"
-version = "0.2.75"
+version = "0.2.76"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 edition.workspace = true
 license = "Apache-2.0 WITH LLVM-exception"
diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs
index 0832471a..fd9dd4d8 100644
--- a/crates/wasmprinter/src/lib.rs
+++ b/crates/wasmprinter/src/lib.rs
@@ -848,7 +848,7 @@ impl Printer {
             self.result.push_str("final ");
         }
         for idx in &ty.supertype_idx {
-            self.print_name(&state.core.type_names, idx.as_module_index().unwrap())?;
+            self.print_idx(&state.core.type_names, idx.as_module_index().unwrap())?;
             self.result.push(' ');
         }
         Ok(0)
diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml
index 642c3854..8b5b1a09 100644
--- a/crates/wast/Cargo.toml
+++ b/crates/wast/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wast"
-version = "69.0.1"
+version = "70.0.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 edition.workspace = true
 license = "Apache-2.0 WITH LLVM-exception"
diff --git a/crates/wat/Cargo.toml b/crates/wat/Cargo.toml
index 851f5f13..9bfcbe9e 100644
--- a/crates/wat/Cargo.toml
+++ b/crates/wat/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "wat"
-version = "1.0.82"
+version = "1.0.83"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 edition.workspace = true
 license = "Apache-2.0 WITH LLVM-exception"
diff --git a/crates/wit-component/Cargo.toml b/crates/wit-component/Cargo.toml
index d4df5ca7..f763306a 100644
--- a/crates/wit-component/Cargo.toml
+++ b/crates/wit-component/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "wit-component"
 authors = ["Peter Huene <peter@huene.dev>"]
-version = "0.19.0"
+version = "0.19.1"
 edition.workspace = true
 license = "Apache-2.0 WITH LLVM-exception"
 readme = "README.md"
diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs
index f6de9d2a..2665fbe2 100644
--- a/crates/wit-component/src/encoding.rs
+++ b/crates/wit-component/src/encoding.rs
@@ -94,7 +94,7 @@ const INDIRECT_TABLE_NAME: &str = "$imports";
 
 pub mod docs;
 mod wit;
-pub use wit::{encode, encode_component, encode_world};
+pub use wit::{encode, encode_world};
 
 mod types;
 use types::{InstanceTypeEncoder, RootTypeEncoder, ValtypeEncoder};
diff --git a/crates/wit-component/src/lib.rs b/crates/wit-component/src/lib.rs
index 92205a32..e16d2523 100644
--- a/crates/wit-component/src/lib.rs
+++ b/crates/wit-component/src/lib.rs
@@ -216,7 +216,7 @@ pub fn embed_component_metadata(
     world: WorldId,
     encoding: StringEncoding,
 ) -> Result<()> {
-    let encoded = metadata::encode(&wit_resolver, world, encoding, None, None)?;
+    let encoded = metadata::encode(&wit_resolver, world, encoding, None)?;
 
     let section = wasm_encoder::CustomSection {
         name: "component-type".into(),
diff --git a/crates/wit-component/src/metadata.rs b/crates/wit-component/src/metadata.rs
index 0bd1d5b2..2ea73155 100644
--- a/crates/wit-component/src/metadata.rs
+++ b/crates/wit-component/src/metadata.rs
@@ -47,7 +47,7 @@ use anyhow::{bail, Context, Result};
 use indexmap::IndexMap;
 use std::borrow::Cow;
 use wasm_encoder::{
-    ComponentBuilder, ComponentExportKind, ComponentType, ComponentTypeRef, CustomSection, Encode,
+    ComponentBuilder, ComponentExportKind, ComponentType, ComponentTypeRef, CustomSection,
 };
 use wasm_metadata::Producers;
 use wasmparser::types::ComponentAnyTypeId;
@@ -170,94 +170,34 @@ pub fn encode(
     world: WorldId,
     string_encoding: StringEncoding,
     extra_producers: Option<&Producers>,
-    use_next_encoding: Option<bool>,
 ) -> Result<Vec<u8>> {
-    enum EncodingFormat {
-        // The encoding of the previous format was:
-        //
-        //  * A version byte, at the time 0x03.
-        //  * A string-encoding byte.
-        //  * A string which is the name of a world.
-        //  * A wasm-encoded WIT package which contains the previous world.
-        //
-        // Note that this branch will be deleted in the near future.
-        Previous,
-
-        // The current format.
-        Next,
+    let ty = crate::encoding::encode_world(resolve, world)?;
+
+    let world = &resolve.worlds[world];
+    let mut outer_ty = ComponentType::new();
+    outer_ty.ty().component(&ty);
+    outer_ty.export(
+        &resolve.id_of_name(world.package.unwrap(), &world.name),
+        ComponentTypeRef::Component(0),
+    );
+
+    let mut builder = ComponentBuilder::default();
+
+    let string_encoding = encode_string_encoding(string_encoding);
+    builder.custom_section(&CustomSection {
+        name: CUSTOM_SECTION_NAME.into(),
+        data: Cow::Borrowed(&[CURRENT_VERSION, string_encoding]),
+    });
+
+    let ty = builder.type_component(&outer_ty);
+    builder.export(&world.name, ComponentExportKind::Type, ty, None);
+
+    let mut producers = crate::base_producers();
+    if let Some(p) = extra_producers {
+        producers.merge(&p);
     }
-
-    let format = match use_next_encoding {
-        Some(true) => EncodingFormat::Next,
-        Some(false) => EncodingFormat::Previous,
-        None => match std::env::var("WIT_COMPONENT_NEW_ENCODE") {
-            Ok(s) if s == "0" => EncodingFormat::Previous,
-            _ => EncodingFormat::Next,
-        },
-    };
-
-    let ret = match format {
-        EncodingFormat::Previous => {
-            let world = &resolve.worlds[world];
-            let pkg = &resolve.packages[world.package.unwrap()];
-            assert!(
-                resolve
-                    .packages
-                    .iter()
-                    .filter(|(_, p)| p.name == pkg.name)
-                    .count()
-                    == 1
-            );
-
-            let mut ret = Vec::new();
-            ret.push(0x03);
-            ret.push(encode_string_encoding(string_encoding));
-            world.name.encode(&mut ret);
-            // This appends a wasm binary encoded Component to the ret:
-            let mut component_builder =
-                crate::encoding::encode_component(None, resolve, world.package.unwrap())?;
-
-            let mut producers = crate::base_producers();
-            if let Some(p) = extra_producers {
-                producers.merge(&p);
-            }
-            component_builder.raw_custom_section(&producers.raw_custom_section());
-
-            ret.extend(component_builder.finish());
-            ret
-        }
-        EncodingFormat::Next => {
-            let ty = crate::encoding::encode_world(resolve, world)?;
-
-            let world = &resolve.worlds[world];
-            let mut outer_ty = ComponentType::new();
-            outer_ty.ty().component(&ty);
-            outer_ty.export(
-                &resolve.id_of_name(world.package.unwrap(), &world.name),
-                ComponentTypeRef::Component(0),
-            );
-
-            let mut builder = ComponentBuilder::default();
-
-            let string_encoding = encode_string_encoding(string_encoding);
-            builder.custom_section(&CustomSection {
-                name: CUSTOM_SECTION_NAME.into(),
-                data: Cow::Borrowed(&[CURRENT_VERSION, string_encoding]),
-            });
-
-            let ty = builder.type_component(&outer_ty);
-            builder.export(&world.name, ComponentExportKind::Type, ty, None);
-
-            let mut producers = crate::base_producers();
-            if let Some(p) = extra_producers {
-                producers.merge(&p);
-            }
-            builder.raw_custom_section(&producers.raw_custom_section());
-            builder.finish()
-        }
-    };
-
-    Ok(ret)
+    builder.raw_custom_section(&producers.raw_custom_section());
+    Ok(builder.finish())
 }
 
 fn decode_custom_section(wasm: &[u8]) -> Result<(Resolve, WorldId, StringEncoding)> {
diff --git a/crates/wit-parser/Cargo.toml b/crates/wit-parser/Cargo.toml
index 6508cd57..a9b3b6f6 100644
--- a/crates/wit-parser/Cargo.toml
+++ b/crates/wit-parser/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "wit-parser"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
-version = "0.13.0"
+version = "0.13.1"
 edition.workspace = true
 license = "Apache-2.0 WITH LLVM-exception"
 readme = "README.md"
diff --git a/crates/wit-smith/Cargo.toml b/crates/wit-smith/Cargo.toml
index 2fa51fd3..e280fbec 100644
--- a/crates/wit-smith/Cargo.toml
+++ b/crates/wit-smith/Cargo.toml
@@ -5,7 +5,7 @@ edition.workspace = true
 license = "Apache-2.0 WITH LLVM-exception"
 name = "wit-smith"
 repository = "https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-smith"
-version = "0.1.24"
+version = "0.1.25"
 
 [dependencies]
 arbitrary = { workspace = true, features = ["derive"] }
diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs
index e22b03b7..885a55dc 100644
--- a/fuzz/src/lib.rs
+++ b/fuzz/src/lib.rs
@@ -28,6 +28,9 @@ pub fn generate_valid_module(
     config.canonicalize_nans = u.arbitrary()?;
     config.tail_call_enabled = u.arbitrary()?;
 
+    config.gc_enabled = u.arbitrary()?;
+    config.reference_types_enabled = config.reference_types_enabled || config.gc_enabled;
+
     configure(&mut config, u)?;
 
     // Use wasm-smith to generate an arbitrary module and convert it to wasm
diff --git a/fuzz/src/mutate.rs b/fuzz/src/mutate.rs
index a735a515..4b201e27 100644
--- a/fuzz/src/mutate.rs
+++ b/fuzz/src/mutate.rs
@@ -13,6 +13,7 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
     let mut preserve_semantics = false;
     let (wasm, config) = crate::generate_valid_module(u, |config, u| {
         config.exceptions_enabled = false;
+        config.gc_enabled = false;
         seed = u.arbitrary()?;
         preserve_semantics = u.arbitrary()?;
         Ok(())
diff --git a/fuzz/src/no_traps.rs b/fuzz/src/no_traps.rs
index ba5d4983..e9a622f0 100644
--- a/fuzz/src/no_traps.rs
+++ b/fuzz/src/no_traps.rs
@@ -14,6 +14,7 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
         config.disallow_traps = true;
         config.threads_enabled = false;
         config.exceptions_enabled = false;
+        config.gc_enabled = false;
         config.max_memory32_pages = config.max_memory32_pages.min(100);
         config.max_memory64_pages = config.max_memory64_pages.min(100);
         Ok(())
diff --git a/fuzz/src/validate_valid_module.rs b/fuzz/src/validate_valid_module.rs
index 7f3cd21f..85592543 100644
--- a/fuzz/src/validate_valid_module.rs
+++ b/fuzz/src/validate_valid_module.rs
@@ -36,6 +36,12 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
         memory64: config.memory64_enabled,
         threads: config.threads_enabled,
         exceptions: config.exceptions_enabled,
+        // TODO: determine our larger story for function-references in
+        // wasm-tools and whether we should just have a Wasm GC flag since
+        // function-references is effectively part of the Wasm GC proposal at
+        // this point.
+        function_references: config.gc_enabled,
+        gc: config.gc_enabled,
         ..wasmparser::WasmFeatures::default()
     });
     if let Err(e) = validator.validate_all(&wasm_bytes) {
@@ -55,18 +61,28 @@ pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
             e
         )
     });
+
     let wasm_bytes = wat::parse_str(&wat_string).unwrap_or_else(|e| {
         panic!(
             "failed to assemble wat into Wasm with `wat::parse_str`: {}",
             e
         )
     });
+    if log::log_enabled!(log::Level::Debug) {
+        log::debug!("Writing roundtripped wasm to `test2.wasm`...");
+        std::fs::write("test2.wasm", &wasm_bytes).unwrap();
+    }
+
     let wat_string2 = wasmprinter::print_bytes(&wasm_bytes).unwrap_or_else(|e| {
         panic!(
             "failed second disassembly of Wasm into wat with `wasmprinter::print_bytes`: {}",
             e
         )
     });
+    if log::log_enabled!(log::Level::Debug) {
+        log::debug!("Writing round tripped text format to `test2.wat`...");
+        std::fs::write("test2.wat", &wat_string2).unwrap();
+    }
 
     if wat_string != wat_string2 {
         panic!("failed to roundtrip valid module");


Test patch:
diff --git a/crates/wasm-smith/tests/available_imports.rs b/crates/wasm-smith/tests/available_imports.rs
index a5e3fbf7..6528171e 100644
--- a/crates/wasm-smith/tests/available_imports.rs
+++ b/crates/wasm-smith/tests/available_imports.rs
@@ -33,14 +33,16 @@ fn smoke_test_imports_config() {
             for payload in Parser::new(0).parse_all(&wasm_bytes) {
                 let payload = payload.unwrap();
                 if let wasmparser::Payload::TypeSection(rdr) = payload {
-                    // Gather the signature types to later check function types against.
+                    // Gather the signature types to later check function types
+                    // against.
                     for ty in rdr.into_iter_err_on_gc_types() {
                         sig_types.push(ty.unwrap());
                     }
                 } else if let wasmparser::Payload::ImportSection(rdr) = payload {
-                    // Read out imports, checking that they all are within the list of expected
-                    // imports (i.e. we don't generate arbitrary ones), and that we handle the
-                    // logic correctly (i.e. signature types are as expected)
+                    // Read out imports, checking that they all are within the
+                    // list of expected imports (i.e. we don't generate
+                    // arbitrary ones), and that we handle the logic correctly
+                    // (i.e. signature types are as expected)
                     for import in rdr {
                         let import = import.unwrap();
                         use AvailableImportKind as I;
@@ -82,9 +84,10 @@ fn smoke_test_imports_config() {
                 }
             }
 
-            // Verify that we have seen both instances with partial imports (i.e. we don't always
-            // just copy over all the imports from the example module) and also that we eventually
-            // observe all of the imports being used (i.e. selection is reasonably random)
+            // Verify that we have seen both instances with partial imports
+            // (i.e. we don't always just copy over all the imports from the
+            // example module) and also that we eventually observe all of the
+            // imports being used (i.e. selection is reasonably random)
             for (m, f, _) in &available[..] {
                 let seen = imports_seen[&(*m, *f)];
                 let global_seen = global_imports_seen
@@ -117,6 +120,7 @@ fn import_config(
     Vec<(&'static str, &'static str, AvailableImportKind)>,
 ) {
     let mut config = Config::arbitrary(u).expect("arbitrary swarm");
+    config.gc_enabled = false;
     config.exceptions_enabled = u.arbitrary().expect("exceptions enabled for swarm");
     let available = {
         use {AvailableImportKind::*, ValType::*};
@@ -192,5 +196,5 @@ fn validate(validator: &mut Validator, bytes: &[u8]) {
     if let Ok(text) = wasmprinter::print_bytes(bytes) {
         drop(std::fs::write("test.wat", &text));
     }
-    panic!("wasm failed to validate {:?}", err);
+    panic!("wasm failed to validate: {}", err);
 }
diff --git a/crates/wasm-smith/tests/core.rs b/crates/wasm-smith/tests/core.rs
index 17d9329c..5816f8e3 100644
--- a/crates/wasm-smith/tests/core.rs
+++ b/crates/wasm-smith/tests/core.rs
@@ -119,6 +119,25 @@ fn smoke_test_no_trapping_mode() {
     }
 }
 
+#[test]
+fn smoke_test_wasm_gc() {
+    let mut rng = SmallRng::seed_from_u64(0);
+    let mut buf = vec![0; 2048];
+    for _ in 0..1024 {
+        rng.fill_bytes(&mut buf);
+        let mut u = Unstructured::new(&buf);
+        let config = Config {
+            gc_enabled: true,
+            ..Config::default()
+        };
+        if let Ok(module) = Module::new(config, &mut u) {
+            let wasm_bytes = module.to_bytes();
+            let mut validator = Validator::new_with_features(wasm_features());
+            validate(&mut validator, &wasm_bytes);
+        }
+    }
+}
+
 fn wasm_features() -> WasmFeatures {
     WasmFeatures {
         multi_memory: true,
@@ -126,6 +145,8 @@ fn wasm_features() -> WasmFeatures {
         memory64: true,
         exceptions: true,
         tail_call: true,
+        function_references: true,
+        gc: true,
         ..WasmFeatures::default()
     }
 }
@@ -166,5 +187,5 @@ fn validate(validator: &mut Validator, bytes: &[u8]) {
     if let Ok(text) = wasmprinter::print_bytes(bytes) {
         drop(std::fs::write("test.wat", &text));
     }
-    panic!("wasm failed to validate {:?}", err);
+    panic!("wasm failed to validate: {}", err);
 }
diff --git a/crates/wit-component/tests/components.rs b/crates/wit-component/tests/components.rs
index 27871d55..84cdfa41 100644
--- a/crates/wit-component/tests/components.rs
+++ b/crates/wit-component/tests/components.rs
@@ -205,13 +205,8 @@ fn read_core_module(path: &Path, resolve: &Resolve, pkg: PackageId) -> Result<Ve
     let mut producers = wasm_metadata::Producers::empty();
     producers.add("processed-by", "my-fake-bindgen", "123.45");
 
-    let encoded = wit_component::metadata::encode(
-        resolve,
-        world,
-        StringEncoding::UTF8,
-        Some(&producers),
-        Some(true),
-    )?;
+    let encoded =
+        wit_component::metadata::encode(resolve, world, StringEncoding::UTF8, Some(&producers))?;
 
     let section = wasm_encoder::CustomSection {
         name: "component-type".into(),
diff --git a/tests/snapshots/local/gc/gc-rec-sub.wat.print b/tests/snapshots/local/gc/gc-rec-sub.wat.print
index 61319c59..d3bd5f05 100644
--- a/tests/snapshots/local/gc/gc-rec-sub.wat.print
+++ b/tests/snapshots/local/gc/gc-rec-sub.wat.print
@@ -27,15 +27,15 @@
   )
   (rec
     (type $a (;12;) (sub (func)))
-    (type (;13;) (sub $a (;12;) (func)))
+    (type (;13;) (sub $a (func)))
   )
   (rec
-    (type (;14;) (sub $a (;12;) (func)))
+    (type (;14;) (sub $a (func)))
   )
   (rec
-    (type (;15;) (sub final $a (;12;) (func)))
+    (type (;15;) (sub final $a (func)))
   )
-  (type (;16;) (sub $a (;12;) (func)))
+  (type (;16;) (sub $a (func)))
   (rec
     (type $t1 (;17;) (struct (field (ref 18))))
     (type $t2 (;18;) (sub (struct (field (ref 17)))))
diff --git a/tests/snapshots/local/gc/gc-subtypes.wat.print b/tests/snapshots/local/gc/gc-subtypes.wat.print
index 3a33683f..74b672db 100644
--- a/tests/snapshots/local/gc/gc-subtypes.wat.print
+++ b/tests/snapshots/local/gc/gc-subtypes.wat.print
@@ -1,75 +1,75 @@
 (module
   (type $a (;0;) (sub (func)))
-  (type $b (;1;) (sub $a (;0;) (func)))
-  (type $c (;2;) (sub $b (;1;) (func)))
-  (type $b1 (;3;) (sub final $a (;0;) (func)))
+  (type $b (;1;) (sub $a (func)))
+  (type $c (;2;) (sub $b (func)))
+  (type $b1 (;3;) (sub final $a (func)))
   (type $d (;4;) (sub (struct)))
-  (type $e (;5;) (sub $d (;4;) (struct (field (mut (ref null 4))))))
-  (type $f (;6;) (sub final $e (;5;) (struct (field (ref 5)))))
+  (type $e (;5;) (sub $d (struct (field (mut (ref null 4))))))
+  (type $f (;6;) (sub final $e (struct (field (ref 5)))))
   (type $g (;7;) (sub (func (param (ref 5)) (result (ref 5)))))
-  (type $h (;8;) (sub $g (;7;) (func (param (ref 4)) (result (ref 6)))))
+  (type $h (;8;) (sub $g (func (param (ref 4)) (result (ref 6)))))
   (type $j (;9;) (sub (func (param (ref 1)) (result (ref 1)))))
-  (type $k (;10;) (sub $j (;9;) (func (param (ref 0)) (result (ref 2)))))
-  (type $l (;11;) (sub $j (;9;) (func (param (ref 1)) (result (ref 1)))))
+  (type $k (;10;) (sub $j (func (param (ref 0)) (result (ref 2)))))
+  (type $l (;11;) (sub $j (func (param (ref 1)) (result (ref 1)))))
   (type $m (;12;) (sub (array (mut i32))))
-  (type $n (;13;) (sub $m (;12;) (array i32)))
+  (type $n (;13;) (sub $m (array i32)))
   (type $o (;14;) (sub (array i32)))
-  (type $p (;15;) (sub $o (;14;) (array i32)))
+  (type $p (;15;) (sub $o (array i32)))
   (type $o1 (;16;) (sub (array i64)))
-  (type $p1 (;17;) (sub $o1 (;16;) (array i64)))
+  (type $p1 (;17;) (sub $o1 (array i64)))
   (type $q (;18;) (sub (array (mut anyref))))
-  (type $q0 (;19;) (sub $q (;18;) (array (ref any))))
-  (type $q1 (;20;) (sub $q (;18;) (array (mut eqref))))
-  (type $q2 (;21;) (sub $q1 (;20;) (array (mut (ref eq)))))
-  (type $q3 (;22;) (sub $q2 (;21;) (array (ref eq))))
-  (type $r (;23;) (sub $q (;18;) (array i31ref)))
-  (type $r1 (;24;) (sub $q1 (;20;) (array i31ref)))
-  (type $s (;25;) (sub $r (;23;) (array (ref i31))))
-  (type $s1 (;26;) (sub $q1 (;20;) (array (ref i31))))
-  (type $s2 (;27;) (sub $q2 (;21;) (array (ref i31))))
-  (type $rr (;28;) (sub $q (;18;) (array arrayref)))
-  (type $rr1 (;29;) (sub $q1 (;20;) (array arrayref)))
-  (type $ss (;30;) (sub $rr (;28;) (array (ref array))))
-  (type $ss0 (;31;) (sub $ss (;30;) (array (ref 28))))
-  (type $ss1 (;32;) (sub $q1 (;20;) (array (ref array))))
-  (type (;33;) (sub $q1 (;20;) (array (ref 28))))
-  (type $ss2 (;34;) (sub $q2 (;21;) (array (ref array))))
-  (type (;35;) (sub $q2 (;21;) (array (ref 28))))
-  (type $rrr (;36;) (sub $q (;18;) (array structref)))
-  (type $rrr1 (;37;) (sub $q1 (;20;) (array structref)))
-  (type $sss (;38;) (sub $rrr (;36;) (array (ref struct))))
-  (type $sss0 (;39;) (sub $rrr (;36;) (array (ref null 4))))
-  (type $sss1 (;40;) (sub $q1 (;20;) (array (ref struct))))
-  (type (;41;) (sub $q1 (;20;) (array (ref 4))))
-  (type $sss2 (;42;) (sub $q2 (;21;) (array (ref struct))))
-  (type (;43;) (sub $q2 (;21;) (array (ref 4))))
-  (type $z1 (;44;) (sub $q (;18;) (array (mut nullref))))
-  (type $z2 (;45;) (sub $q0 (;19;) (array (ref none))))
-  (type $z3 (;46;) (sub $z1 (;44;) (array (mut (ref none)))))
-  (type $z4 (;47;) (sub $z1 (;44;) (array nullref)))
-  (type (;48;) (sub $q1 (;20;) (array nullref)))
-  (type (;49;) (sub $r (;23;) (array nullref)))
-  (type (;50;) (sub $rr (;28;) (array nullref)))
-  (type (;51;) (sub $rrr (;36;) (array nullref)))
-  (type (;52;) (sub $q1 (;20;) (array (ref none))))
-  (type (;53;) (sub $r (;23;) (array (ref none))))
-  (type (;54;) (sub $rr (;28;) (array (ref none))))
-  (type (;55;) (sub $rrr (;36;) (array (ref none))))
+  (type $q0 (;19;) (sub $q (array (ref any))))
+  (type $q1 (;20;) (sub $q (array (mut eqref))))
+  (type $q2 (;21;) (sub $q1 (array (mut (ref eq)))))
+  (type $q3 (;22;) (sub $q2 (array (ref eq))))
+  (type $r (;23;) (sub $q (array i31ref)))
+  (type $r1 (;24;) (sub $q1 (array i31ref)))
+  (type $s (;25;) (sub $r (array (ref i31))))
+  (type $s1 (;26;) (sub $q1 (array (ref i31))))
+  (type $s2 (;27;) (sub $q2 (array (ref i31))))
+  (type $rr (;28;) (sub $q (array arrayref)))
+  (type $rr1 (;29;) (sub $q1 (array arrayref)))
+  (type $ss (;30;) (sub $rr (array (ref array))))
+  (type $ss0 (;31;) (sub $ss (array (ref 28))))
+  (type $ss1 (;32;) (sub $q1 (array (ref array))))
+  (type (;33;) (sub $q1 (array (ref 28))))
+  (type $ss2 (;34;) (sub $q2 (array (ref array))))
+  (type (;35;) (sub $q2 (array (ref 28))))
+  (type $rrr (;36;) (sub $q (array structref)))
+  (type $rrr1 (;37;) (sub $q1 (array structref)))
+  (type $sss (;38;) (sub $rrr (array (ref struct))))
+  (type $sss0 (;39;) (sub $rrr (array (ref null 4))))
+  (type $sss1 (;40;) (sub $q1 (array (ref struct))))
+  (type (;41;) (sub $q1 (array (ref 4))))
+  (type $sss2 (;42;) (sub $q2 (array (ref struct))))
+  (type (;43;) (sub $q2 (array (ref 4))))
+  (type $z1 (;44;) (sub $q (array (mut nullref))))
+  (type $z2 (;45;) (sub $q0 (array (ref none))))
+  (type $z3 (;46;) (sub $z1 (array (mut (ref none)))))
+  (type $z4 (;47;) (sub $z1 (array nullref)))
+  (type (;48;) (sub $q1 (array nullref)))
+  (type (;49;) (sub $r (array nullref)))
+  (type (;50;) (sub $rr (array nullref)))
+  (type (;51;) (sub $rrr (array nullref)))
+  (type (;52;) (sub $q1 (array (ref none))))
+  (type (;53;) (sub $r (array (ref none))))
+  (type (;54;) (sub $rr (array (ref none))))
+  (type (;55;) (sub $rrr (array (ref none))))
   (type $t (;56;) (sub (array (mut funcref))))
-  (type $u (;57;) (sub $t (;56;) (array funcref)))
-  (type $v (;58;) (sub $u (;57;) (array (ref func))))
-  (type $w (;59;) (sub $v (;58;) (array (ref 0))))
-  (type $x (;60;) (sub $t (;56;) (array (ref null 0))))
-  (type $y (;61;) (sub $w (;59;) (array (ref nofunc))))
-  (type $z (;62;) (sub $x (;60;) (array nullfuncref)))
+  (type $u (;57;) (sub $t (array funcref)))
+  (type $v (;58;) (sub $u (array (ref func))))
+  (type $w (;59;) (sub $v (array (ref 0))))
+  (type $x (;60;) (sub $t (array (ref null 0))))
+  (type $y (;61;) (sub $w (array (ref nofunc))))
+  (type $z (;62;) (sub $x (array nullfuncref)))
   (type $t0 (;63;) (sub (array (mut externref))))
-  (type $u0 (;64;) (sub $t0 (;63;) (array externref)))
-  (type $v0 (;65;) (sub $u0 (;64;) (array (ref extern))))
-  (type $y0 (;66;) (sub $v0 (;65;) (array (ref noextern))))
-  (type $y01 (;67;) (sub $u0 (;64;) (array (ref noextern))))
-  (type $z0 (;68;) (sub $u0 (;64;) (array nullexternref)))
+  (type $u0 (;64;) (sub $t0 (array externref)))
+  (type $v0 (;65;) (sub $u0 (array (ref extern))))
+  (type $y0 (;66;) (sub $v0 (array (ref noextern))))
+  (type $y01 (;67;) (sub $u0 (array (ref noextern))))
+  (type $z0 (;68;) (sub $u0 (array nullexternref)))
   (type $A (;69;) (sub (struct (field (mut i32)))))
-  (type $B (;70;) (sub $A (;69;) (struct (field (mut i32)))))
-  (type (;71;) (sub $A (;69;) (struct (field (mut i32)))))
-  (type (;72;) (sub $A (;69;) (struct (field (mut i32)) (field (mut i64)))))
+  (type $B (;70;) (sub $A (struct (field (mut i32)))))
+  (type (;71;) (sub $A (struct (field (mut i32)))))
+  (type (;72;) (sub $A (struct (field (mut i32)) (field (mut i64)))))
 )
\ No newline at end of file
diff --git a/tests/snapshots/local/gc/subtype-of-self-recursive-type.wast/0.print b/tests/snapshots/local/gc/subtype-of-self-recursive-type.wast/0.print
index 1adacc16..06ddb87d 100644
--- a/tests/snapshots/local/gc/subtype-of-self-recursive-type.wast/0.print
+++ b/tests/snapshots/local/gc/subtype-of-self-recursive-type.wast/0.print
@@ -1,7 +1,7 @@
 (module
   (type $t (;0;) (sub (struct (field anyref))))
   (rec
-    (type $r (;1;) (sub $t (;0;) (struct (field (ref 1)))))
+    (type $r (;1;) (sub $t (struct (field (ref 1)))))
   )
-  (type $t' (;2;) (sub $r (;1;) (struct (field (ref 1)) (field i32))))
+  (type $t' (;2;) (sub $r (struct (field (ref 1)) (field i32))))
 )
\ No newline at end of file
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/0.print b/tests/snapshots/local/gc/type-subtyping.wast/0.print
index e79654ba..3ae0b9b7 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/0.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/0.print
@@ -1,9 +1,9 @@
 (module
   (type $e0 (;0;) (sub (array i32)))
-  (type $e1 (;1;) (sub $e0 (;0;) (array i32)))
+  (type $e1 (;1;) (sub $e0 (array i32)))
   (type $e2 (;2;) (sub (array anyref)))
   (type $e3 (;3;) (sub (array (ref null 0))))
   (type $e4 (;4;) (sub (array (ref 1))))
   (type $m1 (;5;) (sub (array (mut i32))))
-  (type $m2 (;6;) (sub $m1 (;5;) (array (mut i32))))
+  (type $m2 (;6;) (sub $m1 (array (mut i32))))
 )
\ No newline at end of file
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/1.print b/tests/snapshots/local/gc/type-subtyping.wast/1.print
index ba6da153..ad9da2af 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/1.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/1.print
@@ -1,8 +1,8 @@
 (module
   (type $e0 (;0;) (sub (struct)))
-  (type $e1 (;1;) (sub $e0 (;0;) (struct)))
-  (type $e2 (;2;) (sub $e1 (;1;) (struct (field i32))))
-  (type $e3 (;3;) (sub $e2 (;2;) (struct (field i32) (field (ref null 0)))))
-  (type $e4 (;4;) (sub $e3 (;3;) (struct (field i32) (field (ref 0)) (field (mut i64)))))
-  (type $e5 (;5;) (sub $e4 (;4;) (struct (field i32) (field (ref 1)) (field (mut i64)))))
+  (type $e1 (;1;) (sub $e0 (struct)))
+  (type $e2 (;2;) (sub $e1 (struct (field i32))))
+  (type $e3 (;3;) (sub $e2 (struct (field i32) (field (ref null 0)))))
+  (type $e4 (;4;) (sub $e3 (struct (field i32) (field (ref 0)) (field (mut i64)))))
+  (type $e5 (;5;) (sub $e4 (struct (field i32) (field (ref 1)) (field (mut i64)))))
 )
\ No newline at end of file
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/11.print b/tests/snapshots/local/gc/type-subtyping.wast/11.print
index d6b282a8..e065df1d 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/11.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/11.print
@@ -8,7 +8,7 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g (;4;) (sub $f1 (;0;) (func)))
+    (type $g (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (func $g (;0;) (type $g))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/12.print b/tests/snapshots/local/gc/type-subtyping.wast/12.print
index 1d378bb1..1007b08e 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/12.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/12.print
@@ -8,15 +8,15 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
-    (type (;7;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
+    (type $g2 (;6;) (sub $f2 (func)))
+    (type (;7;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
   )
   (rec
-    (type $h (;8;) (sub $g2 (;6;) (func)))
+    (type $h (;8;) (sub $g2 (func)))
     (type (;9;) (struct))
   )
   (func $h (;0;) (type $h))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/13.print b/tests/snapshots/local/gc/type-subtyping.wast/13.print
index 1564b238..ab5b99fd 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/13.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/13.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (func $f11 (;0;) (type $f11) (result (ref func))
     unreachable
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/14.print b/tests/snapshots/local/gc/type-subtyping.wast/14.print
index b270b32a..26222845 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/14.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/14.print
@@ -1,19 +1,19 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (rec
-    (type $g11 (;4;) (sub $f11 (;0;) (func (result (ref func)))))
-    (type $g12 (;5;) (sub $g11 (;4;) (func (result (ref 4)))))
+    (type $g11 (;4;) (sub $f11 (func (result (ref func)))))
+    (type $g12 (;5;) (sub $g11 (func (result (ref 4)))))
   )
   (rec
-    (type $g21 (;6;) (sub $f21 (;2;) (func (result (ref func)))))
-    (type $g22 (;7;) (sub $g21 (;6;) (func (result (ref 6)))))
+    (type $g21 (;6;) (sub $f21 (func (result (ref func)))))
+    (type $g22 (;7;) (sub $g21 (func (result (ref 6)))))
   )
   (func $g11 (;0;) (type $g11) (result (ref func))
     unreachable
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/17.print b/tests/snapshots/local/gc/type-subtyping.wast/17.print
index e6a20185..0ed7ed12 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/17.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/17.print
@@ -1,10 +1,10 @@
 (module
   (type $t0 (;0;) (sub (func (result funcref))))
   (rec
-    (type $t1 (;1;) (sub $t0 (;0;) (func (result (ref null 1)))))
+    (type $t1 (;1;) (sub $t0 (func (result (ref null 1)))))
   )
   (rec
-    (type $t2 (;2;) (sub $t1 (;1;) (func (result (ref null 2)))))
+    (type $t2 (;2;) (sub $t1 (func (result (ref null 2)))))
   )
   (type (;3;) (func))
   (func $f0 (;0;) (type $t0) (result funcref)
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/2.print b/tests/snapshots/local/gc/type-subtyping.wast/2.print
index 65efbd9c..01dc95cd 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/2.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/2.print
@@ -1,8 +1,8 @@
 (module
   (type $s (;0;) (sub (struct)))
-  (type $s' (;1;) (sub $s (;0;) (struct)))
+  (type $s' (;1;) (sub $s (struct)))
   (type $f1 (;2;) (sub (func (param (ref 1)) (result anyref))))
-  (type $f2 (;3;) (sub $f1 (;2;) (func (param (ref 0)) (result (ref any)))))
-  (type $f3 (;4;) (sub $f2 (;3;) (func (param (ref null 0)) (result (ref 0)))))
-  (type $f4 (;5;) (sub $f3 (;4;) (func (param structref) (result (ref 1)))))
+  (type $f2 (;3;) (sub $f1 (func (param (ref 0)) (result (ref any)))))
+  (type $f3 (;4;) (sub $f2 (func (param (ref null 0)) (result (ref 0)))))
+  (type $f4 (;5;) (sub $f3 (func (param structref) (result (ref 1)))))
 )
\ No newline at end of file
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/3.print b/tests/snapshots/local/gc/type-subtyping.wast/3.print
index 1adacc16..06ddb87d 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/3.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/3.print
@@ -1,7 +1,7 @@
 (module
   (type $t (;0;) (sub (struct (field anyref))))
   (rec
-    (type $r (;1;) (sub $t (;0;) (struct (field (ref 1)))))
+    (type $r (;1;) (sub $t (struct (field (ref 1)))))
   )
-  (type $t' (;2;) (sub $r (;1;) (struct (field (ref 1)) (field i32))))
+  (type $t' (;2;) (sub $r (struct (field (ref 1)) (field i32))))
 )
\ No newline at end of file
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/30.print b/tests/snapshots/local/gc/type-subtyping.wast/30.print
index 02d8c7da..99cb8971 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/30.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/30.print
@@ -8,11 +8,11 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
+    (type $g1 (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
+    (type $g2 (;6;) (sub $f2 (func)))
     (type (;7;) (struct))
   )
   (type (;8;) (func (result i32)))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/32.print b/tests/snapshots/local/gc/type-subtyping.wast/32.print
index 6d513aa4..6d941bef 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/32.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/32.print
@@ -8,12 +8,12 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
-    (type (;7;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
+    (type $g2 (;6;) (sub $f2 (func)))
+    (type (;7;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
   )
   (type (;8;) (func (result i32)))
   (func $g (;0;) (type $g2))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/34.print b/tests/snapshots/local/gc/type-subtyping.wast/34.print
index 33dc3bf9..a41c2447 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/34.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/34.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (type (;4;) (func (result i32 i32 i32 i32)))
   (func $f11 (;0;) (type $f11) (result (ref func))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/36.print b/tests/snapshots/local/gc/type-subtyping.wast/36.print
index 268ba4b7..8bf7f79d 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/36.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/36.print
@@ -1,10 +1,10 @@
 (module
   (type $t0 (;0;) (sub (func (result funcref))))
   (rec
-    (type $t1 (;1;) (sub $t0 (;0;) (func (result (ref null 1)))))
+    (type $t1 (;1;) (sub $t0 (func (result (ref null 1)))))
   )
   (rec
-    (type $t2 (;2;) (sub $t1 (;1;) (func (result (ref null 2)))))
+    (type $t2 (;2;) (sub $t1 (func (result (ref null 2)))))
   )
   (func (;0;) (type $t0) (result funcref)
     ref.null func
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/38.print b/tests/snapshots/local/gc/type-subtyping.wast/38.print
index 0bfc8e89..baf7bd1f 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/38.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/38.print
@@ -1,10 +1,10 @@
 (module
   (type $t0 (;0;) (sub (func (result funcref))))
   (rec
-    (type $t1 (;1;) (sub $t0 (;0;) (func (result (ref null 1)))))
+    (type $t1 (;1;) (sub $t0 (func (result (ref null 1)))))
   )
   (rec
-    (type $t2 (;2;) (sub $t1 (;1;) (func (result (ref null 2)))))
+    (type $t2 (;2;) (sub $t1 (func (result (ref null 2)))))
   )
   (import "M" "f0" (func (;0;) (type $t0)))
   (import "M" "f1" (func (;1;) (type $t0)))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/4.print b/tests/snapshots/local/gc/type-subtyping.wast/4.print
index 68305385..cb27eaf2 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/4.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/4.print
@@ -3,7 +3,7 @@
     (type $r1 (;0;) (sub (struct (field i32) (field (ref 0)))))
   )
   (rec
-    (type $r2 (;1;) (sub $r1 (;0;) (struct (field i32) (field (ref 2)))))
-    (type $r3 (;2;) (sub $r1 (;0;) (struct (field i32) (field (ref 1)))))
+    (type $r2 (;1;) (sub $r1 (struct (field i32) (field (ref 2)))))
+    (type $r3 (;2;) (sub $r1 (struct (field i32) (field (ref 1)))))
   )
 )
\ No newline at end of file
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/46.print b/tests/snapshots/local/gc/type-subtyping.wast/46.print
index ffeff4c8..867caa19 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/46.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/46.print
@@ -4,7 +4,7 @@
     (type (;1;) (struct (field (ref 0))))
   )
   (rec
-    (type $g2 (;2;) (sub $f2 (;0;) (func)))
+    (type $g2 (;2;) (sub $f2 (func)))
     (type (;3;) (struct))
   )
   (func (;0;) (type $g2))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/48.print b/tests/snapshots/local/gc/type-subtyping.wast/48.print
index 57106a6c..0995a3b1 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/48.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/48.print
@@ -4,7 +4,7 @@
     (type (;1;) (struct (field (ref 0))))
   )
   (rec
-    (type $g1 (;2;) (sub $f1 (;0;) (func)))
+    (type $g1 (;2;) (sub $f1 (func)))
     (type (;3;) (struct))
   )
   (import "M3" "g" (func (;0;) (type $g1)))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/49.print b/tests/snapshots/local/gc/type-subtyping.wast/49.print
index 8837d211..dda87e56 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/49.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/49.print
@@ -8,8 +8,8 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g2 (;4;) (sub $f2 (;2;) (func)))
-    (type (;5;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 4)))))
+    (type $g2 (;4;) (sub $f2 (func)))
+    (type (;5;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 4)))))
   )
   (func (;0;) (type $g2))
   (export "g" (func 0))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/5.print b/tests/snapshots/local/gc/type-subtyping.wast/5.print
index 74a5f4ec..776b1c50 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/5.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/5.print
@@ -4,8 +4,8 @@
     (type $a2 (;1;) (sub (struct (field i64) (field (ref 0)))))
   )
   (rec
-    (type $b1 (;2;) (sub $a2 (;1;) (struct (field i64) (field (ref 0)) (field i32))))
-    (type $b2 (;3;) (sub $a1 (;0;) (struct (field i32) (field (ref 1)) (field i32))))
-    (type $b3 (;4;) (sub $a2 (;1;) (struct (field i64) (field (ref 3)) (field i32))))
+    (type $b1 (;2;) (sub $a2 (struct (field i64) (field (ref 0)) (field i32))))
+    (type $b2 (;3;) (sub $a1 (struct (field i32) (field (ref 1)) (field i32))))
+    (type $b3 (;4;) (sub $a2 (struct (field i64) (field (ref 3)) (field i32))))
   )
 )
\ No newline at end of file
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/51.print b/tests/snapshots/local/gc/type-subtyping.wast/51.print
index 6982effb..3c0aca3f 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/51.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/51.print
@@ -8,8 +8,8 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (import "M4" "g" (func (;0;) (type $g1)))
 )
\ No newline at end of file
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/52.print b/tests/snapshots/local/gc/type-subtyping.wast/52.print
index e1436ef6..43ef5273 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/52.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/52.print
@@ -8,7 +8,7 @@
     (type (;3;) (struct (field (ref 0))))
   )
   (rec
-    (type $g2 (;4;) (sub $f2 (;2;) (func)))
+    (type $g2 (;4;) (sub $f2 (func)))
     (type (;5;) (struct))
   )
   (func (;0;) (type $g2))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/55.print b/tests/snapshots/local/gc/type-subtyping.wast/55.print
index f920ca8d..06fdc52d 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/55.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/55.print
@@ -8,7 +8,7 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g (;4;) (sub $f1 (;0;) (func)))
+    (type $g (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (func (;0;) (type $g))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/57.print b/tests/snapshots/local/gc/type-subtyping.wast/57.print
index 22a485ad..fbc88506 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/57.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/57.print
@@ -8,7 +8,7 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g (;4;) (sub $f1 (;0;) (func)))
+    (type $g (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (import "M6" "g" (func (;0;) (type $f1)))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/58.print b/tests/snapshots/local/gc/type-subtyping.wast/58.print
index 4964ecda..7af88e83 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/58.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/58.print
@@ -8,11 +8,11 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g2 (;4;) (sub $f2 (;2;) (func)))
-    (type (;5;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 4)))))
+    (type $g2 (;4;) (sub $f2 (func)))
+    (type (;5;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $h (;6;) (sub $g2 (;4;) (func)))
+    (type $h (;6;) (sub $g2 (func)))
     (type (;7;) (struct))
   )
   (func (;0;) (type $h))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/6.print b/tests/snapshots/local/gc/type-subtyping.wast/6.print
index be7f63f4..b0270453 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/6.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/6.print
@@ -1,8 +1,8 @@
 (module
   (rec
     (type $t1 (;0;) (sub (func (param i32 (ref 2)))))
-    (type $t2 (;1;) (sub $t1 (;0;) (func (param i32 (ref 1)))))
-    (type $t3 (;2;) (sub $t2 (;1;) (func (param i32 (ref 0)))))
+    (type $t2 (;1;) (sub $t1 (func (param i32 (ref 1)))))
+    (type $t3 (;2;) (sub $t2 (func (param i32 (ref 0)))))
   )
   (type (;3;) (func (param (ref 0))))
   (type (;4;) (func (param (ref 1))))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/60.print b/tests/snapshots/local/gc/type-subtyping.wast/60.print
index 40471356..4129dc13 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/60.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/60.print
@@ -8,11 +8,11 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $h (;6;) (sub $g1 (;4;) (func)))
+    (type $h (;6;) (sub $g1 (func)))
     (type (;7;) (struct))
   )
   (import "M7" "h" (func (;0;) (type $f1)))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/61.print b/tests/snapshots/local/gc/type-subtyping.wast/61.print
index 141f5b5a..cafd8cb3 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/61.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/61.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (func (;0;) (type $f11) (result (ref func))
     unreachable
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/63.print b/tests/snapshots/local/gc/type-subtyping.wast/63.print
index 74486efc..2d2f3a4e 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/63.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/63.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (import "M8" "f11" (func (;0;) (type $f11)))
   (import "M8" "f11" (func (;1;) (type $f21)))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/64.print b/tests/snapshots/local/gc/type-subtyping.wast/64.print
index c0cb5514..26773efb 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/64.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/64.print
@@ -1,19 +1,19 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (rec
-    (type $g11 (;4;) (sub $f11 (;0;) (func (result (ref func)))))
-    (type $g12 (;5;) (sub $g11 (;4;) (func (result (ref 4)))))
+    (type $g11 (;4;) (sub $f11 (func (result (ref func)))))
+    (type $g12 (;5;) (sub $g11 (func (result (ref 4)))))
   )
   (rec
-    (type $g21 (;6;) (sub $f21 (;2;) (func (result (ref func)))))
-    (type $g22 (;7;) (sub $g21 (;6;) (func (result (ref 6)))))
+    (type $g21 (;6;) (sub $f21 (func (result (ref func)))))
+    (type $g22 (;7;) (sub $g21 (func (result (ref 6)))))
   )
   (func (;0;) (type $g11) (result (ref func))
     unreachable
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/66.print b/tests/snapshots/local/gc/type-subtyping.wast/66.print
index 0fca36c7..3a8aff62 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/66.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/66.print
@@ -1,19 +1,19 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (rec
-    (type $g11 (;4;) (sub $f11 (;0;) (func (result (ref func)))))
-    (type $g12 (;5;) (sub $g11 (;4;) (func (result (ref 4)))))
+    (type $g11 (;4;) (sub $f11 (func (result (ref func)))))
+    (type $g12 (;5;) (sub $g11 (func (result (ref 4)))))
   )
   (rec
-    (type $g21 (;6;) (sub $f21 (;2;) (func (result (ref func)))))
-    (type $g22 (;7;) (sub $g21 (;6;) (func (result (ref 6)))))
+    (type $g21 (;6;) (sub $f21 (func (result (ref func)))))
+    (type $g22 (;7;) (sub $g21 (func (result (ref 6)))))
   )
   (import "M9" "g11" (func (;0;) (type $f11)))
   (import "M9" "g11" (func (;1;) (type $f21)))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/67.print b/tests/snapshots/local/gc/type-subtyping.wast/67.print
index 4a5b7805..1303cd6d 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/67.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/67.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func)))
-    (type $f12 (;1;) (sub $f11 (;0;) (func)))
+    (type $f12 (;1;) (sub $f11 (func)))
   )
   (rec
     (type $f21 (;2;) (sub (func)))
-    (type $f22 (;3;) (sub $f11 (;0;) (func)))
+    (type $f22 (;3;) (sub $f11 (func)))
   )
   (func (;0;) (type $f21))
   (export "f" (func 0))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/7.print b/tests/snapshots/local/gc/type-subtyping.wast/7.print
index f868722a..2ce853d1 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/7.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/7.print
@@ -4,10 +4,10 @@
     (type $u1 (;1;) (sub (func (result f32 (ref 0)))))
   )
   (rec
-    (type $t2 (;2;) (sub $t1 (;0;) (func (result i32 (ref 5)))))
-    (type $u2 (;3;) (sub $u1 (;1;) (func (result f32 (ref 4)))))
-    (type $t3 (;4;) (sub $t1 (;0;) (func (result i32 (ref 3)))))
-    (type $u3 (;5;) (sub $u1 (;1;) (func (result f32 (ref 2)))))
+    (type $t2 (;2;) (sub $t1 (func (result i32 (ref 5)))))
+    (type $u2 (;3;) (sub $u1 (func (result f32 (ref 4)))))
+    (type $t3 (;4;) (sub $t1 (func (result i32 (ref 3)))))
+    (type $u3 (;5;) (sub $u1 (func (result f32 (ref 2)))))
   )
   (type (;6;) (func (param (ref 0))))
   (type (;7;) (func (param (ref 2))))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/70.print b/tests/snapshots/local/gc/type-subtyping.wast/70.print
index 673aa465..198cdbae 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/70.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/70.print
@@ -1,15 +1,15 @@
 (module
   (rec
     (type $f01 (;0;) (sub (func)))
-    (type $f02 (;1;) (sub $f01 (;0;) (func)))
+    (type $f02 (;1;) (sub $f01 (func)))
   )
   (rec
     (type $f11 (;2;) (sub (func)))
-    (type $f12 (;3;) (sub $f01 (;0;) (func)))
+    (type $f12 (;3;) (sub $f01 (func)))
   )
   (rec
     (type $f21 (;4;) (sub (func)))
-    (type $f22 (;5;) (sub $f11 (;2;) (func)))
+    (type $f22 (;5;) (sub $f11 (func)))
   )
   (func (;0;) (type $f21))
   (export "f" (func 0))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/8.print b/tests/snapshots/local/gc/type-subtyping.wast/8.print
index 32a18362..2a9dd915 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/8.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/8.print
@@ -8,11 +8,11 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
+    (type $g1 (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
+    (type $g2 (;6;) (sub $f2 (func)))
     (type (;7;) (struct))
   )
   (func $g (;0;) (type $g2))
diff --git a/tests/snapshots/local/gc/type-subtyping.wast/9.print b/tests/snapshots/local/gc/type-subtyping.wast/9.print
index 612798a6..20361312 100644
--- a/tests/snapshots/local/gc/type-subtyping.wast/9.print
+++ b/tests/snapshots/local/gc/type-subtyping.wast/9.print
@@ -8,12 +8,12 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
-    (type (;7;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
+    (type $g2 (;6;) (sub $f2 (func)))
+    (type (;7;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
   )
   (func $g (;0;) (type $g2))
   (global (;0;) (ref 4) ref.func $g)
diff --git a/tests/snapshots/testsuite/proposals/gc/br_on_cast.wast/27.print b/tests/snapshots/testsuite/proposals/gc/br_on_cast.wast/27.print
index f454acd5..6d2fdbd7 100644
--- a/tests/snapshots/testsuite/proposals/gc/br_on_cast.wast/27.print
+++ b/tests/snapshots/testsuite/proposals/gc/br_on_cast.wast/27.print
@@ -1,12 +1,12 @@
 (module
   (type $t0 (;0;) (sub (struct)))
-  (type $t1 (;1;) (sub $t0 (;0;) (struct (field i32))))
-  (type $t1' (;2;) (sub $t0 (;0;) (struct (field i32))))
-  (type $t2 (;3;) (sub $t1 (;1;) (struct (field i32) (field i32))))
-  (type $t2' (;4;) (sub $t1' (;2;) (struct (field i32) (field i32))))
-  (type $t3 (;5;) (sub $t0 (;0;) (struct (field i32) (field i32))))
-  (type $t0' (;6;) (sub $t0 (;0;) (struct)))
-  (type $t4 (;7;) (sub $t0' (;6;) (struct (field i32) (field i32))))
+  (type $t1 (;1;) (sub $t0 (struct (field i32))))
+  (type $t1' (;2;) (sub $t0 (struct (field i32))))
+  (type $t2 (;3;) (sub $t1 (struct (field i32) (field i32))))
+  (type $t2' (;4;) (sub $t1' (struct (field i32) (field i32))))
+  (type $t3 (;5;) (sub $t0 (struct (field i32) (field i32))))
+  (type $t0' (;6;) (sub $t0 (struct)))
+  (type $t4 (;7;) (sub $t0' (struct (field i32) (field i32))))
   (type (;8;) (func))
   (func $init (;0;) (type 8)
     i32.const 0
diff --git a/tests/snapshots/testsuite/proposals/gc/br_on_cast_fail.wast/27.print b/tests/snapshots/testsuite/proposals/gc/br_on_cast_fail.wast/27.print
index d8e334ad..c880fe62 100644
--- a/tests/snapshots/testsuite/proposals/gc/br_on_cast_fail.wast/27.print
+++ b/tests/snapshots/testsuite/proposals/gc/br_on_cast_fail.wast/27.print
@@ -1,12 +1,12 @@
 (module
   (type $t0 (;0;) (sub (struct)))
-  (type $t1 (;1;) (sub $t0 (;0;) (struct (field i32))))
-  (type $t1' (;2;) (sub $t0 (;0;) (struct (field i32))))
-  (type $t2 (;3;) (sub $t1 (;1;) (struct (field i32) (field i32))))
-  (type $t2' (;4;) (sub $t1' (;2;) (struct (field i32) (field i32))))
-  (type $t3 (;5;) (sub $t0 (;0;) (struct (field i32) (field i32))))
-  (type $t0' (;6;) (sub $t0 (;0;) (struct)))
-  (type $t4 (;7;) (sub $t0' (;6;) (struct (field i32) (field i32))))
+  (type $t1 (;1;) (sub $t0 (struct (field i32))))
+  (type $t1' (;2;) (sub $t0 (struct (field i32))))
+  (type $t2 (;3;) (sub $t1 (struct (field i32) (field i32))))
+  (type $t2' (;4;) (sub $t1' (struct (field i32) (field i32))))
+  (type $t3 (;5;) (sub $t0 (struct (field i32) (field i32))))
+  (type $t0' (;6;) (sub $t0 (struct)))
+  (type $t4 (;7;) (sub $t0' (struct (field i32) (field i32))))
   (type (;8;) (func))
   (func $init (;0;) (type 8)
     i32.const 0
diff --git a/tests/snapshots/testsuite/proposals/gc/ref_cast.wast/42.print b/tests/snapshots/testsuite/proposals/gc/ref_cast.wast/42.print
index 73cd7aa6..1b16a411 100644
--- a/tests/snapshots/testsuite/proposals/gc/ref_cast.wast/42.print
+++ b/tests/snapshots/testsuite/proposals/gc/ref_cast.wast/42.print
@@ -1,12 +1,12 @@
 (module
   (type $t0 (;0;) (sub (struct)))
-  (type $t1 (;1;) (sub $t0 (;0;) (struct (field i32))))
-  (type $t1' (;2;) (sub $t0 (;0;) (struct (field i32))))
-  (type $t2 (;3;) (sub $t1 (;1;) (struct (field i32) (field i32))))
-  (type $t2' (;4;) (sub $t1' (;2;) (struct (field i32) (field i32))))
-  (type $t3 (;5;) (sub $t0 (;0;) (struct (field i32) (field i32))))
-  (type $t0' (;6;) (sub $t0 (;0;) (struct)))
-  (type $t4 (;7;) (sub $t0' (;6;) (struct (field i32) (field i32))))
+  (type $t1 (;1;) (sub $t0 (struct (field i32))))
+  (type $t1' (;2;) (sub $t0 (struct (field i32))))
+  (type $t2 (;3;) (sub $t1 (struct (field i32) (field i32))))
+  (type $t2' (;4;) (sub $t1' (struct (field i32) (field i32))))
+  (type $t3 (;5;) (sub $t0 (struct (field i32) (field i32))))
+  (type $t0' (;6;) (sub $t0 (struct)))
+  (type $t4 (;7;) (sub $t0' (struct (field i32) (field i32))))
   (type (;8;) (func))
   (func $init (;0;) (type 8)
     i32.const 0
diff --git a/tests/snapshots/testsuite/proposals/gc/ref_eq.wast/0.print b/tests/snapshots/testsuite/proposals/gc/ref_eq.wast/0.print
index ac3cb8f9..3d206444 100644
--- a/tests/snapshots/testsuite/proposals/gc/ref_eq.wast/0.print
+++ b/tests/snapshots/testsuite/proposals/gc/ref_eq.wast/0.print
@@ -2,10 +2,10 @@
   (type $st (;0;) (sub (struct)))
   (type $st' (;1;) (sub (struct (field i32))))
   (type $at (;2;) (array i8))
-  (type $st-sub1 (;3;) (sub $st (;0;) (struct)))
-  (type $st-sub2 (;4;) (sub $st (;0;) (struct)))
-  (type $st'-sub1 (;5;) (sub $st' (;1;) (struct (field i32))))
-  (type $st'-sub2 (;6;) (sub $st' (;1;) (struct (field i32))))
+  (type $st-sub1 (;3;) (sub $st (struct)))
+  (type $st-sub2 (;4;) (sub $st (struct)))
+  (type $st'-sub1 (;5;) (sub $st' (struct (field i32))))
+  (type $st'-sub2 (;6;) (sub $st' (struct (field i32))))
   (type (;7;) (func))
   (type (;8;) (func (param i32 i32) (result i32)))
   (func (;0;) (type 7)
diff --git a/tests/snapshots/testsuite/proposals/gc/ref_test.wast/68.print b/tests/snapshots/testsuite/proposals/gc/ref_test.wast/68.print
index 138b9eab..5f445621 100644
--- a/tests/snapshots/testsuite/proposals/gc/ref_test.wast/68.print
+++ b/tests/snapshots/testsuite/proposals/gc/ref_test.wast/68.print
@@ -1,12 +1,12 @@
 (module
   (type $t0 (;0;) (sub (struct)))
-  (type $t1 (;1;) (sub $t0 (;0;) (struct (field i32))))
-  (type $t1' (;2;) (sub $t0 (;0;) (struct (field i32))))
-  (type $t2 (;3;) (sub $t1 (;1;) (struct (field i32) (field i32))))
-  (type $t2' (;4;) (sub $t1' (;2;) (struct (field i32) (field i32))))
-  (type $t3 (;5;) (sub $t0 (;0;) (struct (field i32) (field i32))))
-  (type $t0' (;6;) (sub $t0 (;0;) (struct)))
-  (type $t4 (;7;) (sub $t0' (;6;) (struct (field i32) (field i32))))
+  (type $t1 (;1;) (sub $t0 (struct (field i32))))
+  (type $t1' (;2;) (sub $t0 (struct (field i32))))
+  (type $t2 (;3;) (sub $t1 (struct (field i32) (field i32))))
+  (type $t2' (;4;) (sub $t1' (struct (field i32) (field i32))))
+  (type $t3 (;5;) (sub $t0 (struct (field i32) (field i32))))
+  (type $t0' (;6;) (sub $t0 (struct)))
+  (type $t4 (;7;) (sub $t0' (struct (field i32) (field i32))))
   (type (;8;) (func))
   (func $init (;0;) (type 8)
     i32.const 0
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/0.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/0.print
index e79654ba..3ae0b9b7 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/0.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/0.print
@@ -1,9 +1,9 @@
 (module
   (type $e0 (;0;) (sub (array i32)))
-  (type $e1 (;1;) (sub $e0 (;0;) (array i32)))
+  (type $e1 (;1;) (sub $e0 (array i32)))
   (type $e2 (;2;) (sub (array anyref)))
   (type $e3 (;3;) (sub (array (ref null 0))))
   (type $e4 (;4;) (sub (array (ref 1))))
   (type $m1 (;5;) (sub (array (mut i32))))
-  (type $m2 (;6;) (sub $m1 (;5;) (array (mut i32))))
+  (type $m2 (;6;) (sub $m1 (array (mut i32))))
 )
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/1.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/1.print
index ba6da153..ad9da2af 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/1.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/1.print
@@ -1,8 +1,8 @@
 (module
   (type $e0 (;0;) (sub (struct)))
-  (type $e1 (;1;) (sub $e0 (;0;) (struct)))
-  (type $e2 (;2;) (sub $e1 (;1;) (struct (field i32))))
-  (type $e3 (;3;) (sub $e2 (;2;) (struct (field i32) (field (ref null 0)))))
-  (type $e4 (;4;) (sub $e3 (;3;) (struct (field i32) (field (ref 0)) (field (mut i64)))))
-  (type $e5 (;5;) (sub $e4 (;4;) (struct (field i32) (field (ref 1)) (field (mut i64)))))
+  (type $e1 (;1;) (sub $e0 (struct)))
+  (type $e2 (;2;) (sub $e1 (struct (field i32))))
+  (type $e3 (;3;) (sub $e2 (struct (field i32) (field (ref null 0)))))
+  (type $e4 (;4;) (sub $e3 (struct (field i32) (field (ref 0)) (field (mut i64)))))
+  (type $e5 (;5;) (sub $e4 (struct (field i32) (field (ref 1)) (field (mut i64)))))
 )
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/11.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/11.print
index d6b282a8..e065df1d 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/11.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/11.print
@@ -8,7 +8,7 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g (;4;) (sub $f1 (;0;) (func)))
+    (type $g (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (func $g (;0;) (type $g))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/12.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/12.print
index 1d378bb1..1007b08e 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/12.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/12.print
@@ -8,15 +8,15 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
-    (type (;7;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
+    (type $g2 (;6;) (sub $f2 (func)))
+    (type (;7;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
   )
   (rec
-    (type $h (;8;) (sub $g2 (;6;) (func)))
+    (type $h (;8;) (sub $g2 (func)))
     (type (;9;) (struct))
   )
   (func $h (;0;) (type $h))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/13.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/13.print
index 1564b238..ab5b99fd 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/13.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/13.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (func $f11 (;0;) (type $f11) (result (ref func))
     unreachable
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/14.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/14.print
index b270b32a..26222845 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/14.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/14.print
@@ -1,19 +1,19 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (rec
-    (type $g11 (;4;) (sub $f11 (;0;) (func (result (ref func)))))
-    (type $g12 (;5;) (sub $g11 (;4;) (func (result (ref 4)))))
+    (type $g11 (;4;) (sub $f11 (func (result (ref func)))))
+    (type $g12 (;5;) (sub $g11 (func (result (ref 4)))))
   )
   (rec
-    (type $g21 (;6;) (sub $f21 (;2;) (func (result (ref func)))))
-    (type $g22 (;7;) (sub $g21 (;6;) (func (result (ref 6)))))
+    (type $g21 (;6;) (sub $f21 (func (result (ref func)))))
+    (type $g22 (;7;) (sub $g21 (func (result (ref 6)))))
   )
   (func $g11 (;0;) (type $g11) (result (ref func))
     unreachable
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/17.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/17.print
index e6a20185..0ed7ed12 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/17.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/17.print
@@ -1,10 +1,10 @@
 (module
   (type $t0 (;0;) (sub (func (result funcref))))
   (rec
-    (type $t1 (;1;) (sub $t0 (;0;) (func (result (ref null 1)))))
+    (type $t1 (;1;) (sub $t0 (func (result (ref null 1)))))
   )
   (rec
-    (type $t2 (;2;) (sub $t1 (;1;) (func (result (ref null 2)))))
+    (type $t2 (;2;) (sub $t1 (func (result (ref null 2)))))
   )
   (type (;3;) (func))
   (func $f0 (;0;) (type $t0) (result funcref)
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/2.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/2.print
index 65efbd9c..01dc95cd 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/2.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/2.print
@@ -1,8 +1,8 @@
 (module
   (type $s (;0;) (sub (struct)))
-  (type $s' (;1;) (sub $s (;0;) (struct)))
+  (type $s' (;1;) (sub $s (struct)))
   (type $f1 (;2;) (sub (func (param (ref 1)) (result anyref))))
-  (type $f2 (;3;) (sub $f1 (;2;) (func (param (ref 0)) (result (ref any)))))
-  (type $f3 (;4;) (sub $f2 (;3;) (func (param (ref null 0)) (result (ref 0)))))
-  (type $f4 (;5;) (sub $f3 (;4;) (func (param structref) (result (ref 1)))))
+  (type $f2 (;3;) (sub $f1 (func (param (ref 0)) (result (ref any)))))
+  (type $f3 (;4;) (sub $f2 (func (param (ref null 0)) (result (ref 0)))))
+  (type $f4 (;5;) (sub $f3 (func (param structref) (result (ref 1)))))
 )
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/3.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/3.print
index 1adacc16..06ddb87d 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/3.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/3.print
@@ -1,7 +1,7 @@
 (module
   (type $t (;0;) (sub (struct (field anyref))))
   (rec
-    (type $r (;1;) (sub $t (;0;) (struct (field (ref 1)))))
+    (type $r (;1;) (sub $t (struct (field (ref 1)))))
   )
-  (type $t' (;2;) (sub $r (;1;) (struct (field (ref 1)) (field i32))))
+  (type $t' (;2;) (sub $r (struct (field (ref 1)) (field i32))))
 )
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/30.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/30.print
index 02d8c7da..99cb8971 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/30.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/30.print
@@ -8,11 +8,11 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
+    (type $g1 (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
+    (type $g2 (;6;) (sub $f2 (func)))
     (type (;7;) (struct))
   )
   (type (;8;) (func (result i32)))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/32.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/32.print
index 6d513aa4..6d941bef 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/32.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/32.print
@@ -8,12 +8,12 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
-    (type (;7;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
+    (type $g2 (;6;) (sub $f2 (func)))
+    (type (;7;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
   )
   (type (;8;) (func (result i32)))
   (func $g (;0;) (type $g2))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/34.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/34.print
index 0b30bb67..f67c0e3a 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/34.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/34.print
@@ -8,11 +8,11 @@
     (type (;3;) (struct (field (ref 0))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
+    (type $g1 (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
+    (type $g2 (;6;) (sub $f2 (func)))
     (type (;7;) (struct))
   )
   (type (;8;) (func (result i32)))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/36.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/36.print
index d4815997..475b353a 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/36.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/36.print
@@ -8,7 +8,7 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g (;4;) (sub $f1 (;0;) (func)))
+    (type $g (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (type (;6;) (func (result i32)))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/38.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/38.print
index ff3ad19f..4196c778 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/38.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/38.print
@@ -8,15 +8,15 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
-    (type (;7;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
+    (type $g2 (;6;) (sub $f2 (func)))
+    (type (;7;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
   )
   (rec
-    (type $h (;8;) (sub $g2 (;6;) (func)))
+    (type $h (;8;) (sub $g2 (func)))
     (type (;9;) (struct))
   )
   (type (;10;) (func (result i32 i32)))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/4.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/4.print
index 68305385..cb27eaf2 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/4.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/4.print
@@ -3,7 +3,7 @@
     (type $r1 (;0;) (sub (struct (field i32) (field (ref 0)))))
   )
   (rec
-    (type $r2 (;1;) (sub $r1 (;0;) (struct (field i32) (field (ref 2)))))
-    (type $r3 (;2;) (sub $r1 (;0;) (struct (field i32) (field (ref 1)))))
+    (type $r2 (;1;) (sub $r1 (struct (field i32) (field (ref 2)))))
+    (type $r3 (;2;) (sub $r1 (struct (field i32) (field (ref 1)))))
   )
 )
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/40.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/40.print
index 33dc3bf9..a41c2447 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/40.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/40.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (type (;4;) (func (result i32 i32 i32 i32)))
   (func $f11 (;0;) (type $f11) (result (ref func))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/42.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/42.print
index ddf86620..517c91dd 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/42.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/42.print
@@ -1,19 +1,19 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (rec
-    (type $g11 (;4;) (sub $f11 (;0;) (func (result (ref func)))))
-    (type $g12 (;5;) (sub $g11 (;4;) (func (result (ref 4)))))
+    (type $g11 (;4;) (sub $f11 (func (result (ref func)))))
+    (type $g12 (;5;) (sub $g11 (func (result (ref 4)))))
   )
   (rec
-    (type $g21 (;6;) (sub $f21 (;2;) (func (result (ref func)))))
-    (type $g22 (;7;) (sub $g21 (;6;) (func (result (ref 6)))))
+    (type $g21 (;6;) (sub $f21 (func (result (ref func)))))
+    (type $g22 (;7;) (sub $g21 (func (result (ref 6)))))
   )
   (type (;8;) (func (result i32 i32 i32 i32 i32 i32 i32 i32)))
   (func $g11 (;0;) (type $g11) (result (ref func))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/44.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/44.print
index 3d3c791b..1bf88eea 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/44.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/44.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func)))
-    (type $f12 (;1;) (sub $f11 (;0;) (func)))
+    (type $f12 (;1;) (sub $f11 (func)))
   )
   (rec
     (type $f21 (;2;) (sub (func)))
-    (type $f22 (;3;) (sub $f11 (;0;) (func)))
+    (type $f22 (;3;) (sub $f11 (func)))
   )
   (type (;4;) (func (result i32)))
   (func $f (;0;) (type $f21))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/46.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/46.print
index 53d14181..eacdc66b 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/46.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/46.print
@@ -1,15 +1,15 @@
 (module
   (rec
     (type $f01 (;0;) (sub (func)))
-    (type $f02 (;1;) (sub $f01 (;0;) (func)))
+    (type $f02 (;1;) (sub $f01 (func)))
   )
   (rec
     (type $f11 (;2;) (sub (func)))
-    (type $f12 (;3;) (sub $f01 (;0;) (func)))
+    (type $f12 (;3;) (sub $f01 (func)))
   )
   (rec
     (type $f21 (;4;) (sub (func)))
-    (type $f22 (;5;) (sub $f11 (;2;) (func)))
+    (type $f22 (;5;) (sub $f11 (func)))
   )
   (type (;6;) (func (result i32)))
   (func $f (;0;) (type $f21))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/48.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/48.print
index 268ba4b7..8bf7f79d 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/48.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/48.print
@@ -1,10 +1,10 @@
 (module
   (type $t0 (;0;) (sub (func (result funcref))))
   (rec
-    (type $t1 (;1;) (sub $t0 (;0;) (func (result (ref null 1)))))
+    (type $t1 (;1;) (sub $t0 (func (result (ref null 1)))))
   )
   (rec
-    (type $t2 (;2;) (sub $t1 (;1;) (func (result (ref null 2)))))
+    (type $t2 (;2;) (sub $t1 (func (result (ref null 2)))))
   )
   (func (;0;) (type $t0) (result funcref)
     ref.null func
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/5.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/5.print
index 74a5f4ec..776b1c50 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/5.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/5.print
@@ -4,8 +4,8 @@
     (type $a2 (;1;) (sub (struct (field i64) (field (ref 0)))))
   )
   (rec
-    (type $b1 (;2;) (sub $a2 (;1;) (struct (field i64) (field (ref 0)) (field i32))))
-    (type $b2 (;3;) (sub $a1 (;0;) (struct (field i32) (field (ref 1)) (field i32))))
-    (type $b3 (;4;) (sub $a2 (;1;) (struct (field i64) (field (ref 3)) (field i32))))
+    (type $b1 (;2;) (sub $a2 (struct (field i64) (field (ref 0)) (field i32))))
+    (type $b2 (;3;) (sub $a1 (struct (field i32) (field (ref 1)) (field i32))))
+    (type $b3 (;4;) (sub $a2 (struct (field i64) (field (ref 3)) (field i32))))
   )
 )
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/50.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/50.print
index 0bfc8e89..baf7bd1f 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/50.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/50.print
@@ -1,10 +1,10 @@
 (module
   (type $t0 (;0;) (sub (func (result funcref))))
   (rec
-    (type $t1 (;1;) (sub $t0 (;0;) (func (result (ref null 1)))))
+    (type $t1 (;1;) (sub $t0 (func (result (ref null 1)))))
   )
   (rec
-    (type $t2 (;2;) (sub $t1 (;1;) (func (result (ref null 2)))))
+    (type $t2 (;2;) (sub $t1 (func (result (ref null 2)))))
   )
   (import "M" "f0" (func (;0;) (type $t0)))
   (import "M" "f1" (func (;1;) (type $t0)))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/58.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/58.print
index ffeff4c8..867caa19 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/58.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/58.print
@@ -4,7 +4,7 @@
     (type (;1;) (struct (field (ref 0))))
   )
   (rec
-    (type $g2 (;2;) (sub $f2 (;0;) (func)))
+    (type $g2 (;2;) (sub $f2 (func)))
     (type (;3;) (struct))
   )
   (func (;0;) (type $g2))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/6.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/6.print
index be7f63f4..b0270453 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/6.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/6.print
@@ -1,8 +1,8 @@
 (module
   (rec
     (type $t1 (;0;) (sub (func (param i32 (ref 2)))))
-    (type $t2 (;1;) (sub $t1 (;0;) (func (param i32 (ref 1)))))
-    (type $t3 (;2;) (sub $t2 (;1;) (func (param i32 (ref 0)))))
+    (type $t2 (;1;) (sub $t1 (func (param i32 (ref 1)))))
+    (type $t3 (;2;) (sub $t2 (func (param i32 (ref 0)))))
   )
   (type (;3;) (func (param (ref 0))))
   (type (;4;) (func (param (ref 1))))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/60.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/60.print
index 57106a6c..0995a3b1 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/60.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/60.print
@@ -4,7 +4,7 @@
     (type (;1;) (struct (field (ref 0))))
   )
   (rec
-    (type $g1 (;2;) (sub $f1 (;0;) (func)))
+    (type $g1 (;2;) (sub $f1 (func)))
     (type (;3;) (struct))
   )
   (import "M3" "g" (func (;0;) (type $g1)))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/61.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/61.print
index 8837d211..dda87e56 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/61.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/61.print
@@ -8,8 +8,8 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g2 (;4;) (sub $f2 (;2;) (func)))
-    (type (;5;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 4)))))
+    (type $g2 (;4;) (sub $f2 (func)))
+    (type (;5;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 4)))))
   )
   (func (;0;) (type $g2))
   (export "g" (func 0))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/63.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/63.print
index 6982effb..3c0aca3f 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/63.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/63.print
@@ -8,8 +8,8 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (import "M4" "g" (func (;0;) (type $g1)))
 )
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/64.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/64.print
index e1436ef6..43ef5273 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/64.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/64.print
@@ -8,7 +8,7 @@
     (type (;3;) (struct (field (ref 0))))
   )
   (rec
-    (type $g2 (;4;) (sub $f2 (;2;) (func)))
+    (type $g2 (;4;) (sub $f2 (func)))
     (type (;5;) (struct))
   )
   (func (;0;) (type $g2))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/67.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/67.print
index f920ca8d..06fdc52d 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/67.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/67.print
@@ -8,7 +8,7 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g (;4;) (sub $f1 (;0;) (func)))
+    (type $g (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (func (;0;) (type $g))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/69.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/69.print
index 22a485ad..fbc88506 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/69.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/69.print
@@ -8,7 +8,7 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g (;4;) (sub $f1 (;0;) (func)))
+    (type $g (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (import "M6" "g" (func (;0;) (type $f1)))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/7.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/7.print
index f868722a..2ce853d1 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/7.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/7.print
@@ -4,10 +4,10 @@
     (type $u1 (;1;) (sub (func (result f32 (ref 0)))))
   )
   (rec
-    (type $t2 (;2;) (sub $t1 (;0;) (func (result i32 (ref 5)))))
-    (type $u2 (;3;) (sub $u1 (;1;) (func (result f32 (ref 4)))))
-    (type $t3 (;4;) (sub $t1 (;0;) (func (result i32 (ref 3)))))
-    (type $u3 (;5;) (sub $u1 (;1;) (func (result f32 (ref 2)))))
+    (type $t2 (;2;) (sub $t1 (func (result i32 (ref 5)))))
+    (type $u2 (;3;) (sub $u1 (func (result f32 (ref 4)))))
+    (type $t3 (;4;) (sub $t1 (func (result i32 (ref 3)))))
+    (type $u3 (;5;) (sub $u1 (func (result f32 (ref 2)))))
   )
   (type (;6;) (func (param (ref 0))))
   (type (;7;) (func (param (ref 2))))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/70.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/70.print
index 4964ecda..7af88e83 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/70.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/70.print
@@ -8,11 +8,11 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g2 (;4;) (sub $f2 (;2;) (func)))
-    (type (;5;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 4)))))
+    (type $g2 (;4;) (sub $f2 (func)))
+    (type (;5;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $h (;6;) (sub $g2 (;4;) (func)))
+    (type $h (;6;) (sub $g2 (func)))
     (type (;7;) (struct))
   )
   (func (;0;) (type $h))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/72.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/72.print
index 40471356..4129dc13 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/72.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/72.print
@@ -8,11 +8,11 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $h (;6;) (sub $g1 (;4;) (func)))
+    (type $h (;6;) (sub $g1 (func)))
     (type (;7;) (struct))
   )
   (import "M7" "h" (func (;0;) (type $f1)))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/73.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/73.print
index 141f5b5a..cafd8cb3 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/73.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/73.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (func (;0;) (type $f11) (result (ref func))
     unreachable
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/75.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/75.print
index 74486efc..2d2f3a4e 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/75.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/75.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (import "M8" "f11" (func (;0;) (type $f11)))
   (import "M8" "f11" (func (;1;) (type $f21)))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/76.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/76.print
index c0cb5514..26773efb 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/76.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/76.print
@@ -1,19 +1,19 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (rec
-    (type $g11 (;4;) (sub $f11 (;0;) (func (result (ref func)))))
-    (type $g12 (;5;) (sub $g11 (;4;) (func (result (ref 4)))))
+    (type $g11 (;4;) (sub $f11 (func (result (ref func)))))
+    (type $g12 (;5;) (sub $g11 (func (result (ref 4)))))
   )
   (rec
-    (type $g21 (;6;) (sub $f21 (;2;) (func (result (ref func)))))
-    (type $g22 (;7;) (sub $g21 (;6;) (func (result (ref 6)))))
+    (type $g21 (;6;) (sub $f21 (func (result (ref func)))))
+    (type $g22 (;7;) (sub $g21 (func (result (ref 6)))))
   )
   (func (;0;) (type $g11) (result (ref func))
     unreachable
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/78.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/78.print
index 0fca36c7..3a8aff62 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/78.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/78.print
@@ -1,19 +1,19 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func (result (ref func)))))
-    (type $f12 (;1;) (sub $f11 (;0;) (func (result (ref 0)))))
+    (type $f12 (;1;) (sub $f11 (func (result (ref 0)))))
   )
   (rec
     (type $f21 (;2;) (sub (func (result (ref func)))))
-    (type $f22 (;3;) (sub $f21 (;2;) (func (result (ref 2)))))
+    (type $f22 (;3;) (sub $f21 (func (result (ref 2)))))
   )
   (rec
-    (type $g11 (;4;) (sub $f11 (;0;) (func (result (ref func)))))
-    (type $g12 (;5;) (sub $g11 (;4;) (func (result (ref 4)))))
+    (type $g11 (;4;) (sub $f11 (func (result (ref func)))))
+    (type $g12 (;5;) (sub $g11 (func (result (ref 4)))))
   )
   (rec
-    (type $g21 (;6;) (sub $f21 (;2;) (func (result (ref func)))))
-    (type $g22 (;7;) (sub $g21 (;6;) (func (result (ref 6)))))
+    (type $g21 (;6;) (sub $f21 (func (result (ref func)))))
+    (type $g22 (;7;) (sub $g21 (func (result (ref 6)))))
   )
   (import "M9" "g11" (func (;0;) (type $f11)))
   (import "M9" "g11" (func (;1;) (type $f21)))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/79.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/79.print
index 4a5b7805..1303cd6d 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/79.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/79.print
@@ -1,11 +1,11 @@
 (module
   (rec
     (type $f11 (;0;) (sub (func)))
-    (type $f12 (;1;) (sub $f11 (;0;) (func)))
+    (type $f12 (;1;) (sub $f11 (func)))
   )
   (rec
     (type $f21 (;2;) (sub (func)))
-    (type $f22 (;3;) (sub $f11 (;0;) (func)))
+    (type $f22 (;3;) (sub $f11 (func)))
   )
   (func (;0;) (type $f21))
   (export "f" (func 0))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/8.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/8.print
index 32a18362..2a9dd915 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/8.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/8.print
@@ -8,11 +8,11 @@
     (type (;3;) (struct (field (ref 2))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
+    (type $g1 (;4;) (sub $f1 (func)))
     (type (;5;) (struct))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
+    (type $g2 (;6;) (sub $f2 (func)))
     (type (;7;) (struct))
   )
   (func $g (;0;) (type $g2))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/82.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/82.print
index 673aa465..198cdbae 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/82.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/82.print
@@ -1,15 +1,15 @@
 (module
   (rec
     (type $f01 (;0;) (sub (func)))
-    (type $f02 (;1;) (sub $f01 (;0;) (func)))
+    (type $f02 (;1;) (sub $f01 (func)))
   )
   (rec
     (type $f11 (;2;) (sub (func)))
-    (type $f12 (;3;) (sub $f01 (;0;) (func)))
+    (type $f12 (;3;) (sub $f01 (func)))
   )
   (rec
     (type $f21 (;4;) (sub (func)))
-    (type $f22 (;5;) (sub $f11 (;2;) (func)))
+    (type $f22 (;5;) (sub $f11 (func)))
   )
   (func (;0;) (type $f21))
   (export "f" (func 0))
diff --git a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/9.print b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/9.print
index 612798a6..20361312 100644
--- a/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/9.print
+++ b/tests/snapshots/testsuite/proposals/gc/type-subtyping.wast/9.print
@@ -8,12 +8,12 @@
     (type $s2 (;3;) (sub (struct (field (ref 2)))))
   )
   (rec
-    (type $g1 (;4;) (sub $f1 (;0;) (func)))
-    (type (;5;) (sub $s1 (;1;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
+    (type $g1 (;4;) (sub $f1 (func)))
+    (type (;5;) (sub $s1 (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4)))))
   )
   (rec
-    (type $g2 (;6;) (sub $f2 (;2;) (func)))
-    (type (;7;) (sub $s2 (;3;) (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
+    (type $g2 (;6;) (sub $f2 (func)))
+    (type (;7;) (sub $s2 (struct (field (ref 0)) (field (ref 2)) (field (ref 0)) (field (ref 2)) (field (ref 6)))))
   )
   (func $g (;0;) (type $g2))
   (global (;0;) (ref 4) ref.func $g)