Repository: bytecodealliance/wasm-tools
Pull request #1932 (2024-12-03 00:26:54)

Prepare for 2024 edition migration
Rename all `gen` functions/methods/variables/etc to something else. When using upstream crates (e.g. `Rng::gen`) use `r#gen`, otherwise use "generate" or "generator" as appropriately locally throughout the codebase.


Patch:
diff --git a/README.md b/README.md
index 27b7de5b..da0ae828 100644
--- a/README.md
+++ b/README.md
@@ -235,8 +235,8 @@ implemented in this repository as well. These libraries are:
   files and interfaces.
 * [**`wit-component`**](crates/wit-component) - a crate to create components
   from core wasm modules.
-* [**`wasm-metadata`**](crates/wasm-metadata) - a crate to manipulate name and
-  producer metadata (custom sections) in a wasm module or component.
+* [**`wasm-metadata`**](crates/wasm-metadata) - a crate to read and manipulate
+  WebAssembly metadata
 
 It's recommended to use the libraries directly rather than the CLI tooling when
 embedding into a separate project.
diff --git a/crates/wasm-metadata/src/add_metadata.rs b/crates/wasm-metadata/src/add_metadata.rs
index d8c52da4..c2b997e4 100644
--- a/crates/wasm-metadata/src/add_metadata.rs
+++ b/crates/wasm-metadata/src/add_metadata.rs
@@ -14,8 +14,8 @@ pub struct AddMetadata {
     pub name: Option<String>,
 
     /// Add a programming language to the producers section
-    #[cfg_attr(feature = "clap", clap(long, value_name = "NAME"))]
-    pub language: Vec<String>,
+    #[cfg_attr(feature = "clap", clap(long, value_parser = parse_key_value, value_name = "NAME=VERSION"))]
+    pub language: Vec<(String, String)>,
 
     /// Add a tool and its version to the producers section
     #[cfg_attr(feature = "clap", clap(long = "processed-by", value_parser = parse_key_value, value_name="NAME=VERSION"))]
diff --git a/crates/wasm-metadata/src/producers.rs b/crates/wasm-metadata/src/producers.rs
index 3ad47326..ccec57e4 100644
--- a/crates/wasm-metadata/src/producers.rs
+++ b/crates/wasm-metadata/src/producers.rs
@@ -113,8 +113,8 @@ impl Producers {
     /// Construct the fields specified by [`AddMetadata`]
     pub(crate) fn from_meta(add: &AddMetadata) -> Self {
         let mut s = Self::empty();
-        for lang in add.language.iter() {
-            s.add("language", &lang, "");
+        for (lang, version) in add.language.iter() {
+            s.add("language", &lang, &version);
         }
         for (name, version) in add.processed_by.iter() {
             s.add("processed-by", &name, &version);
diff --git a/crates/wasm-mutate-stats/src/bin/wasm-mutate-stats.rs b/crates/wasm-mutate-stats/src/bin/wasm-mutate-stats.rs
index 4fd56881..be3ee752 100644
--- a/crates/wasm-mutate-stats/src/bin/wasm-mutate-stats.rs
+++ b/crates/wasm-mutate-stats/src/bin/wasm-mutate-stats.rs
@@ -480,7 +480,7 @@ impl State {
         let wasmcp = wasm.clone();
 
         while !self.timeout_reached.load(Relaxed) {
-            let seed = rng.gen();
+            let seed = rng.r#gen();
             wasmmutate.seed(seed);
             wasmmutate.fuel(1000);
             wasmmutate.preserve_semantics(true);
diff --git a/crates/wasm-mutate/src/lib.rs b/crates/wasm-mutate/src/lib.rs
index 6cbbab56..f0a501b7 100644
--- a/crates/wasm-mutate/src/lib.rs
+++ b/crates/wasm-mutate/src/lib.rs
@@ -296,7 +296,7 @@ impl<'wasm> WasmMutate<'wasm> {
         // Next a length of the replacement is chosen. Note that the replacement
         // is always smaller than the input if reduction is requested, otherwise
         // we choose some arbitrary length of bytes to insert.
-        let max_size = if self.reduce || self.rng().gen() {
+        let max_size = if self.reduce || self.rng().r#gen() {
             0
         } else {
             max_size
diff --git a/crates/wasm-mutate/src/mutators/modify_const_exprs.rs b/crates/wasm-mutate/src/mutators/modify_const_exprs.rs
index 8051e73a..25f3d132 100644
--- a/crates/wasm-mutate/src/mutators/modify_const_exprs.rs
+++ b/crates/wasm-mutate/src/mutators/modify_const_exprs.rs
@@ -112,7 +112,7 @@ impl<'cfg, 'wasm> Reencode for InitTranslator<'cfg, 'wasm> {
         // removing the offset) as other values may not necessarily be valid
         // (e.g. maximum table size is limited)
         let is_element_offset = matches!(self.kind, ConstExpressionMutator::ElementOffset);
-        let should_zero = is_element_offset || self.config.rng().gen::<u8>() & 0b11 == 0;
+        let should_zero = is_element_offset || self.config.rng().r#gen::<u8>() & 0b11 == 0;
         let new_op = match ty {
             T::I32 if should_zero => CE::i32_const(0),
             T::I64 if should_zero => CE::i64_const(0),
@@ -123,28 +123,28 @@ impl<'cfg, 'wasm> Reencode for InitTranslator<'cfg, 'wasm> {
                 let range = if value < 0 { value..0 } else { 0..value };
                 self.config.rng().gen_range(range)
             } else {
-                self.config.rng().gen()
+                self.config.rng().r#gen()
             }),
             T::I64 => CE::i64_const(if let O::I64Const { value } = op {
                 let range = if value < 0 { value..0 } else { 0..value };
                 self.config.rng().gen_range(range)
             } else {
-                self.config.rng().gen()
+                self.config.rng().r#gen()
             }),
             T::V128 => CE::v128_const(if let O::V128Const { value } = op {
                 self.config.rng().gen_range(0..value.i128() as u128) as i128
             } else {
-                self.config.rng().gen()
+                self.config.rng().r#gen()
             }),
             T::F32 => CE::f32_const(if let O::F32Const { value } = op {
                 f32::from_bits(value.bits()) / 2.0
             } else {
-                f32::from_bits(self.config.rng().gen())
+                f32::from_bits(self.config.rng().r#gen())
             }),
             T::F64 => CE::f64_const(if let O::F64Const { value } = op {
                 f64::from_bits(value.bits()) / 2.0
             } else {
-                f64::from_bits(self.config.rng().gen())
+                f64::from_bits(self.config.rng().r#gen())
             }),
             T::FuncRef => CE::ref_null(wasm_encoder::HeapType::FUNC),
             T::ExternRef => CE::ref_null(wasm_encoder::HeapType::EXTERN),
diff --git a/crates/wasm-mutate/src/mutators/peephole.rs b/crates/wasm-mutate/src/mutators/peephole.rs
index 75ede341..ad14a99b 100644
--- a/crates/wasm-mutate/src/mutators/peephole.rs
+++ b/crates/wasm-mutate/src/mutators/peephole.rs
@@ -244,7 +244,7 @@ impl PeepholeMutator {
                     root,
                     egraph.clone(),
                     self.max_tree_depth,
-                    config.rng().gen(),
+                    config.rng().r#gen(),
                 ));
 
                 // Filter expression equal to the original one
diff --git a/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder/expr2wasm.rs b/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder/expr2wasm.rs
index f50049ae..aab1cf7f 100644
--- a/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder/expr2wasm.rs
+++ b/crates/wasm-mutate/src/mutators/peephole/eggsy/encoder/expr2wasm.rs
@@ -116,16 +116,16 @@ pub fn expr2wasm(
                     Lang::I64Load16S(memarg, _) => insn(Instruction::I64Load16S(memarg.into())),
                     Lang::I64Load32U(memarg, _) => insn(Instruction::I64Load32U(memarg.into())),
                     Lang::I64Load32S(memarg, _) => insn(Instruction::I64Load32S(memarg.into())),
-                    Lang::RandI32 => insn(Instruction::I32Const(config.rng().gen())),
-                    Lang::RandI64 => insn(Instruction::I64Const(config.rng().gen())),
+                    Lang::RandI32 => insn(Instruction::I32Const(config.rng().r#gen())),
+                    Lang::RandI64 => insn(Instruction::I64Const(config.rng().r#gen())),
                     Lang::RandF32 => {
                         newfunc.instruction(&Instruction::F32Const(f32::from_bits(
-                            config.rng().gen(),
+                            config.rng().r#gen(),
                         )));
                     }
                     Lang::RandF64 => {
                         newfunc.instruction(&Instruction::F64Const(f64::from_bits(
-                            config.rng().gen(),
+                            config.rng().r#gen(),
                         )));
                     }
                     Lang::Undef => { /* Do nothig */ }
@@ -135,7 +135,7 @@ pub fn expr2wasm(
                             Lang::I32(value) => {
                                 // Getting type from eclass.
 
-                                let r: i32 = config.rng().gen();
+                                let r: i32 = config.rng().r#gen();
                                 insn(Instruction::I32Const(r));
                                 insn(Instruction::I32Const(
                                     (Wrapping(*value as i32) - Wrapping(r)).0,
@@ -156,7 +156,7 @@ pub fn expr2wasm(
                             Lang::I64(value) => {
                                 // Getting type from eclass.
 
-                                let r: i64 = config.rng().gen();
+                                let r: i64 = config.rng().r#gen();
                                 insn(Instruction::I64Const(r));
                                 insn(Instruction::I64Const((Wrapping(*value) - Wrapping(r)).0));
                                 insn(Instruction::I64Add);
diff --git a/crates/wasm-shrink/src/lib.rs b/crates/wasm-shrink/src/lib.rs
index fc821952..06e24a30 100755
--- a/crates/wasm-shrink/src/lib.rs
+++ b/crates/wasm-shrink/src/lib.rs
@@ -294,7 +294,7 @@ impl ShrinkRun {
             self.attempt += 1;
 
             let mut mutate = WasmMutate::default();
-            let seed = self.rng.gen();
+            let seed = self.rng.r#gen();
             mutate.reduce(true).seed(seed);
             log::trace!("Attempt #{}: seed: {}", self.attempt, seed);
 
diff --git a/crates/wast/src/component/expand.rs b/crates/wast/src/component/expand.rs
index 0f461578..11ada7bd 100644
--- a/crates/wast/src/component/expand.rs
+++ b/crates/wast/src/component/expand.rs
@@ -490,7 +490,7 @@ impl<'a> Expander<'a> {
                         t.index = Some(*idx);
                         return;
                     }
-                    let id = gensym::gen(item.span);
+                    let id = gensym::generate(item.span);
                     to_prepend.push(ModuleTypeDecl::Type(core::Type {
                         span: item.span,
                         id: Some(id),
@@ -612,7 +612,7 @@ impl<'a> Expander<'a> {
         // And if this type isn't already defined we append it to the index
         // space with a fresh and unique name.
         let span = Span::from_offset(0); // FIXME(#613): don't manufacture
-        let id = gensym::gen(span);
+        let id = gensym::generate(span);
 
         self.types_to_prepend.push(inline.into_any_type(span, id));
 
@@ -658,7 +658,7 @@ impl<'a> Expander<'a> {
 
         // And if this type isn't already defined we append it to the index
         // space with a fresh and unique name.
-        let id = gensym::gen(span);
+        let id = gensym::generate(span);
 
         self.types_to_prepend.push(inline.into_any_type(span, id));
 
@@ -711,7 +711,7 @@ impl<'a> Expander<'a> {
 
         // And if this type isn't already defined we append it to the index
         // space with a fresh and unique name.
-        let id = gensym::gen(span);
+        let id = gensym::generate(span);
 
         self.types_to_prepend.push(inline.into_any_type(span, id));
 
@@ -731,7 +731,7 @@ impl<'a> Expander<'a> {
             CoreInstantiationArgKind::Instance(_) => return,
             CoreInstantiationArgKind::BundleOfExports(span, exports) => (*span, mem::take(exports)),
         };
-        let id = gensym::gen(span);
+        let id = gensym::generate(span);
         self.component_fields_to_prepend
             .push(ComponentField::CoreInstance(CoreInstance {
                 span,
@@ -751,7 +751,7 @@ impl<'a> Expander<'a> {
             InstantiationArgKind::Item(_) => return,
             InstantiationArgKind::BundleOfExports(span, exports) => (*span, mem::take(exports)),
         };
-        let id = gensym::gen(span);
+        let id = gensym::generate(span);
         self.component_fields_to_prepend
             .push(ComponentField::Instance(Instance {
                 span,
diff --git a/crates/wast/src/core/resolve/names.rs b/crates/wast/src/core/resolve/names.rs
index e3dcf9b5..4d9450fc 100644
--- a/crates/wast/src/core/resolve/names.rs
+++ b/crates/wast/src/core/resolve/names.rs
@@ -681,14 +681,11 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
     fn resolve_resume_table(&self, table: &mut ResumeTable<'a>) -> Result<(), Error> {
         for handle in &mut table.handlers {
             match handle {
-                Handle::OnLabel {
-                    ref mut tag,
-                    ref mut label,
-                } => {
+                Handle::OnLabel { tag, label } => {
                     self.resolver.resolve(tag, Ns::Tag)?;
                     self.resolve_label(label)?;
                 }
-                Handle::OnSwitch { ref mut tag } => {
+                Handle::OnSwitch { tag } => {
                     self.resolver.resolve(tag, Ns::Tag)?;
                 }
             }
diff --git a/crates/wast/src/core/resolve/types.rs b/crates/wast/src/core/resolve/types.rs
index 3f62eb89..7a7e36c9 100644
--- a/crates/wast/src/core/resolve/types.rs
+++ b/crates/wast/src/core/resolve/types.rs
@@ -209,7 +209,7 @@ impl<'a> Expander<'a> {
         }
 
         // ... and failing that we insert a new type definition.
-        let id = gensym::gen(span);
+        let id = gensym::generate(span);
         self.to_prepend.push(ModuleField::Type(Type {
             span,
             id: Some(id),
diff --git a/crates/wast/src/gensym.rs b/crates/wast/src/gensym.rs
index 9f718f06..23db7fa7 100644
--- a/crates/wast/src/gensym.rs
+++ b/crates/wast/src/gensym.rs
@@ -7,14 +7,14 @@ pub fn reset() {
     NEXT.with(|c| c.set(0));
 }
 
-pub fn gen(span: Span) -> Id<'static> {
+pub fn generate(span: Span) -> Id<'static> {
     NEXT.with(|next| {
-        let gen = next.get() + 1;
-        next.set(gen);
-        Id::gensym(span, gen)
+        let generation = next.get() + 1;
+        next.set(generation);
+        Id::gensym(span, generation)
     })
 }
 
 pub fn fill<'a>(span: Span, slot: &mut Option<Id<'a>>) -> Id<'a> {
-    *slot.get_or_insert_with(|| gen(span))
+    *slot.get_or_insert_with(|| generate(span))
 }
diff --git a/crates/wast/src/token.rs b/crates/wast/src/token.rs
index c59d834c..be6c6ac6 100644
--- a/crates/wast/src/token.rs
+++ b/crates/wast/src/token.rs
@@ -53,7 +53,7 @@ impl Span {
 #[derive(Copy, Clone)]
 pub struct Id<'a> {
     name: &'a str,
-    gen: u32,
+    generation: u32,
     span: Span,
 }
 
@@ -63,14 +63,18 @@ impl<'a> Id<'a> {
     /// Note that `name` can be any arbitrary string according to the
     /// WebAssembly/annotations proposal.
     pub fn new(name: &'a str, span: Span) -> Id<'a> {
-        Id { name, gen: 0, span }
+        Id {
+            name,
+            generation: 0,
+            span,
+        }
     }
 
     #[cfg(feature = "wasm-module")]
-    pub(crate) fn gensym(span: Span, gen: u32) -> Id<'a> {
+    pub(crate) fn gensym(span: Span, generation: u32) -> Id<'a> {
         Id {
             name: "gensym",
-            gen,
+            generation,
             span,
         }
     }
@@ -89,20 +93,20 @@ impl<'a> Id<'a> {
 
     #[cfg(feature = "wasm-module")]
     pub(crate) fn is_gensym(&self) -> bool {
-        self.gen != 0
+        self.generation != 0
     }
 }
 
 impl<'a> Hash for Id<'a> {
     fn hash<H: Hasher>(&self, hasher: &mut H) {
         self.name.hash(hasher);
-        self.gen.hash(hasher);
+        self.generation.hash(hasher);
     }
 }
 
 impl<'a> PartialEq for Id<'a> {
     fn eq(&self, other: &Id<'a>) -> bool {
-        self.name == other.name && self.gen == other.gen
+        self.name == other.name && self.generation == other.generation
     }
 }
 
@@ -115,7 +119,7 @@ impl<'a> Parse<'a> for Id<'a> {
                 return Ok((
                     Id {
                         name,
-                        gen: 0,
+                        generation: 0,
                         span: c.cur_span(),
                     },
                     rest,
@@ -128,8 +132,10 @@ impl<'a> Parse<'a> for Id<'a> {
 
 impl fmt::Debug for Id<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if self.gen != 0 {
-            f.debug_struct("Id").field("gen", &self.gen).finish()
+        if self.generation != 0 {
+            f.debug_struct("Id")
+                .field("generation", &self.generation)
+                .finish()
         } else {
             self.name.fmt(f)
         }
diff --git a/crates/wit-smith/src/generate.rs b/crates/wit-smith/src/generate.rs
index 41c5c5c1..c6d5d49f 100644
--- a/crates/wit-smith/src/generate.rs
+++ b/crates/wit-smith/src/generate.rs
@@ -20,7 +20,7 @@ type InterfaceList = IndexMap<String, FileInterface>;
 type PackageList = Vec<(PackageName, InterfaceList)>;
 
 struct InterfaceGenerator<'a> {
-    gen: &'a Generator,
+    generator: &'a Generator,
     file: &'a mut File,
     config: &'a Config,
     unique_names: HashSet<String>,
@@ -55,7 +55,7 @@ impl Generator {
         }
     }
 
-    pub fn gen(&mut self, u: &mut Unstructured<'_>) -> Result<Vec<Package>> {
+    pub fn generate(&mut self, u: &mut Unstructured<'_>) -> Result<Vec<Package>> {
         let mut packages = Vec::new();
         let mut names = HashSet::new();
         while packages.len() < self.config.max_packages && packages.is_empty() {
@@ -129,13 +129,13 @@ impl Generator {
 
             // Only generate Use/Done if we've already generated a world or interface. This ensures
             // that we never generate empty packages, which aren't representable.
-            let gen = if empty {
+            let generate = if empty {
                 u.choose(&[Generate::World, Generate::Interface])?.clone()
             } else {
                 u.arbitrary()?
             };
 
-            match gen {
+            match generate {
                 Generate::World => {
                     let name = file.gen_unique_package_name(u, &mut package_names)?;
                     log::debug!("new world `{name}` in {i}");
@@ -258,9 +258,9 @@ impl Generator {
         name: Option<&str>,
         file: &mut File,
     ) -> Result<(String, TypeList)> {
-        let mut gen = InterfaceGenerator::new(self, file);
-        let ret = gen.gen_interface(u, name)?;
-        Ok((ret, gen.types_in_interface))
+        let mut generator = InterfaceGenerator::new(self, file);
+        let ret = generator.gen_interface(u, name)?;
+        Ok((ret, generator.types_in_interface))
     }
 
     fn gen_path<'a>(
@@ -317,11 +317,11 @@ impl Generator {
 }
 
 impl<'a> InterfaceGenerator<'a> {
-    fn new(gen: &'a Generator, file: &'a mut File) -> InterfaceGenerator<'a> {
+    fn new(generator: &'a Generator, file: &'a mut File) -> InterfaceGenerator<'a> {
         InterfaceGenerator {
-            gen,
+            generator,
             file,
-            config: &gen.config,
+            config: &generator.config,
             types_in_interface: Vec::new(),
             // Claim the name `memory` to avoid conflicting with the canonical
             // ABI always using a linear memory named `memory`.
@@ -454,7 +454,7 @@ impl<'a> InterfaceGenerator<'a> {
                     self.gen_func_sig(u, &mut part, false)?;
                 }
                 ItemKind::Interface(dir) => {
-                    let id = match self.gen.gen_path(u, self.file, &mut part)? {
+                    let id = match self.generator.gen_path(u, self.file, &mut part)? {
                         Some((_name, id, _types)) => id,
                         // If an interface couldn't be chosen or wasn't
                         // chosen then skip this import. A unique name was
@@ -477,8 +477,8 @@ impl<'a> InterfaceGenerator<'a> {
                     part.push_str(";");
                 }
                 ItemKind::AnonInterface(_) => {
-                    let iface =
-                        InterfaceGenerator::new(self.gen, self.file).gen_interface(u, None)?;
+                    let iface = InterfaceGenerator::new(self.generator, self.file)
+                        .gen_interface(u, None)?;
                     part.push_str(&iface);
                 }
 
@@ -572,7 +572,7 @@ impl<'a> InterfaceGenerator<'a> {
 
     fn gen_use(&mut self, u: &mut Unstructured<'_>, part: &mut String) -> Result<bool> {
         let mut path = String::new();
-        let (_name, _id, types) = match self.gen.gen_path(u, self.file, &mut path)? {
+        let (_name, _id, types) = match self.generator.gen_path(u, self.file, &mut path)? {
             Some(types) => types,
             None => return Ok(false),
         };
diff --git a/crates/wit-smith/src/lib.rs b/crates/wit-smith/src/lib.rs
index 10e75354..73e6df68 100644
--- a/crates/wit-smith/src/lib.rs
+++ b/crates/wit-smith/src/lib.rs
@@ -17,7 +17,7 @@ mod generate;
 /// The `config` guides the generation of the document and the `u` bytes are
 /// used as input to construct the document.
 pub fn smith(config: &Config, u: &mut Unstructured<'_>) -> Result<Vec<u8>> {
-    let pkgs = generate::Generator::new(config.clone()).gen(u)?;
+    let pkgs = generate::Generator::new(config.clone()).generate(u)?;
     let mut resolve = Resolve::default();
     let mut last = None;
     for pkg in pkgs {


Test patch:
diff --git a/crates/wasm-metadata/tests/component.rs b/crates/wasm-metadata/tests/component.rs
index 6c2c3f3e..beda10a3 100644
--- a/crates/wasm-metadata/tests/component.rs
+++ b/crates/wasm-metadata/tests/component.rs
@@ -8,7 +8,7 @@ fn add_to_empty_component() {
     let component = Component::new().finish();
     let add = AddMetadata {
         name: Some("foo".to_owned()),
-        language: vec!["bar".to_owned()],
+        language: vec![("bar".to_owned(), "1.0".to_owned())],
         processed_by: vec![("baz".to_owned(), "1.0".to_owned())],
         sdk: vec![],
         registry_metadata: Some(RegistryMetadata {
@@ -48,7 +48,10 @@ fn add_to_empty_component() {
             assert!(children.is_empty());
             assert_eq!(name, Some("foo".to_owned()));
             let producers = producers.expect("some producers");
-            assert_eq!(producers.get("language").unwrap().get("bar").unwrap(), "");
+            assert_eq!(
+                producers.get("language").unwrap().get("bar").unwrap(),
+                "1.0"
+            );
             assert_eq!(
                 producers.get("processed-by").unwrap().get("baz").unwrap(),
                 "1.0"
@@ -96,7 +99,7 @@ fn add_to_empty_component() {
             );
 
             assert_eq!(range.start, 0);
-            assert_eq!(range.end, 432);
+            assert_eq!(range.end, 435);
         }
         _ => panic!("metadata should be component"),
     }
@@ -108,7 +111,7 @@ fn add_to_nested_component() {
     let module = Module::new().finish();
     let add = AddMetadata {
         name: Some("foo".to_owned()),
-        language: vec!["bar".to_owned()],
+        language: vec![("bar".to_owned(), "1.0".to_owned())],
         processed_by: vec![("baz".to_owned(), "1.0".to_owned())],
         sdk: vec![],
         registry_metadata: Some(RegistryMetadata {
@@ -161,7 +164,10 @@ fn add_to_nested_component() {
                 } => {
                     assert_eq!(name, &Some("foo".to_owned()));
                     let producers = producers.as_ref().expect("some producers");
-                    assert_eq!(producers.get("language").unwrap().get("bar").unwrap(), "");
+                    assert_eq!(
+                        producers.get("language").unwrap().get("bar").unwrap(),
+                        "1.0"
+                    );
                     assert_eq!(
                         producers.get("processed-by").unwrap().get("baz").unwrap(),
                         "1.0"
@@ -174,7 +180,7 @@ fn add_to_nested_component() {
                     );
 
                     assert_eq!(range.start, 10);
-                    assert_eq!(range.end, 120);
+                    assert_eq!(range.end, 123);
                 }
                 _ => panic!("child is a module"),
             }
diff --git a/crates/wasm-metadata/tests/module.rs b/crates/wasm-metadata/tests/module.rs
index d25014fc..a1b95bc9 100644
--- a/crates/wasm-metadata/tests/module.rs
+++ b/crates/wasm-metadata/tests/module.rs
@@ -8,7 +8,7 @@ fn add_to_empty_module() {
     let module = Module::new().finish();
     let add = AddMetadata {
         name: Some("foo".to_owned()),
-        language: vec!["bar".to_owned()],
+        language: vec![("bar".to_owned(), "1.0".to_owned())],
         processed_by: vec![("baz".to_owned(), "1.0".to_owned())],
         sdk: vec![],
         registry_metadata: Some(RegistryMetadata {
@@ -46,7 +46,10 @@ fn add_to_empty_module() {
         } => {
             assert_eq!(name, Some("foo".to_owned()));
             let producers = producers.expect("some producers");
-            assert_eq!(producers.get("language").unwrap().get("bar").unwrap(), "");
+            assert_eq!(
+                producers.get("language").unwrap().get("bar").unwrap(),
+                "1.0"
+            );
             assert_eq!(
                 producers.get("processed-by").unwrap().get("baz").unwrap(),
                 "1.0"
@@ -94,7 +97,7 @@ fn add_to_empty_module() {
             );
 
             assert_eq!(range.start, 0);
-            assert_eq!(range.end, 422);
+            assert_eq!(range.end, 425);
         }
         _ => panic!("metadata should be module"),
     }
diff --git a/tests/cli/add-metadata-merge-sections.wat b/tests/cli/add-metadata-merge-sections.wat
index b5a8115c..7ad17943 100644
--- a/tests/cli/add-metadata-merge-sections.wat
+++ b/tests/cli/add-metadata-merge-sections.wat
@@ -1,2 +1,2 @@
-;; RUN: metadata add --language foo % | metadata add --language bar | metadata add --sdk foo=2 | metadata show
+;; RUN: metadata add --language foo=3 % | metadata add --language bar=1 | metadata add --sdk foo=2 | metadata show
 (module)
diff --git a/tests/cli/add-metadata-merge-sections.wat.stdout b/tests/cli/add-metadata-merge-sections.wat.stdout
index 4ad91a0d..7ce7a97b 100644
--- a/tests/cli/add-metadata-merge-sections.wat.stdout
+++ b/tests/cli/add-metadata-merge-sections.wat.stdout
@@ -1,6 +1,6 @@
 module:
     language:
-        foo
-        bar
+        foo: 3
+        bar: 1
     sdk:
         foo: 2
diff --git a/tests/cli/add-metadata.wat b/tests/cli/add-metadata.wat
index 857097f3..c3130e96 100644
--- a/tests/cli/add-metadata.wat
+++ b/tests/cli/add-metadata.wat
@@ -1,2 +1,2 @@
-;; RUN: metadata add % --name foo --language bar --processed-by baz=1 --sdk my-sdk=2 | metadata show
+;; RUN: metadata add % --name foo --language bar=1 --processed-by baz=1 --sdk my-sdk=2 | metadata show
 (module)
diff --git a/tests/cli/add-metadata.wat.stdout b/tests/cli/add-metadata.wat.stdout
index 681eadab..775d0001 100644
--- a/tests/cli/add-metadata.wat.stdout
+++ b/tests/cli/add-metadata.wat.stdout
@@ -1,6 +1,6 @@
 module foo:
     language:
-        bar
+        bar: 1
     processed-by:
         baz: 1
     sdk:
diff --git a/tests/cli/metadata-add-component.wat b/tests/cli/metadata-add-component.wat
index b7ba818b..c1ad93c6 100644
--- a/tests/cli/metadata-add-component.wat
+++ b/tests/cli/metadata-add-component.wat
@@ -1,4 +1,4 @@
-;; RUN: metadata add --language foo % | metadata show
+;; RUN: metadata add --language foo=1 % | metadata show
 (component $foo
   (core module
     (func $foo)
diff --git a/tests/cli/metadata-add-component.wat.stdout b/tests/cli/metadata-add-component.wat.stdout
index d98df53e..d099bd0b 100644
--- a/tests/cli/metadata-add-component.wat.stdout
+++ b/tests/cli/metadata-add-component.wat.stdout
@@ -1,4 +1,4 @@
 component foo:
     language:
-        foo
+        foo: 1
     module: