Repository: bytecodealliance/wasm-tools
Pull request #1868 (2024-10-16 20:21:23)

wit-parser: Group sources used for resolve by package ids
This PR is a request for changing the format of the returned source paths for `Resolve::push_path` and `Resolve::push_dir`, from `Vec<PathBuf>` to `BTreeMap<PackageId, Vec<PathBuf>>`.

Our (Golem Cloud) use case is about using a resolved wit dir and then apply further transformations to it, e.g. managing dependencies between related components. Currently we use a workaround which partially re-parses the wit sources using `UnresolvedPackageGroup`, and then maps the sources to the resolved package ids. With this change the double parsing could be avoided, as the already available mapping info would not lost, and I believe there can be other tooling related use cases for this information for others too. The original intention for the sources (triggering builds on change) should also work, with the caller side change of collapsing the sources into a unique set.

In case changing this return type is not okay or preferable, I would be also grateful to get pointers on how to approach this problem differently.

Thanks in advance!

alexcrichton: Thanks for the PR! I think this is a reasonable feature to support, and it's ok to change the return types here. I'm wondering though if it might be good to have a dedicated newtype here as the return value with various methods and accessors perhaps. For example one of the main uses I know of this is for bindings generators to generate a list of files to depend on but simple iteration over this map will now produce duplicate listings of files if a WIT package is defined with other inline WIT packages as well.

What do you think about something like:

```rust
struct PackageSourceMap { /* ... */ }

impl PackageSourceMap {
    // deduplicates paths so each one only shows up once in the return value
    fn paths(&self) -> impl Iterator<Item = &Path> { /* ... */ }

    // basically BTreeMap::get
    fn package_paths(&self, id: PackageId) -> impl Iterator<Item = &Path> { /* ... */ }
}
```

Does that seem reasonable?
noise64: @alexcrichton Thank you for the response! It it much better that way, I will update the PR soon.

Patch:
diff --git a/crates/wasm-wave/Cargo.toml b/crates/wasm-wave/Cargo.toml
index 9291ab0c..6bb4a25e 100644
--- a/crates/wasm-wave/Cargo.toml
+++ b/crates/wasm-wave/Cargo.toml
@@ -17,7 +17,7 @@ wit = ["dep:wit-parser"]
 
 [dependencies]
 indexmap.workspace = true
-logos = "0.14.0"
+logos = { version = "0.14.2", features = ["forbid_unsafe"] }
 thiserror = "1.0.48"
 wit-parser = { workspace = true, optional = true }
 
diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs
index 5f1f5351..b7844bf8 100644
--- a/crates/wasmprinter/src/lib.rs
+++ b/crates/wasmprinter/src/lib.rs
@@ -813,6 +813,7 @@ impl Printer<'_, '_> {
     fn print_composite(&mut self, state: &State, ty: &CompositeType, ty_idx: u32) -> Result<u32> {
         if ty.shared {
             self.start_group("shared")?;
+            self.result.write_str(" ")?;
         }
         let r = match &ty.inner {
             CompositeInnerType::Func(ty) => {
diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs
index 02efb938..6f8eb79c 100644
--- a/crates/wit-parser/src/resolve.rs
+++ b/crates/wit-parser/src/resolve.rs
@@ -41,21 +41,21 @@ mod clone;
 #[derive(Default, Clone, Debug)]
 #[cfg_attr(feature = "serde", derive(Serialize))]
 pub struct Resolve {
-    /// All knowns worlds within this `Resolve`.
+    /// All known worlds within this `Resolve`.
     ///
     /// Each world points at a `PackageId` which is stored below. No ordering is
     /// guaranteed between this list of worlds.
     #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_arena"))]
     pub worlds: Arena<World>,
 
-    /// All knowns interfaces within this `Resolve`.
+    /// All known interfaces within this `Resolve`.
     ///
     /// Each interface points at a `PackageId` which is stored below. No
     /// ordering is guaranteed between this list of interfaces.
     #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_arena"))]
     pub interfaces: Arena<Interface>,
 
-    /// All knowns types within this `Resolve`.
+    /// All known types within this `Resolve`.
     ///
     /// Types are topologically sorted such that any type referenced from one
     /// type is guaranteed to be defined previously. Otherwise though these are
@@ -63,7 +63,7 @@ pub struct Resolve {
     #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_arena"))]
     pub types: Arena<TypeDef>,
 
-    /// All knowns packages within this `Resolve`.
+    /// All known packages within this `Resolve`.
     ///
     /// This list of packages is not sorted. Sorted packages can be queried
     /// through [`Resolve::topological_packages`].
@@ -115,6 +115,71 @@ pub struct Package {
 
 pub type PackageId = Id<Package>;
 
+/// All the sources used during resolving a directory or path.
+#[derive(Clone, Debug)]
+pub struct PackageSourceMap {
+    sources: Vec<Vec<PathBuf>>,
+    package_id_to_source_map_idx: BTreeMap<PackageId, usize>,
+}
+
+impl PackageSourceMap {
+    fn from_single_source(package_id: PackageId, source: &Path) -> Self {
+        Self {
+            sources: vec![vec![source.to_path_buf()]],
+            package_id_to_source_map_idx: BTreeMap::from([(package_id, 0)]),
+        }
+    }
+
+    fn from_source_maps(
+        source_maps: Vec<SourceMap>,
+        package_id_to_source_map_idx: BTreeMap<PackageId, usize>,
+    ) -> PackageSourceMap {
+        for (package_id, idx) in &package_id_to_source_map_idx {
+            if *idx >= source_maps.len() {
+                panic!(
+                    "Invalid source map index: {}, package id: {:?}, source maps size: {}",
+                    idx,
+                    package_id,
+                    source_maps.len()
+                )
+            }
+        }
+
+        Self {
+            sources: source_maps
+                .into_iter()
+                .map(|source_map| {
+                    source_map
+                        .source_files()
+                        .map(|path| path.to_path_buf())
+                        .collect()
+                })
+                .collect(),
+            package_id_to_source_map_idx,
+        }
+    }
+
+    /// All unique source paths.
+    pub fn paths(&self) -> impl Iterator<Item = &Path> {
+        // Usually any two source map should not have duplicated source paths,
+        // but it can happen, e.g. with using [`Resolve::push_str`] directly.
+        // To be sure we use a set for deduplication here.
+        self.sources
+            .iter()
+            .flatten()
+            .map(|path_buf| path_buf.as_ref())
+            .collect::<HashSet<&Path>>()
+            .into_iter()
+    }
+
+    /// Source paths for package
+    pub fn package_paths(&self, id: PackageId) -> Option<impl Iterator<Item = &Path>> {
+        self.package_id_to_source_map_idx
+            .get(&id)
+            .map(|&idx| self.sources[idx].iter().map(|path_buf| path_buf.as_ref()))
+    }
+}
+
 enum ParsedFile {
     #[cfg(feature = "decoding")]
     Package(PackageId),
@@ -176,26 +241,24 @@ impl Resolve {
     /// inserted packages into this `Resolve`. Resolution for packages is based
     /// on the name of each package and reference.
     ///
-    /// This method returns a list of `PackageId` elements and additionally a
-    /// list of `PathBuf` elements. The `PackageId` elements represent the "main
-    /// package" that was parsed. For example if a single WIT file was specified
-    /// this will be all the packages found in the file. For a directory this
-    /// will be all the packages in the directory itself, but not in the `deps`
-    /// directory. The list of `PackageId` values is useful to pass to
-    /// [`Resolve::select_world`] to take a user-specified world in a
+    /// This method returns a `PackageId` and additionally a `PackageSourceMap`.
+    /// The `PackageId` represent the main package that was parsed. For example if a single WIT
+    /// file was specified  this will be the main package found in the file. For a directory this
+    /// will be all the main package in the directory itself. The `PackageId` value is useful
+    /// to pass to [`Resolve::select_world`] to take a user-specified world in a
     /// conventional fashion and select which to use for bindings generation.
     ///
-    /// The returned list of `PathBuf` elements represents all files parsed
-    /// during this operation. This can be useful for systems that want to
-    /// rebuild or regenerate bindings based on files modified.
+    /// The returned [`PackageSourceMap`] contains all the sources used during this operation.
+    /// This can be useful for systems that want to rebuild or regenerate bindings based on files modified,
+    /// or for ones which like to identify the used files for a package.
     ///
     /// More information can also be found at [`Resolve::push_dir`] and
     /// [`Resolve::push_file`].
-    pub fn push_path(&mut self, path: impl AsRef<Path>) -> Result<(PackageId, Vec<PathBuf>)> {
+    pub fn push_path(&mut self, path: impl AsRef<Path>) -> Result<(PackageId, PackageSourceMap)> {
         self._push_path(path.as_ref())
     }
 
-    fn _push_path(&mut self, path: &Path) -> Result<(PackageId, Vec<PathBuf>)> {
+    fn _push_path(&mut self, path: &Path) -> Result<(PackageId, PackageSourceMap)> {
         if path.is_dir() {
             self.push_dir(path).with_context(|| {
                 format!(
@@ -205,7 +268,7 @@ impl Resolve {
             })
         } else {
             let id = self.push_file(path)?;
-            Ok((id, vec![path.to_path_buf()]))
+            Ok((id, PackageSourceMap::from_single_source(id, path)))
         }
     }
 
@@ -213,7 +276,7 @@ impl Resolve {
         &mut self,
         main: UnresolvedPackageGroup,
         deps: Vec<UnresolvedPackageGroup>,
-    ) -> Result<(PackageId, Vec<PathBuf>)> {
+    ) -> Result<(PackageId, PackageSourceMap)> {
         let mut pkg_details_map = BTreeMap::new();
         let mut source_maps = Vec::new();
 
@@ -269,8 +332,9 @@ package {name} is defined in two different locations:\n\
         }
 
         // Ensure that the final output is topologically sorted. Use a set to ensure that we render
-        // the buffers for each `SourceMap` only once, even though multiple packages may references
+        // the buffers for each `SourceMap` only once, even though multiple packages may reference
         // the same `SourceMap`.
+        let mut package_id_to_source_map_idx = BTreeMap::new();
         let mut main_pkg_id = None;
         for name in order {
             let (pkg, source_map_index) = pkg_details_map.remove(&name).unwrap();
@@ -281,15 +345,13 @@ package {name} is defined in two different locations:\n\
                 assert!(main_pkg_id.is_none());
                 main_pkg_id = Some(id);
             }
+            package_id_to_source_map_idx.insert(id, source_map_index);
         }
 
-        let path_bufs = source_maps
-            .iter()
-            .flat_map(|s| s.source_files())
-            .map(|p| p.to_path_buf())
-            .collect();
-
-        Ok((main_pkg_id.unwrap(), path_bufs))
+        Ok((
+            main_pkg_id.unwrap(),
+            PackageSourceMap::from_source_maps(source_maps, package_id_to_source_map_idx),
+        ))
     }
 
     /// Parses the filesystem directory at `path` as a WIT package and returns
@@ -314,24 +376,22 @@ package {name} is defined in two different locations:\n\
     ///
     /// In all cases entries in the `deps` folder are added to `self` first
     /// before adding files found in `path` itself. All WIT packages found are
-    /// candidates for name-based resolution that other packages may used.
-    ///
-    /// This function returns a tuple of two values. The first value is a list
-    /// of [`PackageId`] values which represents the WIT packages found within
-    /// `path`, but not those within `deps`. The `path` provided may contain
-    /// only a single WIT package but might also use the multi-package form of
-    /// WIT, and the returned list will indicate which was used. This argument
-    /// is useful for passing to [`Resolve::select_world`] for choosing
-    /// something to bindgen with.
-    ///
-    /// The second value returned here is the list of paths that were parsed
-    /// when generating the return value. This can be useful for build systems
-    /// that want to rebuild bindings whenever one of the files change.
-    pub fn push_dir(&mut self, path: impl AsRef<Path>) -> Result<(PackageId, Vec<PathBuf>)> {
+    /// candidates for name-based resolution that other packages may use.
+    ///
+    /// This function returns a tuple of two values. The first value is a
+    /// [`PackageId`], which represents the main WIT package found within
+    /// `path`. This argument is useful for passing to [`Resolve::select_world`]
+    /// for choosing something to bindgen with.
+    ///
+    /// The second value returned is a [`PackageSourceMap`], which contains all the sources
+    /// that were parsed during resolving. This can be useful for:
+    /// * build systems that want to rebuild bindings whenever one of the files changed
+    /// * or other tools, which want to identify the sources for the resolved packages
+    pub fn push_dir(&mut self, path: impl AsRef<Path>) -> Result<(PackageId, PackageSourceMap)> {
         self._push_dir(path.as_ref())
     }
 
-    fn _push_dir(&mut self, path: &Path) -> Result<(PackageId, Vec<PathBuf>)> {
+    fn _push_dir(&mut self, path: &Path) -> Result<(PackageId, PackageSourceMap)> {
         let top_pkg = UnresolvedPackageGroup::parse_dir(path)
             .with_context(|| format!("failed to parse package: {}", path.display()))?;
         let deps = path.join("deps");


Test patch:
diff --git a/tests/local/shared-everything-threads/rec-groups.wast b/tests/local/shared-everything-threads/rec-groups.wast
new file mode 100644
index 00000000..72c4c7db
--- /dev/null
+++ b/tests/local/shared-everything-threads/rec-groups.wast
@@ -0,0 +1,19 @@
+(assert_invalid
+  (module
+    (rec
+      (type (; super ;) (sub (func (result (ref null (shared func))))))
+      (type (; sub ;) (sub 0 (func (result (ref null func)))))
+    )
+  )
+  "sub type must match super type"
+)
+
+(assert_invalid
+  (module
+    (rec
+      (type (; super ;) (sub (func (param (ref null (shared func))))))
+      (type (; sub ;) (sub 0 (func (param (ref null 0)))))
+    )
+  )
+  "sub type must match super type"
+)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/0.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/0.print
index d875a17e..cdad9e03 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/0.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/0.print
@@ -1,8 +1,8 @@
 (module
-  (type (;0;) (shared(array i8)))
-  (type (;1;) (shared(array i8)))
+  (type (;0;) (shared (array i8)))
+  (type (;1;) (shared (array i8)))
   (rec
-    (type (;2;) (shared(array i8)))
+    (type (;2;) (shared (array i8)))
   )
   (global (;0;) (ref 0) i32.const 1 array.new_default 1)
   (global (;1;) (ref 1) i32.const 1 array.new_default 2)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/18.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/18.print
index f0cd910d..a37fdc30 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/18.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/18.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32) (result i32)))
   (export "array-atomic-get-i32-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/19.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/19.print
index dc2790d7..96b2e988 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/19.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/19.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32) (result i64)))
   (export "array-atomic-get-i64-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/20.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/20.print
index 787da9a4..a7574117 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/20.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/20.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut (ref null (shared any))))))
+  (type $a (;0;) (shared (array (mut (ref null (shared any))))))
   (type (;1;) (func (param (ref null $a) i32) (result (ref null (shared any)))))
   (export "array-atomic-get-anyref-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result (ref null (shared any)))
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/21.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/21.print
index 703ea625..5d8b7ecb 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/21.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/21.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32) (result i32)))
   (export "array-atomic-get-i32-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/22.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/22.print
index a6ae9922..c9f3819c 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/22.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/22.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32) (result i64)))
   (export "array-atomic-get-i64-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/23.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/23.print
index 8bb37158..9d9f98d7 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/23.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/23.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut (ref null (shared any))))))
+  (type $a (;0;) (shared (array (mut (ref null (shared any))))))
   (type (;1;) (func (param (ref null $a) i32) (result (ref null (shared any)))))
   (export "array-atomic-get-anyref-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result (ref null (shared any)))
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/24.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/24.print
index b109126d..43fd3abf 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/24.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/24.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i8))))
+  (type $a (;0;) (shared (array (mut i8))))
   (type (;1;) (func (param (ref null $a) i32) (result i32)))
   (export "array-atomic-get_s-i8-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/25.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/25.print
index 63217549..2e56807b 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/25.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/25.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i16))))
+  (type $a (;0;) (shared (array (mut i16))))
   (type (;1;) (func (param (ref null $a) i32) (result i32)))
   (export "array-atomic-get_s-i16-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/26.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/26.print
index 5445eb1e..6648562b 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/26.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/26.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i8))))
+  (type $a (;0;) (shared (array (mut i8))))
   (type (;1;) (func (param (ref null $a) i32) (result i32)))
   (export "array-atomic-get_s-i8-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/27.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/27.print
index ea3b3080..ee562e5c 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/27.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/27.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i16))))
+  (type $a (;0;) (shared (array (mut i16))))
   (type (;1;) (func (param (ref null $a) i32) (result i32)))
   (export "array-atomic-get_s-i16-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/28.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/28.print
index e5d89a9e..11ab9b96 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/28.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/28.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i8))))
+  (type $a (;0;) (shared (array (mut i8))))
   (type (;1;) (func (param (ref null $a) i32) (result i32)))
   (export "array-atomic-get_u-i8-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/29.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/29.print
index 48f4e039..59639b4e 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/29.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/29.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i16))))
+  (type $a (;0;) (shared (array (mut i16))))
   (type (;1;) (func (param (ref null $a) i32) (result i32)))
   (export "array-atomic-get_u-i16-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/30.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/30.print
index 7dac211d..4d4c71f8 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/30.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/30.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i8))))
+  (type $a (;0;) (shared (array (mut i8))))
   (type (;1;) (func (param (ref null $a) i32) (result i32)))
   (export "array-atomic-get_u-i8-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/31.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/31.print
index 689a1c55..a02ed854 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/31.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/31.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i16))))
+  (type $a (;0;) (shared (array (mut i16))))
   (type (;1;) (func (param (ref null $a) i32) (result i32)))
   (export "array-atomic-get_u-i16-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/32.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/32.print
index f8586f97..d979508e 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/32.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/32.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i8))))
+  (type $a (;0;) (shared (array (mut i8))))
   (type (;1;) (func (param (ref null $a) i32 i32)))
   (export "array-atomic-set-i8-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/33.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/33.print
index f7ca4a36..ec3fbced 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/33.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/33.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i16))))
+  (type $a (;0;) (shared (array (mut i16))))
   (type (;1;) (func (param (ref null $a) i32 i32)))
   (export "array-atomic-set-i16-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/34.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/34.print
index 0dee78fb..bb89edb8 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/34.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/34.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32)))
   (export "array-atomic-set-i32-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/35.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/35.print
index 74afdceb..0adf6b6c 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/35.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/35.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64)))
   (export "array-atomic-set-i64-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/36.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/36.print
index db3cc5b7..b52fb926 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/36.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/36.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut (ref null (shared any))))))
+  (type $a (;0;) (shared (array (mut (ref null (shared any))))))
   (type (;1;) (func (param (ref null $a) i32 (ref null (shared any)))))
   (export "array-atomic-set-anyref-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any)))
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/37.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/37.print
index 7c3dca67..93ec47b2 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/37.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/37.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i8))))
+  (type $a (;0;) (shared (array (mut i8))))
   (type (;1;) (func (param (ref null $a) i32 i32)))
   (export "array-atomic-set-i8-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/38.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/38.print
index 0d358b93..2f81595e 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/38.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/38.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i16))))
+  (type $a (;0;) (shared (array (mut i16))))
   (type (;1;) (func (param (ref null $a) i32 i32)))
   (export "array-atomic-set-i16-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/39.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/39.print
index 909c54e0..3c4d2f12 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/39.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/39.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32)))
   (export "array-atomic-set-i32-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/40.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/40.print
index f35d7834..9aaa4cda 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/40.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/40.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64)))
   (export "array-atomic-set-i64-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/41.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/41.print
index dad32035..d8380d07 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/41.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/41.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut (ref null (shared any))))))
+  (type $a (;0;) (shared (array (mut (ref null (shared any))))))
   (type (;1;) (func (param (ref null $a) i32 (ref null (shared any)))))
   (export "array-atomic-set-anyref-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any)))
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/42.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/42.print
index 90aadacf..b822e9c1 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/42.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/42.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.add-i32-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/43.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/43.print
index df1d5c44..f70b1cf2 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/43.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/43.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.add-i64-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/44.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/44.print
index 452a6f79..b0591d78 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/44.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/44.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.add-i32-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/45.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/45.print
index 3448e810..edd88925 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/45.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/45.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.add-i64-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/46.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/46.print
index 6345ff94..44322f17 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/46.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/46.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.sub-i32-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/47.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/47.print
index cfb64b46..047df8f0 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/47.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/47.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.sub-i64-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/48.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/48.print
index e79b5c4b..11c250a2 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/48.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/48.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.sub-i32-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/49.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/49.print
index 90215072..85072ee7 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/49.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/49.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.sub-i64-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/50.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/50.print
index d05deca2..816013fb 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/50.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/50.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.and-i32-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/51.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/51.print
index 98f6287b..05101030 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/51.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/51.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.and-i64-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/52.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/52.print
index cdb583b5..98f3983f 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/52.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/52.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.and-i32-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/53.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/53.print
index 1dfd8f2b..3cae42de 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/53.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/53.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.and-i64-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/54.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/54.print
index af504cd8..ac96afd5 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/54.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/54.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.or-i32-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/55.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/55.print
index 553d2642..5b2f39ba 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/55.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/55.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.or-i64-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/56.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/56.print
index 9ac7f088..0ac23a38 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/56.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/56.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.or-i32-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/57.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/57.print
index 6c29694a..fb4b01df 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/57.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/57.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.or-i64-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/58.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/58.print
index ab170a82..9106f6f1 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/58.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/58.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.xor-i32-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/59.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/59.print
index 5ea551b7..91d674cd 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/59.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/59.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.xor-i64-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/6.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/6.print
index 7ea8fb8f..84d609eb 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/6.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/6.print
@@ -1,3 +1,3 @@
 (module
-  (type (;0;) (shared(array (ref null (shared any)))))
+  (type (;0;) (shared (array (ref null (shared any)))))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/60.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/60.print
index 8d40dde7..1fa53d6d 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/60.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/60.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.xor-i32-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/61.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/61.print
index 400824c8..987a6781 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/61.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/61.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.xor-i64-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/62.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/62.print
index 76ccc574..e97f9c91 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/62.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/62.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.xchg-i32-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/63.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/63.print
index 70fe9c99..7d2458e4 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/63.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/63.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.xchg-i64-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/64.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/64.print
index 801f1e97..56ff3cb8 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/64.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/64.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut (ref null (shared any))))))
+  (type $a (;0;) (shared (array (mut (ref null (shared any))))))
   (type (;1;) (func (param (ref null $a) i32 (ref null (shared any))) (result (ref null (shared any)))))
   (export "array-atomic-rmw.xchg-anyref-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any)))
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/65.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/65.print
index d5e9490e..5b9883f0 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/65.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/65.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32) (result i32)))
   (export "array-atomic-rmw.xchg-i32-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/66.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/66.print
index 22cd19a4..ed489fb6 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/66.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/66.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64) (result i64)))
   (export "array-atomic-rmw.xchg-i64-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/67.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/67.print
index 3c6c2bc7..f9890644 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/67.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/67.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut (ref null (shared any))))))
+  (type $a (;0;) (shared (array (mut (ref null (shared any))))))
   (type (;1;) (func (param (ref null $a) i32 (ref null (shared any))) (result (ref null (shared any)))))
   (export "array-atomic-rmw.xchg-anyref-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any)))
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/68.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/68.print
index 7011dec7..76fe386b 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/68.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/68.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32 i32) (result i32)))
   (export "array-atomic-rmw.cmpxchg-i32-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (param $A i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/69.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/69.print
index 2c7db0e9..ee6a89a6 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/69.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/69.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64 i64) (result i64)))
   (export "array-atomic-rmw.cmpxchg-i64-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (param $A i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/70.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/70.print
index 0bae52d1..8e18b045 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/70.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/70.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut (ref null (shared eq))))))
+  (type $a (;0;) (shared (array (mut (ref null (shared eq))))))
   (type (;1;) (func (param (ref null $a) i32 (ref null (shared eq)) (ref null (shared eq))) (result (ref null (shared eq)))))
   (export "array-atomic-rmw.cmpxchg-eqref-seq_cst" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared eq))) (param $A (ref null (shared eq))) (result (ref null (shared eq)))
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/71.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/71.print
index 184f75a3..3d41e424 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/71.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/71.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i32))))
+  (type $a (;0;) (shared (array (mut i32))))
   (type (;1;) (func (param (ref null $a) i32 i32 i32) (result i32)))
   (export "array-atomic-rmw.cmpxchg-i32-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (param $A i32) (result i32)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/72.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/72.print
index 39a2ad49..fb225a5c 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/72.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/72.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut i64))))
+  (type $a (;0;) (shared (array (mut i64))))
   (type (;1;) (func (param (ref null $a) i32 i64 i64) (result i64)))
   (export "array-atomic-rmw.cmpxchg-i64-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (param $A i64) (result i64)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/73.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/73.print
index ea39318a..d9703351 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/73.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/73.print
@@ -1,5 +1,5 @@
 (module
-  (type $a (;0;) (shared(array (mut (ref null (shared eq))))))
+  (type $a (;0;) (shared (array (mut (ref null (shared eq))))))
   (type (;1;) (func (param (ref null $a) i32 (ref null (shared eq)) (ref null (shared eq))) (result (ref null (shared eq)))))
   (export "array-atomic-rmw.cmpxchg-eqref-acq_rel" (func 0))
   (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared eq))) (param $A (ref null (shared eq))) (result (ref null (shared eq)))
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/8.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/8.print
index 7cdf73e2..9de5b8df 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/8.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/8.print
@@ -1,6 +1,6 @@
 (module
-  (type $i8 (;0;) (shared(array (mut i8))))
-  (type $i32 (;1;) (shared(array (mut i32))))
+  (type $i8 (;0;) (shared (array (mut i8))))
+  (type $i32 (;1;) (shared (array (mut i32))))
   (type $unshared (;2;) (array (mut i8)))
   (type (;3;) (func))
   (type (;4;) (func (param (ref null $i8))))
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/9.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/9.print
index 0631d03f..8a7c8119 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/9.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/9.print
@@ -1,7 +1,7 @@
 (module
-  (type $i8 (;0;) (shared(array (mut i8))))
-  (type $i32 (;1;) (shared(array (mut i32))))
-  (type $funcs (;2;) (shared(array (mut (ref null (shared func))))))
+  (type $i8 (;0;) (shared (array (mut i8))))
+  (type $i32 (;1;) (shared (array (mut i32))))
+  (type $funcs (;2;) (shared (array (mut (ref null (shared func))))))
   (type (;3;) (func))
   (type (;4;) (func (param (ref null $i8))))
   (elem (;0;) (ref null (shared func)))
diff --git a/tests/snapshots/local/shared-everything-threads/builtins.wast/0.print b/tests/snapshots/local/shared-everything-threads/builtins.wast/0.print
index 4c37d848..77e3cfd1 100644
--- a/tests/snapshots/local/shared-everything-threads/builtins.wast/0.print
+++ b/tests/snapshots/local/shared-everything-threads/builtins.wast/0.print
@@ -1,5 +1,5 @@
 (component
-  (core type $start (;0;) (shared(func (param i32))))
+  (core type $start (;0;) (shared (func (param i32))))
   (core func $spawn (;0;) (canon thread.spawn $start))
   (core func $concurrency (;1;) (canon thread.hw_concurrency))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/builtins.wast/1.print b/tests/snapshots/local/shared-everything-threads/builtins.wast/1.print
index aa850861..79906b58 100644
--- a/tests/snapshots/local/shared-everything-threads/builtins.wast/1.print
+++ b/tests/snapshots/local/shared-everything-threads/builtins.wast/1.print
@@ -1,9 +1,9 @@
 (component
-  (core type $start (;0;) (shared(func (param i32))))
+  (core type $start (;0;) (shared (func (param i32))))
   (core func $spawn (;0;) (canon thread.spawn $start))
   (core func $concurrency (;1;) (canon thread.hw_concurrency))
   (core module $m (;0;)
-    (type $st (;0;) (shared(func (param i32))))
+    (type $st (;0;) (shared (func (param i32))))
     (type (;1;) (func (param (ref null $st) i32) (result i32)))
     (type (;2;) (func (result i32)))
     (import "" "spawn" (func (;0;) (type 1)))
diff --git a/tests/snapshots/local/shared-everything-threads/funcs.wast/0.print b/tests/snapshots/local/shared-everything-threads/funcs.wast/0.print
index 8a2d5936..f8f56de8 100644
--- a/tests/snapshots/local/shared-everything-threads/funcs.wast/0.print
+++ b/tests/snapshots/local/shared-everything-threads/funcs.wast/0.print
@@ -1,5 +1,5 @@
 (module
-  (type $f (;0;) (shared(func)))
+  (type $f (;0;) (shared (func)))
   (import "spectest" "shared-func" (func (;0;) (type $f)))
   (func (;1;) (type $f))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/rec-groups.wast.json b/tests/snapshots/local/shared-everything-threads/rec-groups.wast.json
new file mode 100644
index 00000000..865a3161
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/rec-groups.wast.json
@@ -0,0 +1,19 @@
+{
+  "source_filename": "tests/local/shared-everything-threads/rec-groups.wast",
+  "commands": [
+    {
+      "type": "assert_invalid",
+      "line": 2,
+      "filename": "rec-groups.0.wasm",
+      "module_type": "binary",
+      "text": "sub type must match super type"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 12,
+      "filename": "rec-groups.1.wasm",
+      "module_type": "binary",
+      "text": "sub type must match super type"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/snapshots/local/shared-everything-threads/ref-equivalence.wast/0.print b/tests/snapshots/local/shared-everything-threads/ref-equivalence.wast/0.print
index f6373012..4e58c0af 100644
--- a/tests/snapshots/local/shared-everything-threads/ref-equivalence.wast/0.print
+++ b/tests/snapshots/local/shared-everything-threads/ref-equivalence.wast/0.print
@@ -1,11 +1,11 @@
 (module
-  (type $st (;0;) (sub (shared(struct))))
-  (type $st' (;1;) (sub (shared(struct (field i32)))))
-  (type $at (;2;) (shared(array i8)))
-  (type $st-sub1 (;3;) (sub $st (shared(struct))))
-  (type $st-sub2 (;4;) (sub $st (shared(struct))))
-  (type $st'-sub1 (;5;) (sub $st' (shared(struct (field i32)))))
-  (type $st'-sub2 (;6;) (sub $st' (shared(struct (field i32)))))
+  (type $st (;0;) (sub (shared (struct))))
+  (type $st' (;1;) (sub (shared (struct (field i32)))))
+  (type $at (;2;) (shared (array i8)))
+  (type $st-sub1 (;3;) (sub $st (shared (struct))))
+  (type $st-sub2 (;4;) (sub $st (shared (struct))))
+  (type $st'-sub1 (;5;) (sub $st' (shared (struct (field i32)))))
+  (type $st'-sub2 (;6;) (sub $st' (shared (struct (field i32)))))
   (type (;7;) (func))
   (type (;8;) (func (param i32 i32) (result i32)))
   (table (;0;) 20 (ref null (shared eq)))
diff --git a/tests/snapshots/local/shared-everything-threads/structs.wast/0.print b/tests/snapshots/local/shared-everything-threads/structs.wast/0.print
index d0c306e0..9f4a0ac9 100644
--- a/tests/snapshots/local/shared-everything-threads/structs.wast/0.print
+++ b/tests/snapshots/local/shared-everything-threads/structs.wast/0.print
@@ -1,8 +1,8 @@
 (module
-  (type (;0;) (shared(struct)))
-  (type (;1;) (shared(struct)))
+  (type (;0;) (shared (struct)))
+  (type (;1;) (shared (struct)))
   (rec
-    (type (;2;) (shared(struct)))
+    (type (;2;) (shared (struct)))
   )
   (global (;0;) (ref 0) struct.new 1)
   (global (;1;) (ref 1) struct.new 2)
diff --git a/tests/snapshots/local/shared-everything-threads/structs.wast/18.print b/tests/snapshots/local/shared-everything-threads/structs.wast/18.print
index 3f458d8e..30009aa5 100644
--- a/tests/snapshots/local/shared-everything-threads/structs.wast/18.print
+++ b/tests/snapshots/local/shared-everything-threads/structs.wast/18.print
@@ -1,5 +1,5 @@
 (module
-  (type $s (;0;) (shared(struct (field $i8 (mut i8)) (field $i16 (mut i16)) (field $i32 (mut i32)) (field $i64 (mut i64)) (field $anyref (mut (ref null (shared any)))) (field $eqref (mut (ref null (shared eq)))))))
+  (type $s (;0;) (shared (struct (field $i8 (mut i8)) (field $i16 (mut i16)) (field $i32 (mut i32)) (field $i64 (mut i64)) (field $anyref (mut (ref null (shared any)))) (field $eqref (mut (ref null (shared eq)))))))
   (type (;1;) (func (param (ref null $s)) (result i32)))
   (type (;2;) (func (param (ref null $s)) (result i64)))
   (type (;3;) (func (param (ref null $s)) (result (ref null (shared any)))))
diff --git a/tests/snapshots/local/shared-everything-threads/structs.wast/6.print b/tests/snapshots/local/shared-everything-threads/structs.wast/6.print
index 586faeaa..87a7bad1 100644
--- a/tests/snapshots/local/shared-everything-threads/structs.wast/6.print
+++ b/tests/snapshots/local/shared-everything-threads/structs.wast/6.print
@@ -1,3 +1,3 @@
 (module
-  (type (;0;) (shared(struct (field (ref null (shared any))))))
+  (type (;0;) (shared (struct (field (ref null (shared any))))))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/structs.wast/8.print b/tests/snapshots/local/shared-everything-threads/structs.wast/8.print
index 95f477bf..27a727b6 100644
--- a/tests/snapshots/local/shared-everything-threads/structs.wast/8.print
+++ b/tests/snapshots/local/shared-everything-threads/structs.wast/8.print
@@ -1,6 +1,6 @@
 (module
-  (type $i8 (;0;) (shared(struct (field (mut i8)))))
-  (type $i32 (;1;) (shared(struct (field (mut i32)))))
+  (type $i8 (;0;) (shared (struct (field (mut i8)))))
+  (type $i32 (;1;) (shared (struct (field (mut i32)))))
   (type $unshared (;2;) (struct (field (mut i8))))
   (type (;3;) (func))
   (type (;4;) (func (param (ref null $i8))))
diff --git a/tests/snapshots/local/shared-everything-threads/structs.wast/9.print b/tests/snapshots/local/shared-everything-threads/structs.wast/9.print
index 2416b69b..675fc4f0 100644
--- a/tests/snapshots/local/shared-everything-threads/structs.wast/9.print
+++ b/tests/snapshots/local/shared-everything-threads/structs.wast/9.print
@@ -1,5 +1,5 @@
 (module
-  (type $i8 (;0;) (shared(struct (field (mut i8)))))
+  (type $i8 (;0;) (shared (struct (field (mut i8)))))
   (type (;1;) (func))
   (func (;0;) (type 1)
     ref.null (shared none)
diff --git a/tests/snapshots/local/shared-everything-threads/types.wast/48.print b/tests/snapshots/local/shared-everything-threads/types.wast/48.print
index 23f2967b..285c93f8 100644
--- a/tests/snapshots/local/shared-everything-threads/types.wast/48.print
+++ b/tests/snapshots/local/shared-everything-threads/types.wast/48.print
@@ -1,5 +1,5 @@
 (module
-  (type $t (;0;) (shared(func)))
+  (type $t (;0;) (shared (func)))
   (import "spectest" "global_t" (global (;0;) (shared (ref $t))))
   (import "spectest" "global_mut_t" (global (;1;) (shared mut (ref $t))))
   (import "spectest" "global_null_t" (global (;2;) (shared (ref null $t))))
diff --git a/tests/snapshots/local/shared-everything-threads/types.wast/52.print b/tests/snapshots/local/shared-everything-threads/types.wast/52.print
index 82a7f609..4d968aab 100644
--- a/tests/snapshots/local/shared-everything-threads/types.wast/52.print
+++ b/tests/snapshots/local/shared-everything-threads/types.wast/52.print
@@ -1,5 +1,5 @@
 (module
-  (type $t (;0;) (shared(array i32)))
+  (type $t (;0;) (shared (array i32)))
   (import "spectest" "global_t" (global (;0;) (shared (ref $t))))
   (import "spectest" "global_mut_t" (global (;1;) (shared mut (ref $t))))
   (import "spectest" "global_null_t" (global (;2;) (shared (ref null $t))))
diff --git a/tests/snapshots/local/shared-everything-threads/types.wast/56.print b/tests/snapshots/local/shared-everything-threads/types.wast/56.print
index ddf50f82..c18799c8 100644
--- a/tests/snapshots/local/shared-everything-threads/types.wast/56.print
+++ b/tests/snapshots/local/shared-everything-threads/types.wast/56.print
@@ -1,5 +1,5 @@
 (module
-  (type $t (;0;) (shared(struct (field i32))))
+  (type $t (;0;) (shared (struct (field i32))))
   (import "spectest" "global_t" (global (;0;) (shared (ref $t))))
   (import "spectest" "global_mut_t" (global (;1;) (shared mut (ref $t))))
   (import "spectest" "global_null_t" (global (;2;) (shared (ref null $t))))