Repository: bytecodealliance/wasm-tools
Pull request #1281 (2023-11-10 23:13:15)

Enable more GC spec tests 


Patch:
diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs
index 99f9cb73..d285c4f9 100644
--- a/crates/wasmparser/src/validator/core.rs
+++ b/crates/wasmparser/src/validator/core.rs
@@ -287,6 +287,7 @@ impl ModuleState {
                 types,
                 module: &mut self.module,
             },
+            features,
         };
 
         let mut ops = expr.get_operators_reader();
@@ -309,6 +310,7 @@ impl ModuleState {
             ops: OperatorValidator,
             resources: OperatorValidatorResources<'a>,
             order: Order,
+            features: &'a WasmFeatures,
         }
 
         impl VisitConstOperator<'_> {
@@ -316,12 +318,15 @@ impl ModuleState {
                 self.ops.with_resources(&self.resources, self.offset)
             }
 
-            fn validate_extended_const(&mut self) -> Result<()> {
+            fn validate_extended_const(&mut self, op: &str) -> Result<()> {
                 if self.ops.features.extended_const {
                     Ok(())
                 } else {
                     Err(BinaryReaderError::new(
-                        "constant expression required: non-constant operator",
+                        format!(
+                            "constant expression required: non-constant operator: {}",
+                            op
+                        ),
                         self.offset,
                     ))
                 }
@@ -330,7 +335,8 @@ impl ModuleState {
             fn validate_global(&mut self, index: u32) -> Result<()> {
                 let module = &self.resources.module;
                 let global = module.global_at(index, self.offset)?;
-                if index >= module.num_imported_globals {
+
+                if index >= module.num_imported_globals && !self.features.gc {
                     return Err(BinaryReaderError::new(
                         "constant expression required: global.get of locally defined global",
                         self.offset,
@@ -411,27 +417,27 @@ impl ModuleState {
 
             // These are valid const expressions when the extended-const proposal is enabled.
             (@visit $self:ident visit_i32_add) => {{
-                $self.validate_extended_const()?;
+                $self.validate_extended_const("i32.add")?;
                 $self.validator().visit_i32_add()
             }};
             (@visit $self:ident visit_i32_sub) => {{
-                $self.validate_extended_const()?;
+                $self.validate_extended_const("i32.sub")?;
                 $self.validator().visit_i32_sub()
             }};
             (@visit $self:ident visit_i32_mul) => {{
-                $self.validate_extended_const()?;
+                $self.validate_extended_const("i32.mul")?;
                 $self.validator().visit_i32_mul()
             }};
             (@visit $self:ident visit_i64_add) => {{
-                $self.validate_extended_const()?;
+                $self.validate_extended_const("i64.add")?;
                 $self.validator().visit_i64_add()
             }};
             (@visit $self:ident visit_i64_sub) => {{
-                $self.validate_extended_const()?;
+                $self.validate_extended_const("i64.sub")?;
                 $self.validator().visit_i64_sub()
             }};
             (@visit $self:ident visit_i64_mul) => {{
-                $self.validate_extended_const()?;
+                $self.validate_extended_const("i64.mul")?;
                 $self.validator().visit_i64_mul()
             }};
 
@@ -450,7 +456,7 @@ impl ModuleState {
 
             (@visit $self:ident $op:ident $($args:tt)*) => {{
                 Err(BinaryReaderError::new(
-                    "constant expression required: non-constant operator",
+                    format!("constant expression required: non-constant operator: {}", stringify!($op)),
                     $self.offset,
                 ))
             }}
diff --git a/crates/wasmparser/src/validator/types.rs b/crates/wasmparser/src/validator/types.rs
index 6a32cfbe..f774d885 100644
--- a/crates/wasmparser/src/validator/types.rs
+++ b/crates/wasmparser/src/validator/types.rs
@@ -2620,15 +2620,18 @@ impl TypeList {
     /// Is `a == b` or was `a` declared (potentially transitively) to be a
     /// subtype of `b`?
     pub fn id_is_subtype(&self, mut a: CoreTypeId, b: CoreTypeId) -> bool {
-        // TODO: maintain supertype vectors and implement this check in O(1)
-        // instead of O(n) time.
-        while let Some(aa) = self.supertype_of(a) {
-            if aa == b {
+        loop {
+            if a == b {
                 return true;
             }
-            a = aa;
+
+            // TODO: maintain supertype vectors and implement this check in O(1)
+            // instead of O(n) time.
+            a = match self.supertype_of(a) {
+                Some(a) => a,
+                None => return false,
+            };
         }
-        false
     }
 
     /// Like `id_is_subtype` but for `RefType`s.
diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs
index 276b1886..d42b1f71 100644
--- a/crates/wasmprinter/src/lib.rs
+++ b/crates/wasmprinter/src/lib.rs
@@ -753,11 +753,12 @@ impl Printer {
         for ty in parser.into_iter_with_offsets() {
             let (offset, rec_group) = ty?;
             self.newline(offset);
-            if rec_group.types().len() == 1 {
+            if rec_group.is_explicit_rec_group() {
+                self.print_rec(state, offset, rec_group.into_types())?
+            } else {
+                assert_eq!(rec_group.types().len(), 1);
                 let ty = rec_group.into_types().next().unwrap();
                 self.print_type(state, ty)?;
-            } else {
-                self.print_rec(state, offset, rec_group.into_types())?
             }
         }
 


Test patch:
diff --git a/tests/local/gc/subtype-of-self-recursive-type.wast b/tests/local/gc/subtype-of-self-recursive-type.wast
new file mode 100644
index 00000000..abcfe974
--- /dev/null
+++ b/tests/local/gc/subtype-of-self-recursive-type.wast
@@ -0,0 +1,5 @@
+(module
+       (type $t  (sub    (struct (field anyref))))
+  (rec (type $r  (sub $t (struct (field (ref $r))))))
+       (type $t' (sub $r (struct (field (ref $r) i32))))
+)
diff --git a/tests/local/globals.wast b/tests/local/missing-features/globals.wast
similarity index 100%
rename from tests/local/globals.wast
rename to tests/local/missing-features/globals.wast
diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs
index a14896ff..548464e0 100644
--- a/tests/roundtrip.rs
+++ b/tests/roundtrip.rs
@@ -35,6 +35,8 @@ use wast::parser::ParseBuffer;
 use wast::{parser, QuoteWat, Wast, WastDirective, Wat};
 
 fn main() {
+    env_logger::init();
+
     let tests = find_tests();
     let filter = std::env::args().nth(1);
     let bless = std::env::var_os("BLESS").is_some();
@@ -168,7 +170,6 @@ fn skip_test(test: &Path, contents: &[u8]) -> bool {
 fn skip_validation(test: &Path) -> bool {
     let broken = &[
         "gc/gc-array.wat",
-        "gc/gc-rec-sub.wat",
         "gc/gc-struct.wat",
         "/proposals/gc/array.wast",
         "/proposals/gc/array_copy.wast",
@@ -178,8 +179,6 @@ fn skip_validation(test: &Path) -> bool {
         "/proposals/gc/binary-gc.wast",
         "/proposals/gc/br_on_cast.wast",
         "/proposals/gc/br_on_cast_fail.wast",
-        "/proposals/gc/data.wast",
-        "/proposals/gc/elem.wast",
         "/proposals/gc/extern.wast",
         "/proposals/gc/global.wast",
         "/proposals/gc/i31.wast",
@@ -187,8 +186,6 @@ fn skip_validation(test: &Path) -> bool {
         "/proposals/gc/ref_eq.wast",
         "/proposals/gc/ref_test.wast",
         "/proposals/gc/struct.wast",
-        "/proposals/gc/type-equivalence.wast",
-        "/proposals/gc/type-rec.wast",
         "/proposals/gc/type-subtyping.wast",
         "/exnref/exnref.wast",
         "/exnref/throw_ref.wast",
@@ -519,6 +516,19 @@ impl TestState {
             return Ok(());
         }
 
+        if log::log_enabled!(log::Level::Debug) {
+            static COUNTER: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
+            let i = COUNTER.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
+
+            let expected_path = format!("expected{i}.wasm");
+            log::debug!("Writing expected Wasm to: {expected_path}");
+            let _ = std::fs::write(expected_path, expected);
+
+            let actual_path = format!("actual{i}.wasm");
+            log::debug!("Writing actual Wasm to: {actual_path}");
+            let _ = std::fs::write(actual_path, actual);
+        }
+
         let difference = actual
             .iter()
             .enumerate()
@@ -569,7 +579,11 @@ impl TestState {
                     msg.push_str(&format!("+ {}\n", actual_state));
                     differences += 1;
                 }
+            } else {
+                msg.push_str("\nfailed to dump expected");
             }
+        } else {
+            msg.push_str("\nfailed to dump actual");
         }
 
         bail!("{}", msg);
@@ -664,6 +678,7 @@ impl TestState {
                 _ => {}
             }
         }
+        log::debug!("features for {} = {features:#?}", test.display());
         Validator::new_with_features(features)
     }
 
diff --git a/tests/snapshots/local/gc/gc-rec-sub.wat.print b/tests/snapshots/local/gc/gc-rec-sub.wat.print
new file mode 100644
index 00000000..9bce1a12
--- /dev/null
+++ b/tests/snapshots/local/gc/gc-rec-sub.wat.print
@@ -0,0 +1,48 @@
+(module
+  (rec
+    (type (;0;) (func))
+  )
+  (rec
+    (type (;1;) (func))
+    (type (;2;) (func))
+  )
+  (rec
+    (type (;3;) (struct))
+  )
+  (rec
+    (type (;4;) (struct))
+    (type (;5;) (struct))
+  )
+  (rec
+    (type (;6;) (array i32))
+  )
+  (rec
+    (type (;7;) (array i32))
+    (type (;8;) (array i32))
+  )
+  (rec
+    (type (;9;) (func))
+    (type (;10;) (struct))
+    (type (;11;) (array i32))
+  )
+  (rec
+    (type $a (;12;) (sub (func)))
+    (type (;13;) (sub $a (;12;) (func)))
+  )
+  (rec
+    (type (;14;) (sub $a (;12;) (func)))
+  )
+  (rec
+    (type (;15;) (sub final $a (;12;) (func)))
+  )
+  (type (;16;) (sub $a (;12;) (func)))
+  (rec
+    (type $t1 (;17;) (struct (field (ref 18))))
+    (type $t2 (;18;) (sub (struct (field (ref 17)))))
+  )
+  (rec
+    (type $t3 (;19;) (struct (field (ref 20))))
+    (type $t4 (;20;) (sub $t2 (;18;) (struct (field (ref 19)))))
+  )
+  (rec)
+)
\ 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
new file mode 100644
index 00000000..1adacc16
--- /dev/null
+++ b/tests/snapshots/local/gc/subtype-of-self-recursive-type.wast/0.print
@@ -0,0 +1,7 @@
+(module
+  (type $t (;0;) (sub (struct (field anyref))))
+  (rec
+    (type $r (;1;) (sub $t (;0;) (struct (field (ref 1)))))
+  )
+  (type $t' (;2;) (sub $r (;1;) (struct (field (ref 1)) (field i32))))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/0.print b/tests/snapshots/testsuite/proposals/gc/data.wast/0.print
new file mode 100644
index 00000000..76dcc35a
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/0.print
@@ -0,0 +1,27 @@
+(module
+  (memory $m (;0;) 1)
+  (data (;0;) (i32.const 0) "")
+  (data (;1;) (i32.const 1) "abcd")
+  (data (;2;) (i32.const 0) "")
+  (data (;3;) (i32.const 0) "abc")
+  (data (;4;) (i32.const 0) "")
+  (data (;5;) (i32.const 1) "abcd")
+  (data (;6;) (i32.const 0) "")
+  (data (;7;) (i32.const 0) "abc")
+  (data (;8;) (i32.const 0) "")
+  (data (;9;) (i32.const 1) "abcd")
+  (data (;10;) (i32.const 0) "")
+  (data (;11;) (i32.const 0) "abc")
+  (data $d1 (;12;) (i32.const 0) "")
+  (data $d2 (;13;) (i32.const 1) "abcd")
+  (data $d3 (;14;) (i32.const 0) "")
+  (data $d4 (;15;) (i32.const 0) "abc")
+  (data $d5 (;16;) (i32.const 0) "")
+  (data $d6 (;17;) (i32.const 1) "abcd")
+  (data $d7 (;18;) (i32.const 0) "")
+  (data $d8 (;19;) (i32.const 0) "abc")
+  (data $d9 (;20;) (i32.const 0) "")
+  (data $d10 (;21;) (i32.const 1) "abcd")
+  (data $d11 (;22;) (i32.const 0) "")
+  (data $d12 (;23;) (i32.const 0) "abc")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/1.print b/tests/snapshots/testsuite/proposals/gc/data.wast/1.print
new file mode 100644
index 00000000..cc1e75fe
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/1.print
@@ -0,0 +1,4 @@
+(module
+  (memory (;0;) 1)
+  (data (;0;) (i32.const 0) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/10.print b/tests/snapshots/testsuite/proposals/gc/data.wast/10.print
new file mode 100644
index 00000000..e6e76ade
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/10.print
@@ -0,0 +1,5 @@
+(module
+  (memory (;0;) 1)
+  (global $g (;0;) i32 i32.const 0)
+  (data (;0;) (global.get $g) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/11.print b/tests/snapshots/testsuite/proposals/gc/data.wast/11.print
new file mode 100644
index 00000000..0474fc65
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/11.print
@@ -0,0 +1,5 @@
+(module
+  (memory (;0;) 1)
+  (data (;0;) (i32.const 0) "a")
+  (data (;1;) (i32.const 65535) "b")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/12.print b/tests/snapshots/testsuite/proposals/gc/data.wast/12.print
new file mode 100644
index 00000000..c7cfbb07
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/12.print
@@ -0,0 +1,5 @@
+(module
+  (import "spectest" "memory" (memory (;0;) 1))
+  (data (;0;) (i32.const 0) "a")
+  (data (;1;) (i32.const 65535) "b")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/13.print b/tests/snapshots/testsuite/proposals/gc/data.wast/13.print
new file mode 100644
index 00000000..0d6dc721
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/13.print
@@ -0,0 +1,4 @@
+(module
+  (memory (;0;) 2)
+  (data (;0;) (i32.const 131071) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/14.print b/tests/snapshots/testsuite/proposals/gc/data.wast/14.print
new file mode 100644
index 00000000..1303df08
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/14.print
@@ -0,0 +1,4 @@
+(module
+  (memory (;0;) 0)
+  (data (;0;) (i32.const 0) "")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/15.print b/tests/snapshots/testsuite/proposals/gc/data.wast/15.print
new file mode 100644
index 00000000..bb79a2b2
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/15.print
@@ -0,0 +1,4 @@
+(module
+  (import "spectest" "memory" (memory (;0;) 0))
+  (data (;0;) (i32.const 0) "")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/16.print b/tests/snapshots/testsuite/proposals/gc/data.wast/16.print
new file mode 100644
index 00000000..70d5011a
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/16.print
@@ -0,0 +1,4 @@
+(module
+  (memory (;0;) 0 0)
+  (data (;0;) (i32.const 0) "")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/17.print b/tests/snapshots/testsuite/proposals/gc/data.wast/17.print
new file mode 100644
index 00000000..2f4c3a8d
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/17.print
@@ -0,0 +1,4 @@
+(module
+  (memory (;0;) 1)
+  (data (;0;) (i32.const 65536) "")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/18.print b/tests/snapshots/testsuite/proposals/gc/data.wast/18.print
new file mode 100644
index 00000000..1303df08
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/18.print
@@ -0,0 +1,4 @@
+(module
+  (memory (;0;) 0)
+  (data (;0;) (i32.const 0) "")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/19.print b/tests/snapshots/testsuite/proposals/gc/data.wast/19.print
new file mode 100644
index 00000000..bb79a2b2
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/19.print
@@ -0,0 +1,4 @@
+(module
+  (import "spectest" "memory" (memory (;0;) 0))
+  (data (;0;) (i32.const 0) "")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/2.print b/tests/snapshots/testsuite/proposals/gc/data.wast/2.print
new file mode 100644
index 00000000..481aec56
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/2.print
@@ -0,0 +1,4 @@
+(module
+  (import "spectest" "memory" (memory (;0;) 1))
+  (data (;0;) (i32.const 0) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/20.print b/tests/snapshots/testsuite/proposals/gc/data.wast/20.print
new file mode 100644
index 00000000..70d5011a
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/20.print
@@ -0,0 +1,4 @@
+(module
+  (memory (;0;) 0 0)
+  (data (;0;) (i32.const 0) "")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/21.print b/tests/snapshots/testsuite/proposals/gc/data.wast/21.print
new file mode 100644
index 00000000..4e08a2a6
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/21.print
@@ -0,0 +1,4 @@
+(module
+  (import "spectest" "memory" (memory (;0;) 0))
+  (data (;0;) (i32.const 0) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/22.print b/tests/snapshots/testsuite/proposals/gc/data.wast/22.print
new file mode 100644
index 00000000..376eeb67
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/22.print
@@ -0,0 +1,4 @@
+(module
+  (import "spectest" "memory" (memory (;0;) 0 3))
+  (data (;0;) (i32.const 0) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/23.print b/tests/snapshots/testsuite/proposals/gc/data.wast/23.print
new file mode 100644
index 00000000..18183a14
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/23.print
@@ -0,0 +1,5 @@
+(module
+  (import "spectest" "global_i32" (global (;0;) i32))
+  (import "spectest" "memory" (memory (;0;) 0))
+  (data (;0;) (global.get 0) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/24.print b/tests/snapshots/testsuite/proposals/gc/data.wast/24.print
new file mode 100644
index 00000000..86be16f7
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/24.print
@@ -0,0 +1,5 @@
+(module
+  (import "spectest" "global_i32" (global (;0;) i32))
+  (import "spectest" "memory" (memory (;0;) 0 3))
+  (data (;0;) (global.get 0) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/25.print b/tests/snapshots/testsuite/proposals/gc/data.wast/25.print
new file mode 100644
index 00000000..6cb38d09
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/25.print
@@ -0,0 +1,4 @@
+(module
+  (import "spectest" "memory" (memory (;0;) 0))
+  (data (;0;) (i32.const 1) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/26.print b/tests/snapshots/testsuite/proposals/gc/data.wast/26.print
new file mode 100644
index 00000000..42df962f
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/26.print
@@ -0,0 +1,4 @@
+(module
+  (import "spectest" "memory" (memory (;0;) 0 3))
+  (data (;0;) (i32.const 1) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/3.print b/tests/snapshots/testsuite/proposals/gc/data.wast/3.print
new file mode 100644
index 00000000..fbef21b7
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/3.print
@@ -0,0 +1,8 @@
+(module
+  (memory (;0;) 1)
+  (data (;0;) (i32.const 0) "a")
+  (data (;1;) (i32.const 3) "b")
+  (data (;2;) (i32.const 100) "cde")
+  (data (;3;) (i32.const 5) "x")
+  (data (;4;) (i32.const 3) "c")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/4.print b/tests/snapshots/testsuite/proposals/gc/data.wast/4.print
new file mode 100644
index 00000000..bb6a67d9
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/4.print
@@ -0,0 +1,9 @@
+(module
+  (import "spectest" "memory" (memory (;0;) 1))
+  (data (;0;) (i32.const 0) "a")
+  (data (;1;) (i32.const 1) "b")
+  (data (;2;) (i32.const 2) "cde")
+  (data (;3;) (i32.const 3) "f")
+  (data (;4;) (i32.const 2) "g")
+  (data (;5;) (i32.const 1) "h")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/5.print b/tests/snapshots/testsuite/proposals/gc/data.wast/5.print
new file mode 100644
index 00000000..ee7a8e6f
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/5.print
@@ -0,0 +1,5 @@
+(module
+  (import "spectest" "global_i32" (global (;0;) i32))
+  (memory (;0;) 1)
+  (data (;0;) (global.get 0) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/6.print b/tests/snapshots/testsuite/proposals/gc/data.wast/6.print
new file mode 100644
index 00000000..55a464f0
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/6.print
@@ -0,0 +1,5 @@
+(module
+  (import "spectest" "global_i32" (global (;0;) i32))
+  (import "spectest" "memory" (memory (;0;) 1))
+  (data (;0;) (global.get 0) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/7.print b/tests/snapshots/testsuite/proposals/gc/data.wast/7.print
new file mode 100644
index 00000000..cc48f688
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/7.print
@@ -0,0 +1,5 @@
+(module
+  (import "spectest" "global_i32" (global $g (;0;) i32))
+  (memory (;0;) 1)
+  (data (;0;) (global.get $g) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/8.print b/tests/snapshots/testsuite/proposals/gc/data.wast/8.print
new file mode 100644
index 00000000..9baa7ce1
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/8.print
@@ -0,0 +1,5 @@
+(module
+  (import "spectest" "global_i32" (global $g (;0;) i32))
+  (import "spectest" "memory" (memory (;0;) 1))
+  (data (;0;) (global.get $g) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/data.wast/9.print b/tests/snapshots/testsuite/proposals/gc/data.wast/9.print
new file mode 100644
index 00000000..ec5c12d5
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/data.wast/9.print
@@ -0,0 +1,5 @@
+(module
+  (memory (;0;) 1)
+  (global (;0;) i32 i32.const 0)
+  (data (;0;) (global.get 0) "a")
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/0.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/0.print
new file mode 100644
index 00000000..f5b37aa0
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/0.print
@@ -0,0 +1,67 @@
+(module
+  (type (;0;) (func))
+  (func $f (;0;) (type 0))
+  (func $g (;1;) (type 0))
+  (table $t (;0;) 10 funcref)
+  (elem (;0;) funcref)
+  (elem (;1;) funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g))
+  (elem (;2;) func)
+  (elem (;3;) func $f $f $g $g)
+  (elem $p1 (;4;) funcref)
+  (elem $p2 (;5;) funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g))
+  (elem $p3 (;6;) func)
+  (elem $p4 (;7;) func $f $f $g $g)
+  (elem (;8;) (i32.const 0) funcref)
+  (elem (;9;) (i32.const 0) funcref (ref.func $f) (ref.null func))
+  (elem (;10;) (i32.const 0) func)
+  (elem (;11;) (i32.const 0) func $f $g)
+  (elem (;12;) (i32.const 0) funcref)
+  (elem (;13;) (i32.const 0) func $f $g)
+  (elem (;14;) (i32.const 0) func)
+  (elem (;15;) (i32.const 0) func $f $f)
+  (elem (;16;) (i32.const 0) func)
+  (elem (;17;) (i32.const 0) func $f $f)
+  (elem (;18;) (i32.const 0) func)
+  (elem (;19;) (i32.const 0) func $f $f)
+  (elem (;20;) (i32.const 0) func)
+  (elem (;21;) (i32.const 0) func $f $f)
+  (elem (;22;) (i32.const 0) func)
+  (elem (;23;) (i32.const 0) funcref (ref.func $f) (ref.null func))
+  (elem (;24;) (i32.const 0) func $f $f)
+  (elem (;25;) (i32.const 0) func $f $f)
+  (elem (;26;) (i32.const 0) func)
+  (elem (;27;) (i32.const 0) funcref (ref.func $f) (ref.null func))
+  (elem (;28;) (i32.const 0) func $f $f)
+  (elem (;29;) (i32.const 0) func $f $f)
+  (elem (;30;) (i32.const 0) funcref (ref.func $f) (ref.null func))
+  (elem $a1 (;31;) (i32.const 0) funcref)
+  (elem $a2 (;32;) (i32.const 0) funcref (ref.func $f) (ref.null func))
+  (elem $a3 (;33;) (i32.const 0) func)
+  (elem $a4 (;34;) (i32.const 0) func $f $g)
+  (elem $a9 (;35;) (i32.const 0) funcref)
+  (elem $a10 (;36;) (i32.const 0) func $f $g)
+  (elem $a11 (;37;) (i32.const 0) func)
+  (elem $a12 (;38;) (i32.const 0) func $f $f)
+  (elem $a13 (;39;) (i32.const 0) func)
+  (elem $a14 (;40;) (i32.const 0) func $f $f)
+  (elem $a15 (;41;) (i32.const 0) func)
+  (elem $a16 (;42;) (i32.const 0) func $f $f)
+  (elem $a17 (;43;) (i32.const 0) func)
+  (elem $a18 (;44;) (i32.const 0) func $f $f)
+  (elem $a19 (;45;) (i32.const 0) func)
+  (elem $a20 (;46;) (i32.const 0) funcref (ref.func $f) (ref.null func))
+  (elem $a21 (;47;) (i32.const 0) func $f $f)
+  (elem $a22 (;48;) (i32.const 0) func $f $f)
+  (elem $a23 (;49;) (i32.const 0) func)
+  (elem $a24 (;50;) (i32.const 0) funcref (ref.func $f) (ref.null func))
+  (elem $a25 (;51;) (i32.const 0) func $f $f)
+  (elem $a26 (;52;) (i32.const 0) func $f $f)
+  (elem (;53;) declare funcref)
+  (elem (;54;) declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g))
+  (elem (;55;) declare func)
+  (elem (;56;) declare func $f $f $g $g)
+  (elem $d1 (;57;) declare funcref)
+  (elem $d2 (;58;) declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g))
+  (elem $d3 (;59;) declare func)
+  (elem $d4 (;60;) declare func $f $f $g $g)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/1.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/1.print
new file mode 100644
index 00000000..609acc4a
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/1.print
@@ -0,0 +1,7 @@
+(module
+  (type (;0;) (func))
+  (func $f (;0;) (type 0))
+  (func $g (;1;) (type 0))
+  (table $t (;0;) 3 3 funcref)
+  (elem (;0;) (i32.const 0) funcref (ref.func $f) (ref.null func) (ref.func $g))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/12.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/12.print
new file mode 100644
index 00000000..c20a9842
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/12.print
@@ -0,0 +1,22 @@
+(module
+  (type $out-i32 (;0;) (func (result i32)))
+  (func $const-i32-a (;0;) (type $out-i32) (result i32)
+    i32.const 65
+  )
+  (func $const-i32-b (;1;) (type $out-i32) (result i32)
+    i32.const 66
+  )
+  (func (;2;) (type $out-i32) (result i32)
+    i32.const 7
+    call_indirect (type $out-i32)
+  )
+  (func (;3;) (type $out-i32) (result i32)
+    i32.const 9
+    call_indirect (type $out-i32)
+  )
+  (table (;0;) 11 funcref)
+  (export "call-7" (func 2))
+  (export "call-9" (func 3))
+  (elem (;0;) (i32.const 6) funcref (ref.null func) (ref.func $const-i32-a))
+  (elem (;1;) (i32.const 9) funcref (ref.func $const-i32-b) (ref.null func))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/15.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/15.print
new file mode 100644
index 00000000..a8c6af53
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/15.print
@@ -0,0 +1,7 @@
+(module
+  (type (;0;) (func))
+  (func $f (;0;) (type 0))
+  (table (;0;) 1 funcref)
+  (global (;0;) i32 i32.const 0)
+  (elem (;0;) (global.get 0) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/16.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/16.print
new file mode 100644
index 00000000..0717ede7
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/16.print
@@ -0,0 +1,7 @@
+(module
+  (type (;0;) (func))
+  (func $f (;0;) (type 0))
+  (table (;0;) 1 funcref)
+  (global $g (;0;) i32 i32.const 0)
+  (elem (;0;) (global.get $g) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/17.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/17.print
new file mode 100644
index 00000000..59834e5a
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/17.print
@@ -0,0 +1,6 @@
+(module
+  (type (;0;) (func))
+  (func $f (;0;) (type 0))
+  (table (;0;) 10 funcref)
+  (elem (;0;) (i32.const 9) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/18.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/18.print
new file mode 100644
index 00000000..6e685d7b
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/18.print
@@ -0,0 +1,6 @@
+(module
+  (type (;0;) (func))
+  (import "spectest" "table" (table (;0;) 10 funcref))
+  (func $f (;0;) (type 0))
+  (elem (;0;) (i32.const 9) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/19.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/19.print
new file mode 100644
index 00000000..3a1c6fc5
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/19.print
@@ -0,0 +1,4 @@
+(module
+  (table (;0;) 0 funcref)
+  (elem (;0;) (i32.const 0) func)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/2.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/2.print
new file mode 100644
index 00000000..75850d88
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/2.print
@@ -0,0 +1,7 @@
+(module
+  (type (;0;) (func))
+  (func $f (;0;) (type 0))
+  (func $g (;1;) (type 0))
+  (table $t (;0;) 10 (ref func) ref.func $f)
+  (elem (;0;) (i32.const 3) func $g)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/20.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/20.print
new file mode 100644
index 00000000..b890117b
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/20.print
@@ -0,0 +1,4 @@
+(module
+  (import "spectest" "table" (table (;0;) 0 funcref))
+  (elem (;0;) (i32.const 0) func)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/21.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/21.print
new file mode 100644
index 00000000..6dd56282
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/21.print
@@ -0,0 +1,4 @@
+(module
+  (table (;0;) 0 0 funcref)
+  (elem (;0;) (i32.const 0) func)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/22.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/22.print
new file mode 100644
index 00000000..9cdf4a45
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/22.print
@@ -0,0 +1,4 @@
+(module
+  (table (;0;) 20 funcref)
+  (elem (;0;) (i32.const 20) func)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/23.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/23.print
new file mode 100644
index 00000000..fdbf02b7
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/23.print
@@ -0,0 +1,6 @@
+(module
+  (type (;0;) (func))
+  (import "spectest" "table" (table (;0;) 0 funcref))
+  (func $f (;0;) (type 0))
+  (elem (;0;) (i32.const 0) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/24.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/24.print
new file mode 100644
index 00000000..9a7e48ca
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/24.print
@@ -0,0 +1,6 @@
+(module
+  (type (;0;) (func))
+  (import "spectest" "table" (table (;0;) 0 100 funcref))
+  (func $f (;0;) (type 0))
+  (elem (;0;) (i32.const 0) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/25.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/25.print
new file mode 100644
index 00000000..8e7e87ee
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/25.print
@@ -0,0 +1,6 @@
+(module
+  (type (;0;) (func))
+  (import "spectest" "table" (table (;0;) 0 funcref))
+  (func $f (;0;) (type 0))
+  (elem (;0;) (i32.const 1) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/26.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/26.print
new file mode 100644
index 00000000..8e00e00f
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/26.print
@@ -0,0 +1,6 @@
+(module
+  (type (;0;) (func))
+  (import "spectest" "table" (table (;0;) 0 30 funcref))
+  (func $f (;0;) (type 0))
+  (elem (;0;) (i32.const 1) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/3.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/3.print
new file mode 100644
index 00000000..2da39bb2
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/3.print
@@ -0,0 +1,6 @@
+(module
+  (type (;0;) (func))
+  (func $f (;0;) (type 0))
+  (table (;0;) 10 funcref)
+  (elem (;0;) (i32.const 0) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/39.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/39.print
new file mode 100644
index 00000000..f553de71
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/39.print
@@ -0,0 +1,13 @@
+(module
+  (type (;0;) (func))
+  (func $f (;0;) (type 0))
+  (func (;1;) (type 0)
+    i32.const 0
+    i32.const 0
+    i32.const 1
+    table.init $e
+  )
+  (table (;0;) 10 funcref)
+  (export "init" (func 1))
+  (elem $e (;0;) (i32.const 0) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/4.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/4.print
new file mode 100644
index 00000000..9fbc90ac
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/4.print
@@ -0,0 +1,6 @@
+(module
+  (type (;0;) (func))
+  (import "spectest" "table" (table (;0;) 10 funcref))
+  (func $f (;0;) (type 0))
+  (elem (;0;) (i32.const 0) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/41.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/41.print
new file mode 100644
index 00000000..0a8dfffa
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/41.print
@@ -0,0 +1,13 @@
+(module
+  (type (;0;) (func))
+  (func $f (;0;) (type 0))
+  (func (;1;) (type 0)
+    i32.const 0
+    i32.const 0
+    i32.const 1
+    table.init $e
+  )
+  (table (;0;) 10 funcref)
+  (export "init" (func 1))
+  (elem $e (;0;) declare func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/5.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/5.print
new file mode 100644
index 00000000..fdf2793a
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/5.print
@@ -0,0 +1,10 @@
+(module
+  (type (;0;) (func))
+  (func $f (;0;) (type 0))
+  (table (;0;) 10 funcref)
+  (elem (;0;) (i32.const 0) func $f)
+  (elem (;1;) (i32.const 3) func $f)
+  (elem (;2;) (i32.const 7) func $f)
+  (elem (;3;) (i32.const 5) func $f)
+  (elem (;4;) (i32.const 3) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/6.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/6.print
new file mode 100644
index 00000000..2c9c937e
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/6.print
@@ -0,0 +1,10 @@
+(module
+  (type (;0;) (func))
+  (import "spectest" "table" (table (;0;) 10 funcref))
+  (func $f (;0;) (type 0))
+  (elem (;0;) (i32.const 9) func $f)
+  (elem (;1;) (i32.const 3) func $f)
+  (elem (;2;) (i32.const 7) func $f)
+  (elem (;3;) (i32.const 3) func $f)
+  (elem (;4;) (i32.const 5) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/64.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/64.print
new file mode 100644
index 00000000..6ad9b0b3
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/64.print
@@ -0,0 +1,17 @@
+(module
+  (type $out-i32 (;0;) (func (result i32)))
+  (func $const-i32-a (;0;) (type $out-i32) (result i32)
+    i32.const 65
+  )
+  (func $const-i32-b (;1;) (type $out-i32) (result i32)
+    i32.const 66
+  )
+  (func (;2;) (type $out-i32) (result i32)
+    i32.const 9
+    call_indirect (type $out-i32)
+  )
+  (table (;0;) 10 funcref)
+  (export "call-overwritten" (func 2))
+  (elem (;0;) (i32.const 9) func $const-i32-a)
+  (elem (;1;) (i32.const 9) func $const-i32-b)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/66.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/66.print
new file mode 100644
index 00000000..9e872c44
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/66.print
@@ -0,0 +1,17 @@
+(module
+  (type $out-i32 (;0;) (func (result i32)))
+  (import "spectest" "table" (table (;0;) 10 funcref))
+  (func $const-i32-a (;0;) (type $out-i32) (result i32)
+    i32.const 65
+  )
+  (func $const-i32-b (;1;) (type $out-i32) (result i32)
+    i32.const 66
+  )
+  (func (;2;) (type $out-i32) (result i32)
+    i32.const 9
+    call_indirect (type $out-i32)
+  )
+  (export "call-overwritten-element" (func 2))
+  (elem (;0;) (i32.const 9) func $const-i32-a)
+  (elem (;1;) (i32.const 9) func $const-i32-b)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/68.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/68.print
new file mode 100644
index 00000000..a7fafae0
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/68.print
@@ -0,0 +1,28 @@
+(module $module1
+  (type $out-i32 (;0;) (func (result i32)))
+  (func $const-i32-a (;0;) (type $out-i32) (result i32)
+    i32.const 65
+  )
+  (func $const-i32-b (;1;) (type $out-i32) (result i32)
+    i32.const 66
+  )
+  (func (;2;) (type $out-i32) (result i32)
+    i32.const 7
+    call_indirect (type $out-i32)
+  )
+  (func (;3;) (type $out-i32) (result i32)
+    i32.const 8
+    call_indirect (type $out-i32)
+  )
+  (func (;4;) (type $out-i32) (result i32)
+    i32.const 9
+    call_indirect (type $out-i32)
+  )
+  (table (;0;) 10 funcref)
+  (export "shared-table" (table 0))
+  (export "call-7" (func 2))
+  (export "call-8" (func 3))
+  (export "call-9" (func 4))
+  (elem (;0;) (i32.const 8) func $const-i32-a)
+  (elem (;1;) (i32.const 9) func $const-i32-b)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/7.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/7.print
new file mode 100644
index 00000000..ba9ed82c
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/7.print
@@ -0,0 +1,7 @@
+(module
+  (type (;0;) (func))
+  (import "spectest" "global_i32" (global (;0;) i32))
+  (func $f (;0;) (type 0))
+  (table (;0;) 1000 funcref)
+  (elem (;0;) (global.get 0) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/73.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/73.print
new file mode 100644
index 00000000..27cf2472
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/73.print
@@ -0,0 +1,12 @@
+(module $module2
+  (type $out-i32 (;0;) (func (result i32)))
+  (import "module1" "shared-table" (table (;0;) 10 funcref))
+  (func $const-i32-c (;0;) (type $out-i32) (result i32)
+    i32.const 67
+  )
+  (func $const-i32-d (;1;) (type $out-i32) (result i32)
+    i32.const 68
+  )
+  (elem (;0;) (i32.const 7) func $const-i32-c)
+  (elem (;1;) (i32.const 8) func $const-i32-d)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/77.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/77.print
new file mode 100644
index 00000000..e0ef8f74
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/77.print
@@ -0,0 +1,12 @@
+(module $module3
+  (type $out-i32 (;0;) (func (result i32)))
+  (import "module1" "shared-table" (table (;0;) 10 funcref))
+  (func $const-i32-e (;0;) (type $out-i32) (result i32)
+    i32.const 69
+  )
+  (func $const-i32-f (;1;) (type $out-i32) (result i32)
+    i32.const 70
+  )
+  (elem (;0;) (i32.const 8) func $const-i32-e)
+  (elem (;1;) (i32.const 9) func $const-i32-f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/8.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/8.print
new file mode 100644
index 00000000..83d7347f
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/8.print
@@ -0,0 +1,7 @@
+(module
+  (type (;0;) (func))
+  (import "spectest" "global_i32" (global $g (;0;) i32))
+  (func $f (;0;) (type 0))
+  (table (;0;) 1000 funcref)
+  (elem (;0;) (global.get $g) func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/85.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/85.print
new file mode 100644
index 00000000..b1267707
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/85.print
@@ -0,0 +1,17 @@
+(module $m
+  (type (;0;) (func (param i32) (result externref)))
+  (type (;1;) (func (param i32 externref)))
+  (func (;0;) (type 0) (param $i i32) (result externref)
+    local.get $i
+    table.get $t
+  )
+  (func (;1;) (type 1) (param $i i32) (param $x externref)
+    local.get $i
+    local.get $x
+    table.set $t
+  )
+  (table $t (;0;) 2 externref)
+  (export "table" (table $t))
+  (export "get" (func 0))
+  (export "set" (func 1))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/9.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/9.print
new file mode 100644
index 00000000..6bb8d5e6
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/9.print
@@ -0,0 +1,22 @@
+(module
+  (type $out-i32 (;0;) (func (result i32)))
+  (func $const-i32-a (;0;) (type $out-i32) (result i32)
+    i32.const 65
+  )
+  (func $const-i32-b (;1;) (type $out-i32) (result i32)
+    i32.const 66
+  )
+  (func (;2;) (type $out-i32) (result i32)
+    i32.const 7
+    call_indirect (type $out-i32)
+  )
+  (func (;3;) (type $out-i32) (result i32)
+    i32.const 9
+    call_indirect (type $out-i32)
+  )
+  (table (;0;) 10 funcref)
+  (export "call-7" (func 2))
+  (export "call-9" (func 3))
+  (elem (;0;) (i32.const 7) func $const-i32-a)
+  (elem (;1;) (i32.const 9) func $const-i32-b)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/93.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/93.print
new file mode 100644
index 00000000..c6a336d9
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/93.print
@@ -0,0 +1,4 @@
+(module
+  (import "exporter" "table" (table $t (;0;) 2 externref))
+  (elem (;0;) (i32.const 0) externref (ref.null extern))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/96.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/96.print
new file mode 100644
index 00000000..d2623e77
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/96.print
@@ -0,0 +1,8 @@
+(module $module4
+  (type (;0;) (func (result i32)))
+  (func (;0;) (type 0) (result i32)
+    i32.const 42
+  )
+  (global (;0;) funcref ref.func 0)
+  (export "f" (global 0))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/elem.wast/98.print b/tests/snapshots/testsuite/proposals/gc/elem.wast/98.print
new file mode 100644
index 00000000..bd279c1b
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/elem.wast/98.print
@@ -0,0 +1,11 @@
+(module
+  (type $out-i32 (;0;) (func (result i32)))
+  (import "module4" "f" (global (;0;) funcref))
+  (func (;0;) (type $out-i32) (result i32)
+    i32.const 0
+    call_indirect (type $out-i32)
+  )
+  (table (;0;) 10 funcref)
+  (export "call_imported_elem" (func 0))
+  (elem (;0;) (i32.const 0) funcref (global.get 0))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/0.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/0.print
new file mode 100644
index 00000000..e6e986b4
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/0.print
@@ -0,0 +1,14 @@
+(module
+  (type $t1 (;0;) (func (param f32 f32) (result f32)))
+  (type $t2 (;1;) (func (param f32 f32) (result f32)))
+  (type (;2;) (func (param (ref 0))))
+  (type (;3;) (func (param (ref 1))))
+  (func $f1 (;0;) (type 2) (param $r (ref 0))
+    local.get $r
+    call $f2
+  )
+  (func $f2 (;1;) (type 3) (param $r (ref 1))
+    local.get $r
+    call $f1
+  )
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/1.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/1.print
new file mode 100644
index 00000000..4677912b
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/1.print
@@ -0,0 +1,17 @@
+(module
+  (type $s0 (;0;) (func (param i32) (result f32)))
+  (type $s1 (;1;) (func (param i32 (ref 0)) (result (ref 0))))
+  (type $s2 (;2;) (func (param i32 (ref 0)) (result (ref 0))))
+  (type $t1 (;3;) (func (param (ref 1)) (result (ref 2))))
+  (type $t2 (;4;) (func (param (ref 2)) (result (ref 1))))
+  (type (;5;) (func (param (ref 3))))
+  (type (;6;) (func (param (ref 4))))
+  (func $f1 (;0;) (type 5) (param $r (ref 3))
+    local.get $r
+    call $f2
+  )
+  (func $f2 (;1;) (type 6) (param $r (ref 4))
+    local.get $r
+    call $f1
+  )
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/10.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/10.print
new file mode 100644
index 00000000..9bc37186
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/10.print
@@ -0,0 +1,53 @@
+(module
+  (rec
+    (type $t1 (;0;) (func (result (ref null 0))))
+  )
+  (rec
+    (type $t2 (;1;) (func (result (ref null 1))))
+  )
+  (type (;2;) (func))
+  (func $f1 (;0;) (type $t1) (result (ref null 0))
+    ref.null 0
+  )
+  (func $f2 (;1;) (type $t2) (result (ref null 1))
+    ref.null 1
+  )
+  (func (;2;) (type 2)
+    block (result (ref null 0)) ;; label = @1
+      i32.const 0
+      call_indirect (type $t1)
+    end
+    block (result (ref null 0)) ;; label = @1
+      i32.const 0
+      call_indirect (type $t2)
+    end
+    block (result (ref null 1)) ;; label = @1
+      i32.const 0
+      call_indirect (type $t1)
+    end
+    block (result (ref null 1)) ;; label = @1
+      i32.const 0
+      call_indirect (type $t2)
+    end
+    block (result (ref null 0)) ;; label = @1
+      i32.const 1
+      call_indirect (type $t1)
+    end
+    block (result (ref null 0)) ;; label = @1
+      i32.const 1
+      call_indirect (type $t2)
+    end
+    block (result (ref null 1)) ;; label = @1
+      i32.const 1
+      call_indirect (type $t1)
+    end
+    block (result (ref null 1)) ;; label = @1
+      i32.const 1
+      call_indirect (type $t2)
+    end
+    br 0 (;@0;)
+  )
+  (table (;0;) 2 2 funcref)
+  (export "run" (func 2))
+  (elem (;0;) (i32.const 0) func $f1 $f2)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/12.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/12.print
new file mode 100644
index 00000000..121f0bfc
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/12.print
@@ -0,0 +1,45 @@
+(module
+  (rec
+    (type $t1 (;0;) (func (param i32 (ref 0))))
+    (type $t2 (;1;) (func (param i32 (ref 2))))
+    (type $t3 (;2;) (func (param i32 (ref 1))))
+  )
+  (rec
+    (type $u1 (;3;) (func (param i32 (ref 3))))
+    (type $u2 (;4;) (func (param i32 (ref 5))))
+    (type $u3 (;5;) (func (param i32 (ref 4))))
+  )
+  (type (;6;) (func))
+  (func $f1 (;0;) (type $t1) (param i32 (ref 0)))
+  (func $f2 (;1;) (type $t2) (param i32 (ref 2)))
+  (func $f3 (;2;) (type $t3) (param i32 (ref 1)))
+  (func (;3;) (type 6)
+    i32.const 1
+    ref.func $f1
+    i32.const 0
+    call_indirect (type $t1)
+    i32.const 1
+    ref.func $f3
+    i32.const 1
+    call_indirect (type $t2)
+    i32.const 1
+    ref.func $f2
+    i32.const 2
+    call_indirect (type $t3)
+    i32.const 1
+    ref.func $f1
+    i32.const 0
+    call_indirect (type $u1)
+    i32.const 1
+    ref.func $f3
+    i32.const 1
+    call_indirect (type $u2)
+    i32.const 1
+    ref.func $f2
+    i32.const 2
+    call_indirect (type $u3)
+  )
+  (table (;0;) 3 3 funcref)
+  (export "run" (func 3))
+  (elem (;0;) (i32.const 0) func $f1 $f2 $f3)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/14.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/14.print
new file mode 100644
index 00000000..018898ab
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/14.print
@@ -0,0 +1,6 @@
+(module
+  (type $t1 (;0;) (func (param f32 f32) (result f32)))
+  (type (;1;) (func (param (ref 0))))
+  (func (;0;) (type 1) (param (ref 0)))
+  (export "f" (func 0))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/16.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/16.print
new file mode 100644
index 00000000..ff5f8b66
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/16.print
@@ -0,0 +1,5 @@
+(module
+  (type $t2 (;0;) (func (param f32 f32) (result f32)))
+  (type (;1;) (func (param (ref 0))))
+  (import "M" "f" (func (;0;) (type 1)))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/17.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/17.print
new file mode 100644
index 00000000..8dce052a
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/17.print
@@ -0,0 +1,12 @@
+(module
+  (type $s0 (;0;) (func (param i32) (result f32)))
+  (type $s1 (;1;) (func (param i32 (ref 0)) (result (ref 0))))
+  (type $s2 (;2;) (func (param i32 (ref 0)) (result (ref 0))))
+  (type $t1 (;3;) (func (param (ref 1)) (result (ref 2))))
+  (type $t2 (;4;) (func (param (ref 2)) (result (ref 1))))
+  (type (;5;) (func (param (ref 3))))
+  (func (;0;) (type 5) (param (ref 3)))
+  (func (;1;) (type 5) (param (ref 3)))
+  (export "f1" (func 0))
+  (export "f2" (func 1))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/19.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/19.print
new file mode 100644
index 00000000..e5c72be0
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/19.print
@@ -0,0 +1,13 @@
+(module
+  (type $s0 (;0;) (func (param i32) (result f32)))
+  (type $s1 (;1;) (func (param i32 (ref 0)) (result (ref 0))))
+  (type $s2 (;2;) (func (param i32 (ref 0)) (result (ref 0))))
+  (type $t1 (;3;) (func (param (ref 1)) (result (ref 2))))
+  (type $t2 (;4;) (func (param (ref 2)) (result (ref 1))))
+  (type (;5;) (func (param (ref 3))))
+  (type (;6;) (func (param (ref 4))))
+  (import "N" "f1" (func (;0;) (type 5)))
+  (import "N" "f1" (func (;1;) (type 6)))
+  (import "N" "f2" (func (;2;) (type 5)))
+  (import "N" "f2" (func (;3;) (type 5)))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/2.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/2.print
new file mode 100644
index 00000000..99b45f1b
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/2.print
@@ -0,0 +1,18 @@
+(module
+  (rec
+    (type $t1 (;0;) (func (param i32 (ref 0))))
+  )
+  (rec
+    (type $t2 (;1;) (func (param i32 (ref 1))))
+  )
+  (type (;2;) (func (param (ref 0))))
+  (type (;3;) (func (param (ref 1))))
+  (func $f1 (;0;) (type 2) (param $r (ref 0))
+    local.get $r
+    call $f2
+  )
+  (func $f2 (;1;) (type 3) (param $r (ref 1))
+    local.get $r
+    call $f1
+  )
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/20.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/20.print
new file mode 100644
index 00000000..d6f3423f
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/20.print
@@ -0,0 +1,8 @@
+(module
+  (rec
+    (type $t1 (;0;) (func (param i32 (ref 0))))
+  )
+  (type (;1;) (func (param (ref 0))))
+  (func (;0;) (type 1) (param (ref 0)))
+  (export "f" (func 0))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/22.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/22.print
new file mode 100644
index 00000000..dcfa0280
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/22.print
@@ -0,0 +1,7 @@
+(module
+  (rec
+    (type $t2 (;0;) (func (param i32 (ref 0))))
+  )
+  (type (;1;) (func (param (ref 0))))
+  (import "M" "f" (func (;0;) (type 1)))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/23.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/23.print
new file mode 100644
index 00000000..ed376c9d
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/23.print
@@ -0,0 +1,16 @@
+(module
+  (rec
+    (type $t1 (;0;) (func (param i32 (ref 0))))
+    (type $t2 (;1;) (func (param i32 (ref 2))))
+    (type $t3 (;2;) (func (param i32 (ref 1))))
+  )
+  (type (;3;) (func (param (ref 0))))
+  (type (;4;) (func (param (ref 1))))
+  (type (;5;) (func (param (ref 2))))
+  (func (;0;) (type 3) (param (ref 0)))
+  (func (;1;) (type 4) (param (ref 1)))
+  (func (;2;) (type 5) (param (ref 2)))
+  (export "f1" (func 0))
+  (export "f2" (func 1))
+  (export "f3" (func 2))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/25.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/25.print
new file mode 100644
index 00000000..e3251951
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/25.print
@@ -0,0 +1,13 @@
+(module
+  (rec
+    (type $t1 (;0;) (func (param i32 (ref 0))))
+    (type $t2 (;1;) (func (param i32 (ref 2))))
+    (type $t3 (;2;) (func (param i32 (ref 1))))
+  )
+  (type (;3;) (func (param (ref 0))))
+  (type (;4;) (func (param (ref 1))))
+  (type (;5;) (func (param (ref 2))))
+  (import "M" "f1" (func (;0;) (type 3)))
+  (import "M" "f2" (func (;1;) (type 4)))
+  (import "M" "f3" (func (;2;) (type 5)))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/26.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/26.print
new file mode 100644
index 00000000..8fe3251c
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/26.print
@@ -0,0 +1,16 @@
+(module
+  (rec
+    (type $t1 (;0;) (func (param i32 (ref 2))))
+    (type $t2 (;1;) (func (param i32 (ref 0))))
+    (type $t3 (;2;) (func (param i32 (ref 1))))
+  )
+  (type (;3;) (func (param (ref 0))))
+  (type (;4;) (func (param (ref 1))))
+  (type (;5;) (func (param (ref 2))))
+  (func (;0;) (type 3) (param (ref 0)))
+  (func (;1;) (type 4) (param (ref 1)))
+  (func (;2;) (type 5) (param (ref 2)))
+  (export "f1" (func 0))
+  (export "f2" (func 1))
+  (export "f3" (func 2))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/28.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/28.print
new file mode 100644
index 00000000..27cfb026
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/28.print
@@ -0,0 +1,13 @@
+(module
+  (rec
+    (type $t1 (;0;) (func (param i32 (ref 2))))
+    (type $t2 (;1;) (func (param i32 (ref 0))))
+    (type $t3 (;2;) (func (param i32 (ref 1))))
+  )
+  (type (;3;) (func (param (ref 0))))
+  (type (;4;) (func (param (ref 1))))
+  (type (;5;) (func (param (ref 2))))
+  (import "M" "f1" (func (;0;) (type 3)))
+  (import "M" "f2" (func (;1;) (type 4)))
+  (import "M" "f3" (func (;2;) (type 5)))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/29.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/29.print
new file mode 100644
index 00000000..7f75f55e
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/29.print
@@ -0,0 +1,21 @@
+(module
+  (rec
+    (type $t1 (;0;) (func (param i32 (ref 1))))
+    (type $u1 (;1;) (func (param f32 (ref 0))))
+  )
+  (rec
+    (type $t2 (;2;) (func (param i32 (ref 5))))
+    (type $u2 (;3;) (func (param f32 (ref 4))))
+    (type $t3 (;4;) (func (param i32 (ref 3))))
+    (type $u3 (;5;) (func (param f32 (ref 2))))
+  )
+  (type (;6;) (func (param (ref 0))))
+  (type (;7;) (func (param (ref 2))))
+  (type (;8;) (func (param (ref 4))))
+  (func (;0;) (type 6) (param (ref 0)))
+  (func (;1;) (type 7) (param (ref 2)))
+  (func (;2;) (type 8) (param (ref 4)))
+  (export "f1" (func 0))
+  (export "f2" (func 1))
+  (export "f3" (func 2))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/3.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/3.print
new file mode 100644
index 00000000..bef81772
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/3.print
@@ -0,0 +1,14 @@
+(module
+  (type $t1 (;0;) (func (param i32 (ref 0))))
+  (type $t2 (;1;) (func (param i32 (ref 1))))
+  (type (;2;) (func (param (ref 0))))
+  (type (;3;) (func (param (ref 1))))
+  (func $f1 (;0;) (type 2) (param $r (ref 0))
+    local.get $r
+    call $f2
+  )
+  (func $f2 (;1;) (type 3) (param $r (ref 1))
+    local.get $r
+    call $f1
+  )
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/31.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/31.print
new file mode 100644
index 00000000..f9e87d81
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/31.print
@@ -0,0 +1,18 @@
+(module
+  (rec
+    (type $t1 (;0;) (func (param i32 (ref 1))))
+    (type $u1 (;1;) (func (param f32 (ref 0))))
+  )
+  (rec
+    (type $t2 (;2;) (func (param i32 (ref 5))))
+    (type $u2 (;3;) (func (param f32 (ref 4))))
+    (type $t3 (;4;) (func (param i32 (ref 3))))
+    (type $u3 (;5;) (func (param f32 (ref 2))))
+  )
+  (type (;6;) (func (param (ref 0))))
+  (type (;7;) (func (param (ref 2))))
+  (type (;8;) (func (param (ref 4))))
+  (import "M" "f1" (func (;0;) (type 6)))
+  (import "M" "f2" (func (;1;) (type 7)))
+  (import "M" "f3" (func (;2;) (type 8)))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/4.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/4.print
new file mode 100644
index 00000000..ef679ea2
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/4.print
@@ -0,0 +1,30 @@
+(module
+  (rec
+    (type $t0 (;0;) (func (param i32 (ref 1))))
+    (type $t1 (;1;) (func (param i32 (ref 0))))
+  )
+  (rec
+    (type $t2 (;2;) (func (param i32 (ref 3))))
+    (type $t3 (;3;) (func (param i32 (ref 2))))
+  )
+  (type (;4;) (func (param (ref 0))))
+  (type (;5;) (func (param (ref 1))))
+  (type (;6;) (func (param (ref 2))))
+  (type (;7;) (func (param (ref 3))))
+  (func $f0 (;0;) (type 4) (param $r (ref 0))
+    local.get $r
+    call $f2
+  )
+  (func $f1 (;1;) (type 5) (param $r (ref 1))
+    local.get $r
+    call $f3
+  )
+  (func $f2 (;2;) (type 6) (param $r (ref 2))
+    local.get $r
+    call $f0
+  )
+  (func $f3 (;3;) (type 7) (param $r (ref 3))
+    local.get $r
+    call $f1
+  )
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/6.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/6.print
new file mode 100644
index 00000000..51cfc602
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/6.print
@@ -0,0 +1,20 @@
+(module
+  (type $t1 (;0;) (func (param f32 f32)))
+  (type $t2 (;1;) (func (param f32 f32)))
+  (type (;2;) (func))
+  (func $f1 (;0;) (type $t1) (param f32 f32))
+  (func $f2 (;1;) (type $t2) (param f32 f32))
+  (func (;2;) (type 2)
+    f32.const 0x1p+0 (;=1;)
+    f32.const 0x1p+1 (;=2;)
+    i32.const 1
+    call_indirect (type $t1)
+    f32.const 0x1p+0 (;=1;)
+    f32.const 0x1p+1 (;=2;)
+    i32.const 0
+    call_indirect (type $t2)
+  )
+  (table (;0;) 2 2 funcref)
+  (export "run" (func 2))
+  (elem (;0;) (i32.const 0) func $f1 $f2)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/8.print b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/8.print
new file mode 100644
index 00000000..790198e7
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-equivalence.wast/8.print
@@ -0,0 +1,41 @@
+(module
+  (type $s0 (;0;) (func (param i32)))
+  (type $s1 (;1;) (func (param i32 (ref 0))))
+  (type $s2 (;2;) (func (param i32 (ref 0))))
+  (type $t1 (;3;) (func (param (ref 1))))
+  (type $t2 (;4;) (func (param (ref 2))))
+  (type (;5;) (func))
+  (func $s1 (;0;) (type $s1) (param i32 (ref 0)))
+  (func $s2 (;1;) (type $s2) (param i32 (ref 0)))
+  (func $f1 (;2;) (type $t1) (param (ref 1)))
+  (func $f2 (;3;) (type $t2) (param (ref 2)))
+  (func (;4;) (type 5)
+    ref.func $s1
+    i32.const 0
+    call_indirect (type $t1)
+    ref.func $s1
+    i32.const 1
+    call_indirect (type $t1)
+    ref.func $s2
+    i32.const 0
+    call_indirect (type $t1)
+    ref.func $s2
+    i32.const 1
+    call_indirect (type $t1)
+    ref.func $s1
+    i32.const 0
+    call_indirect (type $t2)
+    ref.func $s1
+    i32.const 1
+    call_indirect (type $t2)
+    ref.func $s2
+    i32.const 0
+    call_indirect (type $t2)
+    ref.func $s2
+    i32.const 1
+    call_indirect (type $t2)
+  )
+  (table (;0;) 4 4 funcref)
+  (export "run" (func 4))
+  (elem (;0;) (i32.const 0) func $f1 $f2 $s1 $s2)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-rec.wast/0.print b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/0.print
new file mode 100644
index 00000000..cb45ea25
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/0.print
@@ -0,0 +1,12 @@
+(module
+  (rec
+    (type $f1 (;0;) (func))
+    (type (;1;) (struct (field (ref 0))))
+  )
+  (rec
+    (type $f2 (;2;) (func))
+    (type (;3;) (struct (field (ref 2))))
+  )
+  (func $f (;0;) (type $f2))
+  (global (;0;) (ref 0) ref.func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-rec.wast/1.print b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/1.print
new file mode 100644
index 00000000..1d83cdc5
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/1.print
@@ -0,0 +1,20 @@
+(module
+  (rec
+    (type $f1 (;0;) (func))
+    (type (;1;) (struct (field (ref 0))))
+  )
+  (rec
+    (type $f2 (;2;) (func))
+    (type (;3;) (struct (field (ref 2))))
+  )
+  (rec
+    (type $g1 (;4;) (func))
+    (type (;5;) (struct (field (ref 0)) (field (ref 0)) (field (ref 2)) (field (ref 2)) (field (ref 4))))
+  )
+  (rec
+    (type $g2 (;6;) (func))
+    (type (;7;) (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)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-rec.wast/11.print b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/11.print
new file mode 100644
index 00000000..7bf069fc
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/11.print
@@ -0,0 +1,19 @@
+(module
+  (rec
+    (type $f1 (;0;) (func))
+    (type (;1;) (struct))
+  )
+  (rec
+    (type $f2 (;2;) (func))
+    (type (;3;) (struct))
+  )
+  (type (;4;) (func))
+  (func $f1 (;0;) (type $f1))
+  (func (;1;) (type 4)
+    i32.const 0
+    call_indirect (type $f2)
+  )
+  (table (;0;) 1 1 funcref)
+  (export "run" (func 1))
+  (elem (;0;) (i32.const 0) func $f1)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-rec.wast/13.print b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/13.print
new file mode 100644
index 00000000..99f6e708
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/13.print
@@ -0,0 +1,19 @@
+(module
+  (rec
+    (type $f1 (;0;) (func))
+    (type (;1;) (struct))
+  )
+  (rec
+    (type (;2;) (struct))
+    (type $f2 (;3;) (func))
+  )
+  (type (;4;) (func))
+  (func $f1 (;0;) (type $f1))
+  (func (;1;) (type 4)
+    i32.const 0
+    call_indirect (type $f2)
+  )
+  (table (;0;) 1 1 funcref)
+  (export "run" (func 1))
+  (elem (;0;) (i32.const 0) func $f1)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-rec.wast/15.print b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/15.print
new file mode 100644
index 00000000..017e41e2
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/15.print
@@ -0,0 +1,18 @@
+(module
+  (rec
+    (type $f1 (;0;) (func))
+    (type (;1;) (struct))
+  )
+  (rec
+    (type $f2 (;2;) (func))
+  )
+  (type (;3;) (func))
+  (func $f1 (;0;) (type $f1))
+  (func (;1;) (type 3)
+    i32.const 0
+    call_indirect (type $f2)
+  )
+  (table (;0;) 1 1 funcref)
+  (export "run" (func 1))
+  (elem (;0;) (i32.const 0) func $f1)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-rec.wast/17.print b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/17.print
new file mode 100644
index 00000000..d9f4e208
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/17.print
@@ -0,0 +1,11 @@
+(module
+  (rec
+    (type $s (;0;) (struct))
+  )
+  (rec
+    (type $t (;1;) (func (param (ref 0))))
+  )
+  (type (;2;) (func (param (ref 0))))
+  (func $f (;0;) (type 2) (param (ref 0)))
+  (global (;0;) (ref 1) ref.func $f)
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-rec.wast/6.print b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/6.print
new file mode 100644
index 00000000..1be15507
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/6.print
@@ -0,0 +1,8 @@
+(module $M
+  (rec
+    (type $f1 (;0;) (func))
+    (type (;1;) (struct))
+  )
+  (func (;0;) (type $f1))
+  (export "f" (func 0))
+)
\ No newline at end of file
diff --git a/tests/snapshots/testsuite/proposals/gc/type-rec.wast/8.print b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/8.print
new file mode 100644
index 00000000..a9605384
--- /dev/null
+++ b/tests/snapshots/testsuite/proposals/gc/type-rec.wast/8.print
@@ -0,0 +1,7 @@
+(module
+  (rec
+    (type $f2 (;0;) (func))
+    (type (;1;) (struct))
+  )
+  (import "M" "f" (func (;0;) (type $f2)))
+)
\ No newline at end of file