Repository: bytecodealliance/wasm-tools
Pull request #1873 (2024-10-18 14:39:40)

wit-encoder: interface identifier and getter setter fixes
Changes:
- Add some more missing getters and setters which were left out from https://github.com/bytecodealliance/wasm-tools/pull/1867.
- Interface identifiers were missing the package parts in case they were from another package




Patch:
diff --git a/Cargo.lock b/Cargo.lock
index a5b45006..e64411ad 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2321,6 +2321,7 @@ dependencies = [
 name = "wit-encoder"
 version = "0.219.1"
 dependencies = [
+ "anyhow",
  "id-arena",
  "indoc",
  "pretty_assertions",
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-encoder/Cargo.toml b/crates/wit-encoder/Cargo.toml
index 1f8a0700..cae10c59 100644
--- a/crates/wit-encoder/Cargo.toml
+++ b/crates/wit-encoder/Cargo.toml
@@ -33,4 +33,5 @@ wit-parser = { workspace = true, optional = true }
 id-arena = { workspace = true, optional = true }
 
 [dev-dependencies]
+anyhow = { workspace = true }
 indoc = { workspace = true }
diff --git a/crates/wit-encoder/src/from_parser.rs b/crates/wit-encoder/src/from_parser.rs
index a9306c6f..98fded85 100644
--- a/crates/wit-encoder/src/from_parser.rs
+++ b/crates/wit-encoder/src/from_parser.rs
@@ -1,10 +1,10 @@
-use id_arena::Id;
-
 use crate::{
-    Enum, Flags, Interface, InterfaceItem, Package, PackageName, Params, Record, Resource,
+    Enum, Flags, Ident, Interface, InterfaceItem, Package, PackageName, Params, Record, Resource,
     ResourceFunc, Result_, Results, StandaloneFunc, Tuple, Type, TypeDef, TypeDefKind, Variant,
     World, WorldItem,
 };
+use id_arena::Id;
+use wit_parser::PackageId;
 
 pub fn packages_from_parsed(resolve: &wit_parser::Resolve) -> Vec<Package> {
     let converter = Converter::new(resolve);
@@ -24,15 +24,16 @@ impl<'a> Converter<'a> {
         self.resolve
             .packages
             .iter()
-            .map(|(_, p)| self.convert_package(p))
+            .map(|(p_id, p)| self.convert_package(p_id, p))
             .collect()
     }
 
-    fn convert_package(&self, package: &wit_parser::Package) -> Package {
+    fn convert_package(&self, package_id: PackageId, package: &wit_parser::Package) -> Package {
         let mut output = Package::new(self.convert_package_name(&package.name));
         for (_, id) in &package.interfaces {
             let interface = self.resolve.interfaces.get(*id).unwrap();
             output.interface(self.convert_interface(
+                package_id,
                 interface,
                 None,
                 wit_parser::TypeOwner::Interface(*id),
@@ -40,7 +41,7 @@ impl<'a> Converter<'a> {
         }
         for (_, id) in &package.worlds {
             let world = self.resolve.worlds.get(*id).unwrap();
-            output.world(self.convert_world(world, wit_parser::TypeOwner::World(*id)));
+            output.world(self.convert_world(package_id, world, wit_parser::TypeOwner::World(*id)));
         }
         output
     }
@@ -53,33 +54,30 @@ impl<'a> Converter<'a> {
         )
     }
 
-    fn convert_world(&self, world: &wit_parser::World, owner: wit_parser::TypeOwner) -> World {
+    fn convert_world(
+        &self,
+        package_id: PackageId,
+        world: &wit_parser::World,
+        owner: wit_parser::TypeOwner,
+    ) -> World {
         let mut output = World::new(world.name.clone());
 
         for (key, item) in &world.imports {
             match item {
                 wit_parser::WorldItem::Interface { id, .. } => {
                     let interface = self.resolve.interfaces.get(*id).unwrap();
-                    output.item(match &interface.name {
-                        Some(name) => {
-                            // standalone
-                            WorldItem::named_interface_import(name.clone())
-                        }
-                        None => {
-                            // inlined
-                            let name = match key {
-                                wit_parser::WorldKey::Name(name) => name.clone(),
-                                wit_parser::WorldKey::Interface(_) => {
-                                    unreachable!("inlined interface must have a kye name")
-                                }
-                            };
-                            WorldItem::inline_interface_import(self.convert_interface(
-                                interface,
-                                Some(name),
-                                owner,
-                            ))
-                        }
-                    });
+                    let ident = self.interface_ident(package_id, Some(key), interface);
+
+                    if interface.name.is_some() {
+                        output.item(WorldItem::named_interface_import(ident))
+                    } else {
+                        output.item(WorldItem::inline_interface_import(self.convert_interface(
+                            package_id,
+                            interface,
+                            Some(ident),
+                            owner,
+                        )))
+                    }
                 }
                 wit_parser::WorldItem::Function(func) => {
                     if let Some(func) = self.standalone_func_convert(func) {
@@ -95,26 +93,17 @@ impl<'a> Converter<'a> {
             match item {
                 wit_parser::WorldItem::Interface { id, .. } => {
                     let interface = self.resolve.interfaces.get(*id).unwrap();
-                    output.item(match &interface.name {
-                        Some(name) => {
-                            // standalone
-                            WorldItem::named_interface_export(name.clone())
-                        }
-                        None => {
-                            // inlined
-                            let name = match key {
-                                wit_parser::WorldKey::Name(name) => name.clone(),
-                                wit_parser::WorldKey::Interface(_) => {
-                                    unreachable!("inlined interface must have a kye name")
-                                }
-                            };
-                            WorldItem::inline_interface_export(self.convert_interface(
-                                interface,
-                                Some(name),
-                                owner,
-                            ))
-                        }
-                    });
+                    let ident = self.interface_ident(package_id, Some(key), interface);
+                    if interface.name.is_some() {
+                        output.item(WorldItem::named_interface_export(ident));
+                    } else {
+                        output.item(WorldItem::inline_interface_export(self.convert_interface(
+                            package_id,
+                            interface,
+                            Some(ident),
+                            owner,
+                        )));
+                    }
                 }
                 wit_parser::WorldItem::Function(func) => {
                     if let Some(func) = self.standalone_func_convert(func) {
@@ -132,15 +121,17 @@ impl<'a> Converter<'a> {
 
     fn convert_interface(
         &self,
+        package_id: PackageId,
         interface: &wit_parser::Interface,
-        inlined_name: Option<String>,
+        inlined_name: Option<Ident>,
         owner: wit_parser::TypeOwner,
     ) -> Interface {
-        let mut output = Interface::new(interface.name.clone().unwrap_or_else(|| {
-            inlined_name
-                .clone()
-                .expect("inlined interface must pass in inlined_name")
-        }));
+        let mut output =
+            Interface::new(interface.name.clone().map(Ident::new).unwrap_or_else(|| {
+                inlined_name
+                    .clone()
+                    .expect("inlined interface must pass in inlined_name")
+            }));
 
         for (_, func) in &interface.functions {
             if let Some(func) = self.standalone_func_convert(func) {
@@ -166,24 +157,21 @@ impl<'a> Converter<'a> {
                     output.item(InterfaceItem::TypeDef(type_def));
                 }
             } else {
-                let interface_name = match underlying_type_def.owner {
-                    wit_parser::TypeOwner::Interface(id) => self
-                        .resolve
-                        .interfaces
-                        .get(id)
-                        .unwrap()
-                        .name
-                        .clone()
-                        .expect("can't use type from inline interface"),
+                let interface_ident = match underlying_type_def.owner {
+                    wit_parser::TypeOwner::Interface(id) => self.interface_ident(
+                        package_id,
+                        None,
+                        self.resolve.interfaces.get(id).unwrap(),
+                    ),
                     _ => panic!("Type not part of an interface"),
                 };
                 let local_type_name = type_def.name.clone().unwrap();
                 let underlying_local_type_name = underlying_type_def.name.clone().unwrap();
                 if underlying_local_type_name == local_type_name {
-                    output.use_type(interface_name, local_type_name, None);
+                    output.use_type(interface_ident, local_type_name, None);
                 } else {
                     output.use_type(
-                        interface_name,
+                        interface_ident,
                         underlying_local_type_name,
                         Some(local_type_name.into()),
                     );
@@ -488,6 +476,51 @@ impl<'a> Converter<'a> {
         }
         output
     }
+
+    fn interface_ident(
+        &self,
+        package_id: PackageId,
+        world_key: Option<&wit_parser::WorldKey>,
+        interface: &wit_parser::Interface,
+    ) -> Ident {
+        match &interface.name {
+            Some(name) => {
+                // Standalone
+                if interface.package == Some(package_id) {
+                    Ident::new(name.clone())
+                } else {
+                    let package = interface
+                        .package
+                        .map(|package_id| self.resolve.packages.get(package_id).unwrap());
+
+                    match package {
+                        Some(package) => Ident::new(format!(
+                            "{}:{}/{}{}",
+                            package.name.namespace,
+                            package.name.name,
+                            name,
+                            package
+                                .name
+                                .version
+                                .as_ref()
+                                .map(|version| format!("@{}", version))
+                                .unwrap_or_else(|| "".to_string())
+                        )),
+                        None => Ident::new(name.clone()),
+                    }
+                }
+            }
+            None => match world_key {
+                Some(world_key) => match world_key {
+                    wit_parser::WorldKey::Name(name) => Ident::new(name.clone()),
+                    wit_parser::WorldKey::Interface(_) => {
+                        unreachable!("inlined interface must have a world key name")
+                    }
+                },
+                None => panic!("inlined interface requires a world key"),
+            },
+        }
+    }
 }
 
 fn clean_func_name(resource_name: &str, method_name: &str) -> String {
diff --git a/crates/wit-encoder/src/world.rs b/crates/wit-encoder/src/world.rs
index f1a66043..2eaeeba8 100644
--- a/crates/wit-encoder/src/world.rs
+++ b/crates/wit-encoder/src/world.rs
@@ -31,7 +31,7 @@ impl World {
         self.name = name.into();
     }
 
-    pub fn name(&mut self) -> &Ident {
+    pub fn name(&self) -> &Ident {
         &self.name
     }
 
@@ -254,7 +254,20 @@ impl WorldNamedInterface {
             docs: None,
         }
     }
-    pub fn docs(&mut self, docs: Option<impl Into<Docs>>) {
+
+    pub fn set_name(&mut self, name: impl Into<Ident>) {
+        self.name = name.into();
+    }
+
+    pub fn name(&self) -> &Ident {
+        &self.name
+    }
+
+    pub fn set_docs(&mut self, docs: Option<impl Into<Docs>>) {
         self.docs = docs.map(|d| d.into());
     }
+
+    pub fn docs(&self) -> Option<&Docs> {
+        self.docs.as_ref()
+    }
 }
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/crates/wit-encoder/tests/deps.rs b/crates/wit-encoder/tests/deps.rs
new file mode 100644
index 00000000..428f17a1
--- /dev/null
+++ b/crates/wit-encoder/tests/deps.rs
@@ -0,0 +1,188 @@
+use anyhow::Result;
+use pretty_assertions::assert_eq;
+use wit_encoder::{packages_from_parsed, Package};
+use wit_parser::Resolve;
+
+const MAIN_PACKAGE_SOURCE: &str = indoc::indoc! {"
+    package foo:main;
+
+    interface main-interface-a {
+      use foo:dep-a/dep-a-interface-b.{ ra };
+    }
+
+    interface main-interface-b {}
+
+    interface main-interface-c {}
+
+    interface main-interface-d {}
+
+    interface main-interface-e {}
+
+    world main-world-a {
+      import foo:dep-c/dep-c-interface-a;
+      export foo:dep-c/dep-c-interface-b;
+      include foo:dep-c/dep-c-world-a;
+
+      import foo:dep-b/dep-b-interface-a@1.2.3;
+      export foo:dep-b/dep-b-interface-b@1.2.3;
+      include foo:dep-b/dep-b-world-b@1.2.3;
+
+      import main-interface-b;
+      export main-interface-a;
+      include main-world-b;
+    }
+
+    world main-world-b {
+      export main-interface-d;
+      import main-interface-d;
+    }
+"};
+
+const MAIN_PACKAGE_RESOLVED_ENCODED: &str = indoc::indoc! {"
+    package foo:main;
+
+    interface main-interface-a {
+      use foo:dep-a/dep-a-interface-b.{ ra };
+    }
+
+    interface main-interface-b {}
+
+    interface main-interface-c {}
+
+    interface main-interface-d {}
+
+    interface main-interface-e {}
+
+    world main-world-b {
+      import main-interface-d;
+      export main-interface-d;
+    }
+
+    world main-world-a {
+      import foo:dep-c/dep-c-interface-a;
+      import foo:dep-b/dep-b-interface-a@1.2.3;
+      import main-interface-b;
+      import foo:dep-c/dep-c-interface-c;
+      import main-interface-d;
+      import foo:dep-a/dep-a-interface-b;
+      export foo:dep-c/dep-c-interface-b;
+      export foo:dep-b/dep-b-interface-b@1.2.3;
+      export main-interface-a;
+      export foo:dep-c/dep-c-interface-d;
+      export main-interface-d;
+    }
+"};
+
+const DEP_PACKAGE_A: &str = indoc::indoc! {"
+    package foo:dep-a;
+
+    interface dep-a-interface-b {
+      use foo:dep-b/dep-b-interface-a@1.2.3.{a};
+      type ra = a;
+    }
+
+    world dep-a-world {}
+"};
+
+const DEP_PACKAGE_B: &str = indoc::indoc! {"
+    package foo:dep-b@1.2.3;
+
+    interface dep-b-interface-a {
+      record a {
+        x: f32,
+        y: f32,
+      }
+    }
+
+    interface dep-b-interface-b {
+      use foo:dep-c/dep-c-interface-a.{a};
+    }
+
+    world dep-b-world-a {
+      export dep-b-interface-a;
+    }
+
+    world dep-b-world-b {}
+"};
+
+const DEP_PACKAGE_C: &str = indoc::indoc! {"
+    package foo:dep-c;
+
+    interface dep-c-interface-a {
+      record a {
+        x: f32,
+        y: f32,
+      }
+    }
+
+    interface dep-c-interface-b {}
+
+    interface dep-c-interface-c {}
+
+    interface dep-c-interface-d {}
+
+    world dep-c-world-a {
+      import dep-c-interface-c;
+      export dep-c-interface-d;
+    }
+"};
+
+#[test]
+fn resolve_encode_resolve_round_trip_with_use_and_include() {
+    let packages = packages_from_parsed(
+        &resolve_packages(&[
+            ("dep_c.wit", DEP_PACKAGE_C),
+            ("dep_b.wit", DEP_PACKAGE_B),
+            ("dep_a.wit", DEP_PACKAGE_A),
+            ("main_foo.wit", MAIN_PACKAGE_SOURCE),
+        ])
+        .unwrap(),
+    );
+
+    assert_eq!(packages.len(), 4);
+
+    assert_package_names(
+        &packages,
+        &["foo:dep-c", "foo:dep-b@1.2.3", "foo:dep-a", "foo:main"],
+    );
+
+    // Resolve should still work after rendering the encoded packages
+    let packages = packages_from_parsed(
+        &resolve_packages(&[
+            ("dep_c.wit", &packages[0].to_string()),
+            ("dep_b.wit", &packages[1].to_string()),
+            ("dep_a.wit", &packages[2].to_string()),
+            ("main_foo.wit", &packages[3].to_string()),
+        ])
+        .unwrap(),
+    );
+
+    // Check that no package is lost
+    assert_package_names(
+        &packages,
+        &["foo:dep-c", "foo:dep-b@1.2.3", "foo:dep-a", "foo:main"],
+    );
+
+    // Check for the encoded main wit
+    assert_eq!(MAIN_PACKAGE_RESOLVED_ENCODED, &packages[3].to_string());
+}
+
+fn resolve_packages(packages: &[(&str, &str)]) -> Result<Resolve> {
+    let mut resolve = Resolve::new();
+    for (name, wit) in packages {
+        resolve.push_str(name, wit)?;
+    }
+    Ok(resolve)
+}
+
+// The order of converted packages currently follows the order of pushes to the parser's package arena.
+// If this changes, then explicit sorting or search should be added to these tests
+fn assert_package_names(packages: &[Package], package_names: &[&str]) {
+    assert_eq!(
+        packages
+            .iter()
+            .map(|p| p.name().to_string())
+            .collect::<Vec<_>>(),
+        package_names
+    );
+}
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))))