From cd886fe6d7df851ad159391a7d7f9e586ac21f1f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Sep 2024 12:01:52 -0500 Subject: [PATCH 01/18] Fix build with latest nightly (#1752) Fix some warnings related to a new lint cropping up on nightly. --- crates/wasmparser/src/readers/core/init.rs | 2 +- crates/wast/src/component/component.rs | 2 +- crates/wast/src/component/import.rs | 49 +++++++++++----------- crates/wast/src/core/expr.rs | 2 +- crates/wast/src/core/module.rs | 2 +- 5 files changed, 29 insertions(+), 28 deletions(-) diff --git a/crates/wasmparser/src/readers/core/init.rs b/crates/wasmparser/src/readers/core/init.rs index fe61eb0fa0..f14e31051a 100644 --- a/crates/wasmparser/src/readers/core/init.rs +++ b/crates/wasmparser/src/readers/core/init.rs @@ -32,7 +32,7 @@ impl Eq for ConstExpr<'_> {} impl<'a> ConstExpr<'a> { /// Constructs a new `ConstExpr` from the given data and offset. - pub fn new(reader: BinaryReader<'a>) -> ConstExpr { + pub fn new(reader: BinaryReader<'a>) -> ConstExpr<'a> { ConstExpr { reader } } diff --git a/crates/wast/src/component/component.rs b/crates/wast/src/component/component.rs index 92814db0e7..1660a8740f 100644 --- a/crates/wast/src/component/component.rs +++ b/crates/wast/src/component/component.rs @@ -157,7 +157,7 @@ pub enum ComponentField<'a> { } impl<'a> ComponentField<'a> { - fn parse_remaining(parser: Parser<'a>) -> Result> { + fn parse_remaining(parser: Parser<'a>) -> Result>> { let mut fields = Vec::new(); while !parser.is_empty() { fields.push(parser.parens(ComponentField::parse)?); diff --git a/crates/wast/src/component/import.rs b/crates/wast/src/component/import.rs index 6689f4a765..81c8e5e406 100644 --- a/crates/wast/src/component/import.rs +++ b/crates/wast/src/component/import.rs @@ -80,30 +80,31 @@ impl<'a> Parse<'a> for ItemSigNoName<'a> { fn parse_item_sig<'a>(parser: Parser<'a>, name: bool) -> Result> { let mut l = parser.lookahead1(); - let (span, parse_kind): (_, fn(Parser<'a>) -> Result) = if l.peek::()? { - let span = parser.parse::()?.0; - parser.parse::()?; - (span, |parser| Ok(ItemSigKind::CoreModule(parser.parse()?))) - } else if l.peek::()? { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemSigKind::Func(parser.parse()?))) - } else if l.peek::()? { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemSigKind::Component(parser.parse()?))) - } else if l.peek::()? { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemSigKind::Instance(parser.parse()?))) - } else if l.peek::()? { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemSigKind::Value(parser.parse()?))) - } else if l.peek::()? { - let span = parser.parse::()?.0; - (span, |parser| { - Ok(ItemSigKind::Type(parser.parens(|parser| parser.parse())?)) - }) - } else { - return Err(l.error()); - }; + let (span, parse_kind): (_, fn(Parser<'a>) -> Result>) = + if l.peek::()? { + let span = parser.parse::()?.0; + parser.parse::()?; + (span, |parser| Ok(ItemSigKind::CoreModule(parser.parse()?))) + } else if l.peek::()? { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Func(parser.parse()?))) + } else if l.peek::()? { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Component(parser.parse()?))) + } else if l.peek::()? { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Instance(parser.parse()?))) + } else if l.peek::()? { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Value(parser.parse()?))) + } else if l.peek::()? { + let span = parser.parse::()?.0; + (span, |parser| { + Ok(ItemSigKind::Type(parser.parens(|parser| parser.parse())?)) + }) + } else { + return Err(l.error()); + }; Ok(ItemSig { span, id: if name { parser.parse()? } else { None }, diff --git a/crates/wast/src/core/expr.rs b/crates/wast/src/core/expr.rs index 026a535078..f45619f483 100644 --- a/crates/wast/src/core/expr.rs +++ b/crates/wast/src/core/expr.rs @@ -162,7 +162,7 @@ enum If<'a> { } impl<'a> ExpressionParser<'a> { - fn new(parser: Parser<'a>) -> ExpressionParser { + fn new(parser: Parser<'a>) -> ExpressionParser<'a> { ExpressionParser { raw_instrs: Vec::new(), stack: Vec::new(), diff --git a/crates/wast/src/core/module.rs b/crates/wast/src/core/module.rs index bba4a8dd95..39a60f519c 100644 --- a/crates/wast/src/core/module.rs +++ b/crates/wast/src/core/module.rs @@ -156,7 +156,7 @@ pub enum ModuleField<'a> { } impl<'a> ModuleField<'a> { - pub(crate) fn parse_remaining(parser: Parser<'a>) -> Result> { + pub(crate) fn parse_remaining(parser: Parser<'a>) -> Result>> { let mut fields = Vec::new(); while !parser.is_empty() { fields.push(parser.parens(ModuleField::parse)?); From 8c3346e72d3f5100ed80db2e44e326873a9d2443 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Sep 2024 12:36:44 -0500 Subject: [PATCH 02/18] Fix build of `wast` with randomized layouts (#1751) Move the static assertion about size to a runtime test to enable building with randomized layouts for testing. --- crates/wast/src/lexer.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/wast/src/lexer.rs b/crates/wast/src/lexer.rs index 0fd9a72d64..c1a04deb8f 100644 --- a/crates/wast/src/lexer.rs +++ b/crates/wast/src/lexer.rs @@ -61,9 +61,10 @@ pub struct Token { pub len: u32, } -const _: () = { +#[test] +fn token_is_not_too_big() { assert!(std::mem::size_of::() <= std::mem::size_of::() * 2); -}; +} /// Classification of what was parsed from the input stream. /// From 4a6929b79a07d45fea8f8614760de50ec8099fb8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 4 Sep 2024 09:48:39 -0500 Subject: [PATCH 03/18] Expand the suite of invalid tests (#1754) This commit goes through some of the coverage information for the operator validator for the roundtrip test suite and fills in gaps of modules which are invalid but were previously not tested anywhere. --- crates/wasmparser/src/validator/operators.rs | 48 +-- tests/local/code-after-end.wast | 34 +++ tests/local/exnref/try-table.wast | 10 + tests/local/gc/invalid.wast | 289 ++++++++++++++++++ tests/local/invalid.wast | 10 + .../local/missing-features/gc/shared-any.wast | 8 + .../shared-everything-threads/arrays.wast | 43 +++ .../shared-everything-threads/globals.wast | 60 ++++ .../shared-everything-threads/structs.wast | 43 +++ .../shared-everything-threads/tables.wast | 32 ++ .../snapshots/local/code-after-end.wast.json | 54 ++++ .../local/exnref/try-table.wast.json | 12 + tests/snapshots/local/gc/invalid.wast.json | 178 +++++++++++ .../snapshots/local/gc/invalid.wast/16.print | 11 + .../snapshots/local/gc/invalid.wast/25.print | 9 + tests/snapshots/local/invalid.wast.json | 19 ++ .../missing-features/gc/shared-any.wast.json | 12 + .../arrays.wast.json | 28 ++ .../globals.wast.json | 38 +++ .../globals.wast/28.print | 9 + .../globals.wast/30.print | 10 + .../structs.wast.json | 28 ++ .../tables.wast.json | 21 ++ 23 files changed, 973 insertions(+), 33 deletions(-) create mode 100644 tests/local/code-after-end.wast create mode 100644 tests/local/exnref/try-table.wast create mode 100644 tests/local/invalid.wast create mode 100644 tests/local/missing-features/gc/shared-any.wast create mode 100644 tests/snapshots/local/code-after-end.wast.json create mode 100644 tests/snapshots/local/exnref/try-table.wast.json create mode 100644 tests/snapshots/local/gc/invalid.wast/16.print create mode 100644 tests/snapshots/local/gc/invalid.wast/25.print create mode 100644 tests/snapshots/local/invalid.wast.json create mode 100644 tests/snapshots/local/missing-features/gc/shared-any.wast.json create mode 100644 tests/snapshots/local/shared-everything-threads/globals.wast/28.print create mode 100644 tests/snapshots/local/shared-everything-threads/globals.wast/30.print diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index 2000f8e058..cd94153bb0 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -1472,6 +1472,14 @@ where _ => Either::B(self.results(ty)?), }) } + + fn check_data_segment(&self, data_index: u32) -> Result<()> { + match self.resources.data_count() { + None => bail!(self.offset, "data count section required"), + Some(count) if data_index < count => Ok(()), + Some(_) => bail!(self.offset, "unknown data segment {data_index}"), + } + } } pub fn ty_to_str(ty: ValType) -> &'static str { @@ -1693,12 +1701,8 @@ where for ty in ty.clone().params().iter().rev() { self.pop_operand(Some(*ty))?; } - if ty.results().len() > 0 { - bail!( - self.offset, - "result type expected to be empty for exception" - ); - } + // this should be validated when the tag was defined in the module + debug_assert!(ty.results().is_empty()); self.unreachable()?; Ok(()) } @@ -3757,22 +3761,14 @@ where } fn visit_memory_init(&mut self, segment: u32, mem: u32) -> Self::Output { let ty = self.check_memory_index(mem)?; - match self.resources.data_count() { - None => bail!(self.offset, "data count section required"), - Some(count) if segment < count => {} - Some(_) => bail!(self.offset, "unknown data segment {}", segment), - } + self.check_data_segment(segment)?; self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; Ok(()) } fn visit_data_drop(&mut self, segment: u32) -> Self::Output { - match self.resources.data_count() { - None => bail!(self.offset, "data count section required"), - Some(count) if segment < count => {} - Some(_) => bail!(self.offset, "unknown data segment {}", segment), - } + self.check_data_segment(segment)?; Ok(()) } fn visit_memory_copy(&mut self, dst: u32, src: u32) -> Self::Output { @@ -3820,13 +3816,7 @@ where Ok(()) } fn visit_elem_drop(&mut self, segment: u32) -> Self::Output { - if segment >= self.resources.element_count() { - bail!( - self.offset, - "unknown elem segment {}: segment index out of bounds", - segment - ); - } + self.element_type_at(segment)?; Ok(()) } fn visit_table_copy(&mut self, dst_table: u32, src_table: u32) -> Self::Output { @@ -4222,11 +4212,7 @@ where "type mismatch: array.new_data can only create arrays with numeric and vector elements" ), } - match self.resources.data_count() { - None => bail!(self.offset, "data count section required"), - Some(count) if data_index < count => {} - Some(_) => bail!(self.offset, "unknown data segment {}", data_index), - } + self.check_data_segment(data_index)?; self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ValType::I32))?; self.push_concrete_ref(false, type_index) @@ -4419,11 +4405,7 @@ where "invalid array.init_data: array type is not numeric or vector" ), } - match self.resources.data_count() { - None => bail!(self.offset, "data count section required"), - Some(count) if array_data_index < count => {} - Some(_) => bail!(self.offset, "unknown data segment {}", array_data_index), - } + self.check_data_segment(array_data_index)?; self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ValType::I32))?; diff --git a/tests/local/code-after-end.wast b/tests/local/code-after-end.wast new file mode 100644 index 0000000000..5656e5e94f --- /dev/null +++ b/tests/local/code-after-end.wast @@ -0,0 +1,34 @@ +(assert_invalid + (module + (func end)) + "operators remaining after end of function") + +(assert_invalid + (module + (func end block)) + "operators remaining after end of function") + +(assert_invalid + (module + (func end i32.add)) + "operators remaining after end of function") + +(assert_invalid + (module + (func end unreachable)) + "operators remaining after end of function") + +(assert_invalid + (module + (func end br 0)) + "operators remaining after end of function") + +(assert_invalid + (module + (func end return)) + "operators remaining after end of function") + +(assert_invalid + (module + (func end return_call 0)) + "operators remaining after end of function") diff --git a/tests/local/exnref/try-table.wast b/tests/local/exnref/try-table.wast new file mode 100644 index 0000000000..f416a8b93c --- /dev/null +++ b/tests/local/exnref/try-table.wast @@ -0,0 +1,10 @@ +(assert_invalid + (module + (func + block $l (result anyref) + try_table (catch_all_ref $l) + end + end + ) + ) + "type mismatch: catch_all_ref label must a subtype of (ref exn)") diff --git a/tests/local/gc/invalid.wast b/tests/local/gc/invalid.wast index 3f3342b5aa..20f7727459 100644 --- a/tests/local/gc/invalid.wast +++ b/tests/local/gc/invalid.wast @@ -29,3 +29,292 @@ ) "type mismatch: expected structref, found anyref" ) + +(assert_invalid + (module + (type $t (func)) + (func struct.new $t drop)) + "expected struct type at index 0, found (func ...)") + +(assert_invalid + (module + (type $t (struct)) + (func struct.get $t 100)) + "unknown field: field index out of bounds") + +(assert_invalid + (module + (func struct.get 200 100)) + "unknown type: type index out of bounds") + +(assert_invalid + (module + (type $t (struct)) + (func array.new $t drop)) + "expected array type at index 0, found (struct ...)") + +(assert_invalid + (module + (func array.new 100)) + "unknown type: type index out of bounds") + +(assert_invalid + (module + (type $t (struct)) + (func (type $t))) + "type index 0 is not a function type") + +(assert_invalid + (module + (type $t (struct)) + (func block (type $t) end)) + "expected func type at index 0, found (struct ...)") + +(assert_invalid + (module + (func + block $l + unreachable + br_on_non_null $l + end + ) + ) + "type mismatch: br_on_non_null target has no label types") + +(assert_invalid + (module + (func + block $l (result i32) + unreachable + br_on_non_null $l + end + ) + ) + "type mismatch: br_on_non_null target does not end with heap type") + +(assert_invalid + (module + (type $t (struct (field (ref func)))) + (func + struct.new_default $t + ) + ) + "invalid `struct.new_default`: (ref func) field is not defaultable") + +(assert_invalid + (module + (type $t (struct (field $f i32))) + (func + unreachable + struct.get_u $t $f + ) + ) + "cannot use struct.get_u with non-packed storage types") + +(assert_invalid + (module + (type $t (array (ref func))) + (func + array.new_default $t + ) + ) + "invalid `array.new_default`: (ref func) field is not defaultable") + +(assert_invalid + (module + (type $t (array (ref func))) + (func + i32.const 0 + i32.const 0 + array.new_data $t $d + drop + ) + (data $d "xxx") + ) + "array.new_data can only create arrays with numeric and vector elements") + +(assert_invalid + (module binary + "\00asm" "\01\00\00\00" ;; module header + + "\01\07" ;; type section, 7 bytes + "\02" ;; 2 types + "\5e\7f\00" ;; (type (array i32)) + "\60\00\00" ;; (type (func)) + + "\03\02" ;; func section, 2 bytes + "\01" ;; 1 func + "\01" ;; type 1 + + "\0a\0d" ;; code section, 13 bytes + "\01" ;; 1 count + "\0b" ;; 11-byte function + "\00" ;; no locals + "\41\00" ;; i32.const 0 + "\41\00" ;; i32.const 0 + "\fb\09\00\00" ;; array.new_data 0 0 + "\1a" ;; drop + "\0b" ;; end + + "\0b\06" ;; data section, 6 bytes + "\01" ;; 1 count + "\01" ;; passive + "\03xxx" ;; 3 bytes of data "xxx" + ) + "data count section required") + +;; slightly modified version of the above with a data count section +(module binary + "\00asm" "\01\00\00\00" ;; module header + + "\01\07" ;; type section, 7 bytes + "\02" ;; 2 types + "\5e\7f\00" ;; (type (array i32)) + "\60\00\00" ;; (type (func)) + + "\03\02" ;; func section, 2 bytes + "\01" ;; 1 func + "\01" ;; type 1 + + "\0c\01" ;; data count section, 1 byte + "\01" ;; 1 data + + "\0a\0d" ;; code section, 13 bytes + "\01" ;; 1 count + "\0b" ;; 11-byte function + "\00" ;; no locals + "\41\00" ;; i32.const 0 + "\41\00" ;; i32.const 0 + "\fb\09\00\00" ;; array.new_data 0 0 + "\1a" ;; drop + "\0b" ;; end + + "\0b\06" ;; data section, 6 bytes + "\01" ;; 1 count + "\01" ;; passive + "\03xxx" ;; 3 bytes of data "xxx" +) + +(assert_invalid + (module + (type $t (array i8)) + (func + i32.const 0 + i32.const 0 + array.new_data $t 100 + drop + ) + ) + "unknown data segment 100") + +(assert_invalid + (module + (type $t (array i8)) + (func + i32.const 0 + i32.const 0 + array.new_elem $t $e + drop + ) + (elem $e funcref) + ) + "type mismatch: array.new_elem can only create arrays with reference elements") + +(assert_invalid + (module + (type $t (array (ref any))) + (func + i32.const 0 + i32.const 0 + array.new_elem $t $e + drop + ) + (elem $e funcref) + ) + "invalid array.new_elem instruction: element segment 0 type mismatch: expected (ref any), found funcref") + +(assert_invalid + (module + (type $t1 (array (mut i8))) + (type $t2 (array (mut i16))) + (func + unreachable + array.copy $t1 $t2 + ) + ) + "array types do not match: expected i8, found i16") + +(assert_invalid + (module + (type $t1 (array (mut i16))) + (type $t2 (array (mut i8))) + (func + unreachable + array.copy $t1 $t2 + ) + ) + "array types do not match: expected i16, found i8") + +(assert_invalid + (module + (type $t1 (array (mut i32))) + (type $t2 (array (mut i64))) + (func + unreachable + array.copy $t1 $t2 + ) + ) + "array types do not match: expected i32, found i64") + +(assert_invalid + (module + (type $t1 (array (mut i32))) + (type $t2 (array (mut i8))) + (func + unreachable + array.copy $t1 $t2 + ) + ) + "array types do not match: expected i32, found i8") + +(assert_invalid + (module + (type $t1 (array (mut i8))) + (type $t2 (array (mut i32))) + (func + unreachable + array.copy $t1 $t2 + ) + ) + "array types do not match: expected i8, found i32") + +(module + (type $t1 (array (mut i16))) + (type $t2 (array (mut i16))) + (func + unreachable + array.copy $t1 $t2 + ) +) + +(assert_invalid + (module + (type $t1 (array (mut i8))) + (type $t2 (array (mut i32))) + (func + block + unreachable + br_on_cast_fail 0 anyref anyref + end + ) + ) + "type mismatch: expected a reference type, found nothing") + +(assert_invalid + (module + (table 1 externref) + (func + i32.const 0 + call_indirect + )) + "indirect calls must go through a table with type <= funcref") diff --git a/tests/local/invalid.wast b/tests/local/invalid.wast new file mode 100644 index 0000000000..f793557676 --- /dev/null +++ b/tests/local/invalid.wast @@ -0,0 +1,10 @@ +(assert_invalid + (module + (table 1 funcref) + (func table.init 0 100)) + "unknown elem segment") + +(assert_invalid + (module + (func else)) + "else found outside of an `if` block") diff --git a/tests/local/missing-features/gc/shared-any.wast b/tests/local/missing-features/gc/shared-any.wast new file mode 100644 index 0000000000..ae1de285fe --- /dev/null +++ b/tests/local/missing-features/gc/shared-any.wast @@ -0,0 +1,8 @@ +(assert_invalid + (module + (func + ref.null (shared any) + drop + ) + ) + "shared reference types require the shared-everything-threads proposal") diff --git a/tests/local/shared-everything-threads/arrays.wast b/tests/local/shared-everything-threads/arrays.wast index b545b4458d..2d91dde5d2 100644 --- a/tests/local/shared-everything-threads/arrays.wast +++ b/tests/local/shared-everything-threads/arrays.wast @@ -849,3 +849,46 @@ ) "invalid type" ) + +(assert_invalid + (module + (type $s (shared (array f32))) + (func + unreachable + array.atomic.get seq_cst $s + drop + )) + "invalid type: `array.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`" +) + +(assert_invalid + (module + (type $s (shared (array (ref (shared func))))) + (func + unreachable + array.atomic.get seq_cst $s + drop + )) + "invalid type: `array.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`" +) + +(assert_invalid + (module + (type $s (shared (array i8))) + (func + unreachable + array.atomic.get seq_cst $s + drop + )) + "cannot use array.get with packed storage types" +) + +(assert_invalid + (module + (type $s (shared (array (mut (ref (shared extern)))))) + (func + unreachable + array.atomic.set seq_cst $s + )) + "invalid type: `array.atomic.set` only allows `i8`, `i16`, `i32`, `i64` and subtypes of `anyref`" +) diff --git a/tests/local/shared-everything-threads/globals.wast b/tests/local/shared-everything-threads/globals.wast index 1066fcf406..857a0bda7a 100644 --- a/tests/local/shared-everything-threads/globals.wast +++ b/tests/local/shared-everything-threads/globals.wast @@ -367,3 +367,63 @@ global.atomic.rmw.cmpxchg acq_rel $b) ) +(assert_invalid + (module + (global $g (mut funcref) (ref.null func)) + (func + ref.null func + global.atomic.rmw.xor acq_rel $g + drop + ) + ) + "invalid type: `global.atomic.rmw.*` only allows `i32` and `i64`") + +(assert_invalid + (module + (func + global.atomic.rmw.xor acq_rel 200 + ) + ) + "global index out of bounds") + +(assert_invalid + (module + (global $g (mut funcref) (ref.null func)) + (func + ref.null func + global.atomic.rmw.xchg acq_rel $g + drop + ) + ) + "invalid type: `global.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`") + +(module + (global $g (mut eqref) (ref.null eq)) + (func + ref.null eq + global.atomic.rmw.xchg acq_rel $g + drop + ) +) + +(assert_invalid + (module + (global $g (mut anyref) (ref.null any)) + (func + ref.null any + ref.null any + global.atomic.rmw.cmpxchg acq_rel $g + drop + ) + ) + "invalid type: `global.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`") + +(module + (global $g (mut eqref) (ref.null eq)) + (func + ref.null eq + ref.null eq + global.atomic.rmw.cmpxchg acq_rel $g + drop + ) +) diff --git a/tests/local/shared-everything-threads/structs.wast b/tests/local/shared-everything-threads/structs.wast index 240e1f87ff..da112f7d7c 100644 --- a/tests/local/shared-everything-threads/structs.wast +++ b/tests/local/shared-everything-threads/structs.wast @@ -527,3 +527,46 @@ ) "invalid type" ) + +(assert_invalid + (module + (type $s (shared (struct (field $f f32)))) + (func + unreachable + struct.atomic.get seq_cst $s $f + drop + )) + "invalid type: `struct.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`" +) + +(assert_invalid + (module + (type $s (shared (struct (field $f (ref (shared func)))))) + (func + unreachable + struct.atomic.get seq_cst $s $f + drop + )) + "invalid type: `struct.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`" +) + +(assert_invalid + (module + (type $s (shared (struct (field $f i8)))) + (func + unreachable + struct.atomic.get seq_cst $s $f + drop + )) + "can only use struct `get` with non-packed storage types" +) + +(assert_invalid + (module + (type $s (shared (struct (field $f (mut (ref (shared extern))))))) + (func + unreachable + struct.atomic.set seq_cst $s $f + )) + "invalid type: `struct.atomic.set` only allows `i8`, `i16`, `i32`, `i64` and subtypes of `anyref`" +) diff --git a/tests/local/shared-everything-threads/tables.wast b/tests/local/shared-everything-threads/tables.wast index b733ec4c2b..3a14ff2f4f 100644 --- a/tests/local/shared-everything-threads/tables.wast +++ b/tests/local/shared-everything-threads/tables.wast @@ -172,3 +172,35 @@ local.get $z table.atomic.rmw.cmpxchg seq_cst $a)) "invalid type") + +(assert_invalid + (module + (table 1 funcref) + (func + i32.const 0 + table.atomic.get seq_cst 0 + ) + ) + "invalid type: `table.atomic.get` only allows subtypes of `anyref`") + +(assert_invalid + (module + (table 1 funcref) + (func + i32.const 0 + ref.null func + table.atomic.set seq_cst 0 + ) + ) + "invalid type: `table.atomic.set` only allows subtypes of `anyref`") + +(assert_invalid + (module + (table 1 funcref) + (func + i32.const 0 + ref.null func + table.atomic.rmw.xchg seq_cst 0 + ) + ) + "invalid type: `table.atomic.rmw.xchg` only allows subtypes of `anyref`") diff --git a/tests/snapshots/local/code-after-end.wast.json b/tests/snapshots/local/code-after-end.wast.json new file mode 100644 index 0000000000..4dce353aba --- /dev/null +++ b/tests/snapshots/local/code-after-end.wast.json @@ -0,0 +1,54 @@ +{ + "source_filename": "tests/local/code-after-end.wast", + "commands": [ + { + "type": "assert_invalid", + "line": 2, + "filename": "code-after-end.0.wasm", + "text": "operators remaining after end of function", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 7, + "filename": "code-after-end.1.wasm", + "text": "operators remaining after end of function", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 12, + "filename": "code-after-end.2.wasm", + "text": "operators remaining after end of function", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 17, + "filename": "code-after-end.3.wasm", + "text": "operators remaining after end of function", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 22, + "filename": "code-after-end.4.wasm", + "text": "operators remaining after end of function", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 27, + "filename": "code-after-end.5.wasm", + "text": "operators remaining after end of function", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 32, + "filename": "code-after-end.6.wasm", + "text": "operators remaining after end of function", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/exnref/try-table.wast.json b/tests/snapshots/local/exnref/try-table.wast.json new file mode 100644 index 0000000000..79f3b810df --- /dev/null +++ b/tests/snapshots/local/exnref/try-table.wast.json @@ -0,0 +1,12 @@ +{ + "source_filename": "tests/local/exnref/try-table.wast", + "commands": [ + { + "type": "assert_invalid", + "line": 2, + "filename": "try-table.0.wasm", + "text": "type mismatch: catch_all_ref label must a subtype of (ref exn)", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/gc/invalid.wast.json b/tests/snapshots/local/gc/invalid.wast.json index 715407e667..1ffe11ce2f 100644 --- a/tests/snapshots/local/gc/invalid.wast.json +++ b/tests/snapshots/local/gc/invalid.wast.json @@ -14,6 +14,184 @@ "filename": "invalid.1.wasm", "text": "type mismatch: expected structref, found anyref", "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 34, + "filename": "invalid.2.wasm", + "text": "expected struct type at index 0, found (func ...)", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 40, + "filename": "invalid.3.wasm", + "text": "unknown field: field index out of bounds", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 46, + "filename": "invalid.4.wasm", + "text": "unknown type: type index out of bounds", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 51, + "filename": "invalid.5.wasm", + "text": "expected array type at index 0, found (struct ...)", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 57, + "filename": "invalid.6.wasm", + "text": "unknown type: type index out of bounds", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 62, + "filename": "invalid.7.wasm", + "text": "type index 0 is not a function type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 68, + "filename": "invalid.8.wasm", + "text": "expected func type at index 0, found (struct ...)", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 74, + "filename": "invalid.9.wasm", + "text": "type mismatch: br_on_non_null target has no label types", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 85, + "filename": "invalid.10.wasm", + "text": "type mismatch: br_on_non_null target does not end with heap type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 96, + "filename": "invalid.11.wasm", + "text": "invalid `struct.new_default`: (ref func) field is not defaultable", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 105, + "filename": "invalid.12.wasm", + "text": "cannot use struct.get_u with non-packed storage types", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 115, + "filename": "invalid.13.wasm", + "text": "invalid `array.new_default`: (ref func) field is not defaultable", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 124, + "filename": "invalid.14.wasm", + "text": "array.new_data can only create arrays with numeric and vector elements", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 137, + "filename": "invalid.15.wasm", + "text": "data count section required", + "module_type": "binary" + }, + { + "type": "module", + "line": 167, + "filename": "invalid.16.wasm" + }, + { + "type": "assert_invalid", + "line": 199, + "filename": "invalid.17.wasm", + "text": "unknown data segment 100", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 211, + "filename": "invalid.18.wasm", + "text": "type mismatch: array.new_elem can only create arrays with reference elements", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 224, + "filename": "invalid.19.wasm", + "text": "invalid array.new_elem instruction: element segment 0 type mismatch: expected (ref any), found funcref", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 237, + "filename": "invalid.20.wasm", + "text": "array types do not match: expected i8, found i16", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 248, + "filename": "invalid.21.wasm", + "text": "array types do not match: expected i16, found i8", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 259, + "filename": "invalid.22.wasm", + "text": "array types do not match: expected i32, found i64", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 270, + "filename": "invalid.23.wasm", + "text": "array types do not match: expected i32, found i8", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 281, + "filename": "invalid.24.wasm", + "text": "array types do not match: expected i8, found i32", + "module_type": "binary" + }, + { + "type": "module", + "line": 291, + "filename": "invalid.25.wasm" + }, + { + "type": "assert_invalid", + "line": 301, + "filename": "invalid.26.wasm", + "text": "type mismatch: expected a reference type, found nothing", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 314, + "filename": "invalid.27.wasm", + "text": "indirect calls must go through a table with type <= funcref", + "module_type": "binary" } ] } \ No newline at end of file diff --git a/tests/snapshots/local/gc/invalid.wast/16.print b/tests/snapshots/local/gc/invalid.wast/16.print new file mode 100644 index 0000000000..bea3b7bd00 --- /dev/null +++ b/tests/snapshots/local/gc/invalid.wast/16.print @@ -0,0 +1,11 @@ +(module + (type (;0;) (array i32)) + (type (;1;) (func)) + (func (;0;) (type 1) + i32.const 0 + i32.const 0 + array.new_data 0 0 + drop + ) + (data (;0;) "xxx") +) diff --git a/tests/snapshots/local/gc/invalid.wast/25.print b/tests/snapshots/local/gc/invalid.wast/25.print new file mode 100644 index 0000000000..bfb5305a6a --- /dev/null +++ b/tests/snapshots/local/gc/invalid.wast/25.print @@ -0,0 +1,9 @@ +(module + (type $t1 (;0;) (array (mut i16))) + (type $t2 (;1;) (array (mut i16))) + (type (;2;) (func)) + (func (;0;) (type 2) + unreachable + array.copy $t1 $t2 + ) +) diff --git a/tests/snapshots/local/invalid.wast.json b/tests/snapshots/local/invalid.wast.json new file mode 100644 index 0000000000..8f286c330d --- /dev/null +++ b/tests/snapshots/local/invalid.wast.json @@ -0,0 +1,19 @@ +{ + "source_filename": "tests/local/invalid.wast", + "commands": [ + { + "type": "assert_invalid", + "line": 2, + "filename": "invalid.0.wasm", + "text": "unknown elem segment", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 8, + "filename": "invalid.1.wasm", + "text": "else found outside of an `if` block", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/missing-features/gc/shared-any.wast.json b/tests/snapshots/local/missing-features/gc/shared-any.wast.json new file mode 100644 index 0000000000..c4f2700273 --- /dev/null +++ b/tests/snapshots/local/missing-features/gc/shared-any.wast.json @@ -0,0 +1,12 @@ +{ + "source_filename": "tests/local/missing-features/gc/shared-any.wast", + "commands": [ + { + "type": "assert_invalid", + "line": 2, + "filename": "shared-any.0.wasm", + "text": "shared reference types require the shared-everything-threads proposal", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast.json b/tests/snapshots/local/shared-everything-threads/arrays.wast.json index fb61bec7ac..b4c2426fbd 100644 --- a/tests/snapshots/local/shared-everything-threads/arrays.wast.json +++ b/tests/snapshots/local/shared-everything-threads/arrays.wast.json @@ -487,6 +487,34 @@ "filename": "arrays.86.wasm", "text": "invalid type", "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 854, + "filename": "arrays.87.wasm", + "text": "invalid type: `array.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 865, + "filename": "arrays.88.wasm", + "text": "invalid type: `array.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 876, + "filename": "arrays.89.wasm", + "text": "cannot use array.get with packed storage types", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 887, + "filename": "arrays.90.wasm", + "text": "invalid type: `array.atomic.set` only allows `i8`, `i16`, `i32`, `i64` and subtypes of `anyref`", + "module_type": "binary" } ] } \ No newline at end of file diff --git a/tests/snapshots/local/shared-everything-threads/globals.wast.json b/tests/snapshots/local/shared-everything-threads/globals.wast.json index d28c04dff0..65879d88d1 100644 --- a/tests/snapshots/local/shared-everything-threads/globals.wast.json +++ b/tests/snapshots/local/shared-everything-threads/globals.wast.json @@ -167,6 +167,44 @@ "type": "module", "line": 277, "filename": "globals.24.wasm" + }, + { + "type": "assert_invalid", + "line": 371, + "filename": "globals.25.wasm", + "text": "invalid type: `global.atomic.rmw.*` only allows `i32` and `i64`", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 382, + "filename": "globals.26.wasm", + "text": "global index out of bounds", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 390, + "filename": "globals.27.wasm", + "text": "invalid type: `global.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`", + "module_type": "binary" + }, + { + "type": "module", + "line": 400, + "filename": "globals.28.wasm" + }, + { + "type": "assert_invalid", + "line": 410, + "filename": "globals.29.wasm", + "text": "invalid type: `global.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`", + "module_type": "binary" + }, + { + "type": "module", + "line": 421, + "filename": "globals.30.wasm" } ] } \ No newline at end of file diff --git a/tests/snapshots/local/shared-everything-threads/globals.wast/28.print b/tests/snapshots/local/shared-everything-threads/globals.wast/28.print new file mode 100644 index 0000000000..6cd361a78a --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/globals.wast/28.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + ref.null eq + global.atomic.rmw.xchg acq_rel $g + drop + ) + (global $g (;0;) (mut eqref) ref.null eq) +) diff --git a/tests/snapshots/local/shared-everything-threads/globals.wast/30.print b/tests/snapshots/local/shared-everything-threads/globals.wast/30.print new file mode 100644 index 0000000000..c97befa30b --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/globals.wast/30.print @@ -0,0 +1,10 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + ref.null eq + ref.null eq + global.atomic.rmw.cmpxchg acq_rel $g + drop + ) + (global $g (;0;) (mut eqref) ref.null eq) +) diff --git a/tests/snapshots/local/shared-everything-threads/structs.wast.json b/tests/snapshots/local/shared-everything-threads/structs.wast.json index 0a68ac7d6d..be1a6db1a9 100644 --- a/tests/snapshots/local/shared-everything-threads/structs.wast.json +++ b/tests/snapshots/local/shared-everything-threads/structs.wast.json @@ -212,6 +212,34 @@ "filename": "structs.31.wasm", "text": "invalid type", "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 532, + "filename": "structs.32.wasm", + "text": "invalid type: `struct.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 543, + "filename": "structs.33.wasm", + "text": "invalid type: `struct.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 554, + "filename": "structs.34.wasm", + "text": "can only use struct `get` with non-packed storage types", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 565, + "filename": "structs.35.wasm", + "text": "invalid type: `struct.atomic.set` only allows `i8`, `i16`, `i32`, `i64` and subtypes of `anyref`", + "module_type": "binary" } ] } \ No newline at end of file diff --git a/tests/snapshots/local/shared-everything-threads/tables.wast.json b/tests/snapshots/local/shared-everything-threads/tables.wast.json index 14f91dacca..46c2ea084a 100644 --- a/tests/snapshots/local/shared-everything-threads/tables.wast.json +++ b/tests/snapshots/local/shared-everything-threads/tables.wast.json @@ -62,6 +62,27 @@ "filename": "tables.9.wasm", "text": "invalid type", "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 177, + "filename": "tables.10.wasm", + "text": "invalid type: `table.atomic.get` only allows subtypes of `anyref`", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 187, + "filename": "tables.11.wasm", + "text": "invalid type: `table.atomic.set` only allows subtypes of `anyref`", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 198, + "filename": "tables.12.wasm", + "text": "invalid type: `table.atomic.rmw.xchg` only allows subtypes of `anyref`", + "module_type": "binary" } ] } \ No newline at end of file From f932b598ec5c87cb5d47be236b0550ddb1b0ed09 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 4 Sep 2024 09:48:46 -0500 Subject: [PATCH 04/18] Don't do "sloppy" error matching on our own tests (#1755) Right now all upstream spec tests are asserted to have roughly the same shape of error as wasmparser produces to ensure that wasmparser isn't failing for the wrong reason on an invalid wasm module. This involves quite a large function, however, which is quite fuzzy on how it matches error strings. None of this logic should be applicable in the `tests/local/**/*.wast` tests however because those are all checked in to this repository and aren't intended to reflect upstream error messages. This commit disables the sloppy error matching and requires that the exact error contains the exact string in the assertion. This then goes through some tests and updates some of the expected errors. --- tests/local/duplicate.wast | 30 +++++++++---------- .../function-references/return-call.wast | 2 +- tests/local/invalid/empty-br-table.wast | 4 +-- tests/local/legacy-exceptions/throw.wast | 4 +-- tests/local/legacy-exceptions/try_catch.wast | 10 +++---- .../shared-everything-threads/tables.wast | 2 +- tests/roundtrip.rs | 11 +++++-- tests/snapshots/local/duplicate.wast.json | 30 +++++++++---------- .../function-references/return-call.wast.json | 2 +- .../local/legacy-exceptions/throw.wast.json | 4 +-- .../legacy-exceptions/try_catch.wast.json | 10 +++---- .../tables.wast.json | 2 +- 12 files changed, 59 insertions(+), 52 deletions(-) diff --git a/tests/local/duplicate.wast b/tests/local/duplicate.wast index 621a837083..c01aa35bae 100644 --- a/tests/local/duplicate.wast +++ b/tests/local/duplicate.wast @@ -1,58 +1,58 @@ (assert_malformed (module quote "(func $foo)" "(func $foo)") - "duplicate identifier") + "duplicate func identifier") (assert_malformed (module quote "(import \"\" \"\" (func $foo))" "(func $foo)") - "duplicate identifier") + "duplicate func identifier") (assert_malformed (module quote "(import \"\" \"\" (func $foo))" "(import \"\" \"\" (func $foo))") - "duplicate identifier") + "duplicate func identifier") (assert_malformed (module quote "(global $foo i32 (i32.const 0))" "(global $foo i32 (i32.const 0))") - "duplicate identifier") + "duplicate global identifier") (assert_malformed (module quote "(import \"\" \"\" (global $foo i32))" "(global $foo i32 (i32.const 0))") - "duplicate identifier") + "duplicate global identifier") (assert_malformed (module quote "(import \"\" \"\" (global $foo i32))" "(import \"\" \"\" (global $foo i32))") - "duplicate identifier") + "duplicate global identifier") (assert_malformed (module quote "(memory $foo 1)" "(memory $foo 1)") - "duplicate identifier") + "duplicate memory identifier") (assert_malformed (module quote "(import \"\" \"\" (memory $foo 1))" "(memory $foo 1)") - "duplicate identifier") + "duplicate memory identifier") (assert_malformed (module quote "(import \"\" \"\" (memory $foo 1))" "(import \"\" \"\" (memory $foo 1))") - "duplicate identifier") + "duplicate memory identifier") (assert_malformed (module quote "(table $foo 1 funcref)" "(table $foo 1 funcref)") - "duplicate identifier") + "duplicate table identifier") (assert_malformed (module quote "(import \"\" \"\" (table $foo 1 funcref))" "(table $foo 1 funcref)") - "duplicate identifier") + "duplicate table identifier") (assert_malformed (module quote "(import \"\" \"\" (table $foo 1 funcref))" "(import \"\" \"\" (table $foo 1 funcref))") - "duplicate identifier") + "duplicate table identifier") (assert_malformed (module quote "(func (param $foo i32) (param $foo i32))") - "duplicate identifier") + "duplicate local identifier") (assert_malformed (module quote "(func (param $foo i32) (local $foo i32))") - "duplicate identifier") + "duplicate local identifier") (assert_malformed (module quote "(func (local $foo i32) (local $foo i32))") - "duplicate identifier") + "duplicate local identifier") diff --git a/tests/local/function-references/return-call.wast b/tests/local/function-references/return-call.wast index c1c56079ad..a5eb4e7592 100644 --- a/tests/local/function-references/return-call.wast +++ b/tests/local/function-references/return-call.wast @@ -33,5 +33,5 @@ return_call_ref $ty ) ) - "type mismatch: current function requires result type [i32] but callee returns [i32 i32]" + "type mismatch: expected (ref null $type), found funcref" ) diff --git a/tests/local/invalid/empty-br-table.wast b/tests/local/invalid/empty-br-table.wast index f73082dfa4..1b95fa2020 100644 --- a/tests/local/invalid/empty-br-table.wast +++ b/tests/local/invalid/empty-br-table.wast @@ -5,8 +5,8 @@ "\01\04\01\60\00\00" ;; type section, 1 type, (func) "\03\02\01\00" ;; func section, 1 function, type 0 - "\0a\0d\01" ;; code section - "\0b" ;; function size + "\0a\0e\01" ;; code section + "\0c" ;; function size "\00" ;; no locals "\02\40" ;; block "\41\01" ;; i32.const 1 diff --git a/tests/local/legacy-exceptions/throw.wast b/tests/local/legacy-exceptions/throw.wast index 2ab9f2f330..d36e849164 100644 --- a/tests/local/legacy-exceptions/throw.wast +++ b/tests/local/legacy-exceptions/throw.wast @@ -51,6 +51,6 @@ (assert_invalid (module (func (throw 0))) "unknown tag 0") (assert_invalid (module (tag (param i32)) (func (throw 0))) - "type mismatch: instruction requires [i32] but stack has []") + "type mismatch") (assert_invalid (module (tag (param i32)) (func (i64.const 5) (throw 0))) - "type mismatch: instruction requires [i32] but stack has [i64]") + "type mismatch") diff --git a/tests/local/legacy-exceptions/try_catch.wast b/tests/local/legacy-exceptions/try_catch.wast index 8819e82487..7d93a36335 100644 --- a/tests/local/legacy-exceptions/try_catch.wast +++ b/tests/local/legacy-exceptions/try_catch.wast @@ -295,15 +295,15 @@ ;; ) (assert_invalid (module (func (result i32) try (result i32) end)) - "type mismatch: instruction requires [i32] but stack has []") + "type mismatch") (assert_invalid (module (func (result i32) try (result i32) i64.const 42 end)) - "type mismatch: instruction requires [i32] but stack has [i64]") + "type mismatch") (assert_invalid (module (tag) (func try catch 0 i32.const 42 end)) - "type mismatch: block requires [] but stack has [i32]") + "type mismatch") (assert_invalid (module (tag (param i64)) (func (result i32) try (result i32) i32.const 42 catch 0 end)) - "type mismatch: instruction requires [i32] but stack has [i64]") + "type mismatch") (assert_invalid (module (func try catch_all i32.const 32 end)) - "type mismatch: block requires [] but stack has [i32]") + "type mismatch") diff --git a/tests/local/shared-everything-threads/tables.wast b/tests/local/shared-everything-threads/tables.wast index 3a14ff2f4f..d293a29203 100644 --- a/tests/local/shared-everything-threads/tables.wast +++ b/tests/local/shared-everything-threads/tables.wast @@ -30,7 +30,7 @@ ;; would need to lookahead multiple tokens. (assert_malformed (module quote "(table shared i64 (ref null (shared func)) (elem (ref.null (shared func))))") - "unexpected token") + "expected a u64") (assert_invalid (module (table (import "spectest" "table_ref") shared 0 funcref)) diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs index 63917769fd..a5b15c4c70 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -354,7 +354,7 @@ impl TestState { message, ), Err(e) => { - if error_matches(&format!("{:?}", e), message) { + if error_matches(test, &format!("{:?}", e), message) { self.bump_ntests(); return Ok(()); } @@ -669,10 +669,17 @@ impl TestState { } } -fn error_matches(error: &str, message: &str) -> bool { +fn error_matches(test: &Path, error: &str, message: &str) -> bool { if error.contains(message) { return true; } + // we are in control over all tsets in `tests/local/*` so all the error + // messages there should exactly match the `assert_invalid` or such. No need + // for fuzzy matching on error messages. + if test.starts_with("tests/local") { + return false; + } + if message == "unknown operator" || message == "unexpected token" || message == "wrong number of lane literals" diff --git a/tests/snapshots/local/duplicate.wast.json b/tests/snapshots/local/duplicate.wast.json index 96a0173dce..40d6bedef2 100644 --- a/tests/snapshots/local/duplicate.wast.json +++ b/tests/snapshots/local/duplicate.wast.json @@ -5,105 +5,105 @@ "type": "assert_malformed", "line": 1, "filename": "duplicate.0.wat", - "text": "duplicate identifier", + "text": "duplicate func identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 5, "filename": "duplicate.1.wat", - "text": "duplicate identifier", + "text": "duplicate func identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 9, "filename": "duplicate.2.wat", - "text": "duplicate identifier", + "text": "duplicate func identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 14, "filename": "duplicate.3.wat", - "text": "duplicate identifier", + "text": "duplicate global identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 18, "filename": "duplicate.4.wat", - "text": "duplicate identifier", + "text": "duplicate global identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 22, "filename": "duplicate.5.wat", - "text": "duplicate identifier", + "text": "duplicate global identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 27, "filename": "duplicate.6.wat", - "text": "duplicate identifier", + "text": "duplicate memory identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 31, "filename": "duplicate.7.wat", - "text": "duplicate identifier", + "text": "duplicate memory identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 35, "filename": "duplicate.8.wat", - "text": "duplicate identifier", + "text": "duplicate memory identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 40, "filename": "duplicate.9.wat", - "text": "duplicate identifier", + "text": "duplicate table identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 44, "filename": "duplicate.10.wat", - "text": "duplicate identifier", + "text": "duplicate table identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 48, "filename": "duplicate.11.wat", - "text": "duplicate identifier", + "text": "duplicate table identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 53, "filename": "duplicate.12.wat", - "text": "duplicate identifier", + "text": "duplicate local identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 55, "filename": "duplicate.13.wat", - "text": "duplicate identifier", + "text": "duplicate local identifier", "module_type": "text" }, { "type": "assert_malformed", "line": 57, "filename": "duplicate.14.wat", - "text": "duplicate identifier", + "text": "duplicate local identifier", "module_type": "text" } ] diff --git a/tests/snapshots/local/function-references/return-call.wast.json b/tests/snapshots/local/function-references/return-call.wast.json index 7ea31ec638..6c7d32a464 100644 --- a/tests/snapshots/local/function-references/return-call.wast.json +++ b/tests/snapshots/local/function-references/return-call.wast.json @@ -19,7 +19,7 @@ "type": "assert_invalid", "line": 29, "filename": "return-call.2.wasm", - "text": "type mismatch: current function requires result type [i32] but callee returns [i32 i32]", + "text": "type mismatch: expected (ref null $type), found funcref", "module_type": "binary" } ] diff --git a/tests/snapshots/local/legacy-exceptions/throw.wast.json b/tests/snapshots/local/legacy-exceptions/throw.wast.json index bbffce788a..19bd9185bf 100644 --- a/tests/snapshots/local/legacy-exceptions/throw.wast.json +++ b/tests/snapshots/local/legacy-exceptions/throw.wast.json @@ -117,14 +117,14 @@ "type": "assert_invalid", "line": 53, "filename": "throw.2.wasm", - "text": "type mismatch: instruction requires [i32] but stack has []", + "text": "type mismatch", "module_type": "binary" }, { "type": "assert_invalid", "line": 55, "filename": "throw.3.wasm", - "text": "type mismatch: instruction requires [i32] but stack has [i64]", + "text": "type mismatch", "module_type": "binary" } ] diff --git a/tests/snapshots/local/legacy-exceptions/try_catch.wast.json b/tests/snapshots/local/legacy-exceptions/try_catch.wast.json index 8b256d189b..eafa83c339 100644 --- a/tests/snapshots/local/legacy-exceptions/try_catch.wast.json +++ b/tests/snapshots/local/legacy-exceptions/try_catch.wast.json @@ -564,35 +564,35 @@ "type": "assert_invalid", "line": 297, "filename": "try_catch.3.wasm", - "text": "type mismatch: instruction requires [i32] but stack has []", + "text": "type mismatch", "module_type": "binary" }, { "type": "assert_invalid", "line": 299, "filename": "try_catch.4.wasm", - "text": "type mismatch: instruction requires [i32] but stack has [i64]", + "text": "type mismatch", "module_type": "binary" }, { "type": "assert_invalid", "line": 301, "filename": "try_catch.5.wasm", - "text": "type mismatch: block requires [] but stack has [i32]", + "text": "type mismatch", "module_type": "binary" }, { "type": "assert_invalid", "line": 303, "filename": "try_catch.6.wasm", - "text": "type mismatch: instruction requires [i32] but stack has [i64]", + "text": "type mismatch", "module_type": "binary" }, { "type": "assert_invalid", "line": 308, "filename": "try_catch.7.wasm", - "text": "type mismatch: block requires [] but stack has [i32]", + "text": "type mismatch", "module_type": "binary" } ] diff --git a/tests/snapshots/local/shared-everything-threads/tables.wast.json b/tests/snapshots/local/shared-everything-threads/tables.wast.json index 46c2ea084a..595de4263c 100644 --- a/tests/snapshots/local/shared-everything-threads/tables.wast.json +++ b/tests/snapshots/local/shared-everything-threads/tables.wast.json @@ -29,7 +29,7 @@ "type": "assert_malformed", "line": 32, "filename": "tables.4.wat", - "text": "unexpected token", + "text": "expected a u64", "module_type": "text" }, { From 64821ec5d8979e3f1dafb250a083da1ae8584518 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 4 Sep 2024 10:43:25 -0500 Subject: [PATCH 05/18] Generate WITs with the latest `wit-smith` (#1758) With the new wit64 fuzzer don't use the old `wit-smith` but instead use the newer version. The old version still generates multi-return functions which are no longer supported by default in WIT. This will eventually cause a problem when the newest wit-smith generates features the "old" version no longer supports, but I figure that's a bridge that can be crossed when we get there. --- Cargo.lock | 19 ++----------------- fuzz/Cargo.toml | 4 ---- fuzz/src/wit64.rs | 2 +- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 844cea6e2f..bea35ec67e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1786,7 +1786,7 @@ dependencies = [ "wit-component 0.216.0", "wit-encoder", "wit-parser 0.216.0", - "wit-smith 0.216.0", + "wit-smith", ] [[package]] @@ -1825,8 +1825,7 @@ dependencies = [ "wit-component 0.216.0", "wit-parser 0.214.0", "wit-parser 0.216.0", - "wit-smith 0.214.0", - "wit-smith 0.216.0", + "wit-smith", ] [[package]] @@ -2462,20 +2461,6 @@ dependencies = [ "wit-parser 0.216.0", ] -[[package]] -name = "wit-smith" -version = "0.214.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cf816019a376a912cafb103677a8d28e3cba86b7671b754281e75f4909e129" -dependencies = [ - "arbitrary", - "indexmap 2.4.0", - "log", - "semver", - "wit-component 0.214.0", - "wit-parser 0.214.0", -] - [[package]] name = "wit-smith" version = "0.216.0" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 7bcf6d52d1..31ebb4cd14 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -37,10 +37,6 @@ version = '0.214.0' package = 'wit-component' version = '0.214.0' -[dependencies.wit-smith-old] -package = 'wit-smith' -version = '0.214.0' - [lib] test = false doctest = false diff --git a/fuzz/src/wit64.rs b/fuzz/src/wit64.rs index 594156bfbb..b6e8af8c07 100644 --- a/fuzz/src/wit64.rs +++ b/fuzz/src/wit64.rs @@ -6,7 +6,7 @@ use wit_parser as wit_parser_new; pub fn run(u: &mut Unstructured<'_>) -> Result<()> { let wasm = u.arbitrary().and_then(|config| { log::debug!("config: {config:#?}"); - wit_smith_old::smith(&config, u) + wit_smith::smith(&config, u) })?; write_file("doc.wasm", &wasm); let r1 = wit_component_old::decode(&wasm).unwrap(); From 83f25b72581d5e50fc7f453bcd94c5a147399ab6 Mon Sep 17 00:00:00 2001 From: Mendy Berger <12537668+MendyBerger@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:13:32 -0400 Subject: [PATCH 06/18] wit-encoder: added a few accessors and better naming for serde (#1759) * Added and improved some accessors * Better name for serde (type instead of ty) * cargo fmt --- crates/wit-encoder/src/enum_.rs | 2 +- crates/wit-encoder/src/record.rs | 19 ++++++++++++------- crates/wit-encoder/src/resource.rs | 16 ++++++++++++++++ crates/wit-encoder/src/result.rs | 12 ++++++++++++ crates/wit-encoder/src/ty.rs | 27 ++++++++++++++++++++------- 5 files changed, 61 insertions(+), 15 deletions(-) diff --git a/crates/wit-encoder/src/enum_.rs b/crates/wit-encoder/src/enum_.rs index 6132ebb609..63757b470b 100644 --- a/crates/wit-encoder/src/enum_.rs +++ b/crates/wit-encoder/src/enum_.rs @@ -65,7 +65,7 @@ impl EnumCase { } } - pub fn name(&mut self) -> &Ident { + pub fn name(&self) -> &Ident { &self.name } diff --git a/crates/wit-encoder/src/record.rs b/crates/wit-encoder/src/record.rs index 6b2dca0a06..7bc505082b 100644 --- a/crates/wit-encoder/src/record.rs +++ b/crates/wit-encoder/src/record.rs @@ -28,7 +28,8 @@ impl Record { #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Field { pub(crate) name: Ident, - pub(crate) ty: Type, + #[cfg_attr(feature = "serde", serde(rename = "type"))] + pub(crate) type_: Type, pub(crate) docs: Option, } @@ -36,12 +37,12 @@ impl Field { pub fn new(name: impl Into, ty: Type) -> Self { Self { name: name.into(), - ty, + type_: ty, docs: None, } } - pub fn name(&mut self) -> &Ident { + pub fn name(&self) -> &Ident { &self.name } @@ -57,12 +58,16 @@ impl Field { &self.docs } - pub fn ty(&self) -> &Type { - &self.ty + pub fn type_(&self) -> &Type { + &self.type_ } - pub fn ty_mut(&mut self) -> &mut Type { - &mut self.ty + pub fn type_mut(&mut self) -> &mut Type { + &mut self.type_ + } + + pub fn set_type(&mut self, type_: impl Into) { + self.type_ = type_.into(); } } diff --git a/crates/wit-encoder/src/resource.rs b/crates/wit-encoder/src/resource.rs index e59e941760..cab2ff6a44 100644 --- a/crates/wit-encoder/src/resource.rs +++ b/crates/wit-encoder/src/resource.rs @@ -108,6 +108,22 @@ impl ResourceFunc { } } + pub fn results(&self) -> Option<&Results> { + match &self.kind { + ResourceFuncKind::Method(_, results) => Some(results), + ResourceFuncKind::Static(_, results) => Some(results), + ResourceFuncKind::Constructor => None, + } + } + + pub fn results_mut(&mut self) -> Option<&mut Results> { + match &mut self.kind { + ResourceFuncKind::Method(_, results) => Some(results), + ResourceFuncKind::Static(_, results) => Some(results), + ResourceFuncKind::Constructor => None, + } + } + pub fn set_docs(&mut self, docs: Option>) { self.docs = docs.map(|d| d.into()); } diff --git a/crates/wit-encoder/src/result.rs b/crates/wit-encoder/src/result.rs index ee8ff11909..e7436e3ad3 100644 --- a/crates/wit-encoder/src/result.rs +++ b/crates/wit-encoder/src/result.rs @@ -17,12 +17,24 @@ impl Result_ { err: None, } } + pub fn get_ok(&self) -> &Option { + &self.ok + } + pub fn get_ok_mut(&mut self) -> &mut Option { + &mut self.ok + } pub fn err(type_: Type) -> Self { Self { ok: None, err: Some(type_), } } + pub fn get_err(&self) -> &Option { + &self.err + } + pub fn get_err_mut(&mut self) -> &mut Option { + &mut self.err + } pub fn both(ok: Type, err: Type) -> Self { Self { ok: Some(ok), diff --git a/crates/wit-encoder/src/ty.rs b/crates/wit-encoder/src/ty.rs index 434868a536..62bf852f16 100644 --- a/crates/wit-encoder/src/ty.rs +++ b/crates/wit-encoder/src/ty.rs @@ -117,7 +117,8 @@ impl Display for Type { #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct VariantCase { name: Ident, - ty: Option, + #[cfg_attr(feature = "serde", serde(rename = "type"))] + type_: Option, docs: Option, } @@ -125,7 +126,7 @@ impl VariantCase { pub fn empty(name: impl Into) -> Self { Self { name: name.into(), - ty: None, + type_: None, docs: None, } } @@ -133,17 +134,29 @@ impl VariantCase { pub fn value(name: impl Into, ty: Type) -> Self { Self { name: name.into(), - ty: Some(ty), + type_: Some(ty), docs: None, } } + pub fn set_name(&mut self, name: impl Into) { + self.name = name.into(); + } + + pub fn name(&self) -> &Ident { + &self.name + } + + pub fn name_mut(&mut self) -> &mut Ident { + &mut self.name + } + pub fn type_(&self) -> Option<&Type> { - self.ty.as_ref() + self.type_.as_ref() } pub fn type_mut(&mut self) -> &mut Option { - &mut self.ty + &mut self.type_ } pub fn set_docs(&mut self, docs: Option>) { @@ -348,7 +361,7 @@ impl Render for TypeDef { if let Some(docs) = &field.docs { docs.render(f, &opts)?; } - write!(f, "{}{}: {},\n", opts.spaces(), field.name, field.ty)?; + write!(f, "{}{}: {},\n", opts.spaces(), field.name, field.type_)?; } write!(f, "{}}}\n", opts.spaces())?; } @@ -408,7 +421,7 @@ impl Render for TypeDef { if let Some(docs) = &case.docs { docs.render(f, &opts)?; } - match &case.ty { + match &case.type_ { Some(type_) => { write!(f, "{}{}({}),\n", opts.spaces(), case.name, type_)?; } From 50aef2f61d6017bb878f630f9c20d7bb4abb39b1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Sep 2024 11:16:24 -0500 Subject: [PATCH 07/18] Add a shorthand feature constructor for Wasm 3.0 (#1760) * Add a shorthand feature constructor for Wasm 3.0 This is still in-development but is likely close to the final set of proposals. Additionally move the previous function constructors to associated `const` values to be a bit more idiomatic with other feature names. Finally refactor the CLI to more easily support these named sets in suggestions and refactor some feature selection in the roundtrip tests. * Update some tests --- crates/wasm-smith/tests/common/mod.rs | 2 +- crates/wasmparser/src/features.rs | 43 ++++++--- src/bin/wasm-tools/validate.rs | 91 ++++++++++++------- .../cli/validate-unknown-features.wat.stderr | 2 +- tests/roundtrip.rs | 22 +---- 5 files changed, 91 insertions(+), 69 deletions(-) diff --git a/crates/wasm-smith/tests/common/mod.rs b/crates/wasm-smith/tests/common/mod.rs index 332fd0ca77..688bb87fcf 100644 --- a/crates/wasm-smith/tests/common/mod.rs +++ b/crates/wasm-smith/tests/common/mod.rs @@ -2,7 +2,7 @@ use wasm_smith::Config; use wasmparser::{types::Types, Validator, WasmFeatures}; pub fn parser_features_from_config(config: &Config) -> WasmFeatures { - let mut features = WasmFeatures::MUTABLE_GLOBAL | WasmFeatures::wasm1(); + let mut features = WasmFeatures::MUTABLE_GLOBAL | WasmFeatures::WASM1; features.set( WasmFeatures::SATURATING_FLOAT_TO_INT, config.saturating_float_to_int_enabled, diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index 4290ff424b..30c8a2f1ff 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -229,26 +229,39 @@ define_wasm_features! { } impl WasmFeatures { - /// Returns the feature set associated with the 1.0 version of the + /// The feature set associated with the 1.0 version of the /// WebAssembly specification or the "MVP" feature set. #[cfg(feature = "features")] - pub fn wasm1() -> WasmFeatures { - WasmFeatures::FLOATS | WasmFeatures::GC_TYPES - } + pub const WASM1: WasmFeatures = WasmFeatures::FLOATS.union(WasmFeatures::GC_TYPES); - /// Returns the feature set associated with the 2.0 version of the + /// The feature set associated with the 2.0 version of the /// WebAssembly specification. #[cfg(feature = "features")] - pub fn wasm2() -> WasmFeatures { - WasmFeatures::wasm1() - | WasmFeatures::BULK_MEMORY - | WasmFeatures::REFERENCE_TYPES - | WasmFeatures::SIGN_EXTENSION - | WasmFeatures::MUTABLE_GLOBAL - | WasmFeatures::SATURATING_FLOAT_TO_INT - | WasmFeatures::MULTI_VALUE - | WasmFeatures::SIMD - } + pub const WASM2: WasmFeatures = WasmFeatures::WASM1 + .union(WasmFeatures::BULK_MEMORY) + .union(WasmFeatures::REFERENCE_TYPES) + .union(WasmFeatures::SIGN_EXTENSION) + .union(WasmFeatures::MUTABLE_GLOBAL) + .union(WasmFeatures::SATURATING_FLOAT_TO_INT) + .union(WasmFeatures::MULTI_VALUE) + .union(WasmFeatures::SIMD); + + /// The feature set associated with the 3.0 version of the + /// WebAssembly specification. + /// + /// Note that as of the time of this writing the 3.0 version of the + /// specification is not yet published. The precise set of features set + /// here may change as that continues to evolve. + #[cfg(feature = "features")] + pub const WASM3: WasmFeatures = WasmFeatures::WASM2 + .union(WasmFeatures::GC) + .union(WasmFeatures::TAIL_CALL) + .union(WasmFeatures::EXTENDED_CONST) + .union(WasmFeatures::FUNCTION_REFERENCES) + .union(WasmFeatures::MULTI_MEMORY) + .union(WasmFeatures::RELAXED_SIMD) + .union(WasmFeatures::THREADS) + .union(WasmFeatures::EXCEPTIONS); } #[cfg(feature = "features")] diff --git a/src/bin/wasm-tools/validate.rs b/src/bin/wasm-tools/validate.rs index 7283c4da0b..a065665df9 100644 --- a/src/bin/wasm-tools/validate.rs +++ b/src/bin/wasm-tools/validate.rs @@ -1,5 +1,5 @@ use addr2line::LookupResult; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{bail, Context, Result}; use bitflags::Flags; use rayon::prelude::*; use std::fmt::Write; @@ -183,53 +183,76 @@ impl Opts { fn parse_features(arg: &str) -> Result { let mut ret = WasmFeatures::default(); - fn flag_name(flag: &bitflags::Flag) -> String { - flag.name().to_lowercase().replace('_', "-") + const GROUPS: &[(&str, WasmFeatures)] = &[ + ("mvp", WasmFeatures::WASM1), + ("wasm1", WasmFeatures::WASM1), + ("wasm2", WasmFeatures::WASM2), + ("wasm3", WasmFeatures::WASM3), + ]; + + enum Action { + ChangeAll, + Group(WasmFeatures), + Modify(WasmFeatures), + } + + fn actions() -> impl Iterator { + WasmFeatures::FLAGS + .iter() + .map(|f| (f.name(), Action::Modify(*f.value()))) + .chain( + GROUPS + .iter() + .map(|(name, features)| (*name, Action::Group(*features))), + ) + .chain([("all", Action::ChangeAll)]) + } + + fn flag_name(name: &str) -> String { + name.to_lowercase().replace('_', "-") } - for part in arg.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()) { + 'outer: for part in arg.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()) { let (enable, part) = if let Some(part) = part.strip_prefix("-") { (false, part) } else { (true, part) }; - match part { - "all" => { - for flag in WasmFeatures::FLAGS.iter() { - ret.set(*flag.value(), enable); - } + for (name, action) in actions() { + if part != flag_name(name) { + continue; } - "wasm1" | "mvp" => { - if !enable { - bail!("cannot disable `{part}`, it can only be enabled"); + match action { + Action::ChangeAll => { + for flag in WasmFeatures::FLAGS.iter() { + ret.set(*flag.value(), enable); + } } - ret = WasmFeatures::wasm1(); - } - "wasm2" => { - if !enable { - bail!("cannot disable `{part}`, it can only be enabled"); + Action::Modify(feature) => { + ret.set(feature, enable); + } + Action::Group(features) => { + if !enable { + bail!("cannot disable `{part}`, it can only be enabled"); + } + ret = features; } - ret = WasmFeatures::wasm2(); } + continue 'outer; + } - name => { - let flag = WasmFeatures::FLAGS - .iter() - .find(|f| flag_name(f) == name) - .ok_or_else(|| { - anyhow!( - "unknown feature `{}`\nValid features: {}", - name, - WasmFeatures::FLAGS - .iter() - .map(flag_name) - .collect::>() - .join(", "), - ) - })?; - ret.set(*flag.value(), enable); + let mut error = format!("unknown feature `{part}`\n"); + error.push_str("Valid features: "); + let mut first = true; + for (name, _) in actions() { + if first { + first = false; + } else { + error.push_str(", "); } + error.push_str(&flag_name(name)); } + bail!("{error}") } Ok(ret) diff --git a/tests/cli/validate-unknown-features.wat.stderr b/tests/cli/validate-unknown-features.wat.stderr index 3e0ccb84e4..95e79d763f 100644 --- a/tests/cli/validate-unknown-features.wat.stderr +++ b/tests/cli/validate-unknown-features.wat.stderr @@ -1,4 +1,4 @@ error: invalid value 'unknown' for '--features ': unknown feature `unknown` -Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, component-model-values, component-model-nested-names, component-model-more-flags, component-model-multiple-returns, legacy-exceptions, gc-types +Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, component-model-values, component-model-nested-names, component-model-more-flags, component-model-multiple-returns, legacy-exceptions, gc-types, mvp, wasm1, wasm2, wasm3, all For more information, try '--help'. diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs index a5b15c4c70..bd40b897e7 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -598,16 +598,9 @@ impl TestState { for part in test.iter().filter_map(|t| t.to_str()) { match part { "testsuite" => { - features = WasmFeatures::wasm2(); - features |= WasmFeatures::TAIL_CALL; - features |= WasmFeatures::EXTENDED_CONST; - - // NB: when these proposals are merged upstream in the spec - // repo then this should be removed. Currently this hasn't - // happened so this is required to get tests passing for - // when these proposals are enabled by default. - features.remove(WasmFeatures::MULTI_MEMORY); - features.remove(WasmFeatures::THREADS); + features = WasmFeatures::WASM2 + | WasmFeatures::TAIL_CALL + | WasmFeatures::EXTENDED_CONST; } "missing-features" => { features = @@ -624,14 +617,7 @@ impl TestState { "exception-handling" => features.insert(WasmFeatures::EXCEPTIONS), "legacy-exceptions" => features.insert(WasmFeatures::LEGACY_EXCEPTIONS), "tail-call" => features.insert(WasmFeatures::TAIL_CALL), - "memory64" => features.insert( - WasmFeatures::MEMORY64 - | WasmFeatures::GC - | WasmFeatures::REFERENCE_TYPES - | WasmFeatures::MULTI_MEMORY - | WasmFeatures::FUNCTION_REFERENCES - | WasmFeatures::EXCEPTIONS, - ), + "memory64" => features.insert(WasmFeatures::MEMORY64 | WasmFeatures::WASM3), "component-model" => features.insert(WasmFeatures::COMPONENT_MODEL), "shared-everything-threads" => { features.insert(WasmFeatures::COMPONENT_MODEL); From d4a6dc207cdd7fe4c961d25136df65f38d13a5c8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Sep 2024 12:43:26 -0500 Subject: [PATCH 08/18] Add write permissions to release process (#1766) * Add write permissions to release process This looks to be required now due to recent repo settings changes * Also add pull-requests permission --- .github/workflows/release-process.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release-process.yml b/.github/workflows/release-process.yml index d6b9b060b3..a9f9f91477 100644 --- a/.github/workflows/release-process.yml +++ b/.github/workflows/release-process.yml @@ -16,6 +16,10 @@ on: required: false default: 'bump' +permissions: + contents: write + pull-requests: write + jobs: release_process: name: Run the release process From c4a77ae9a8f354d5e12ab7fc68a288a2dae5aa27 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Sep 2024 12:44:11 -0500 Subject: [PATCH 09/18] Fix running tests with `RUST_BACKTRACE=1` (#1761) The previous version of test output used the `:?` formatter for `anyhow::Error` which would include the native backtrace when `RUST_BACKTRACE=1` is set. This commit updates formatters to use `:#` which is a bit less readable but doesn't include the backtrace when this env var is set. Additionally a test is added to CI to ensure this doesn't regress in the future. This is adapted from #1578. Closes #1578 --- .github/workflows/main.yml | 7 +++++++ crates/wit-component/tests/components.rs | 2 +- .../error-default-export-sig-mismatch/error.txt | 6 +----- .../error-empty-module-import/error.txt | 6 +----- .../error-export-sig-mismatch/error.txt | 7 +------ .../error-import-resource-rep/error.txt | 6 +----- .../error.txt | 6 +----- .../error-import-sig-mismatch/error.txt | 7 +------ .../error-invalid-module-import/error.txt | 6 +----- .../error-missing-default-export/error.txt | 6 +----- .../components/error-missing-export/error.txt | 7 +------ .../error-missing-import-func/error.txt | 6 +----- .../components/error-missing-import/error.txt | 6 +----- .../error-missing-module-metadata/error.txt | 5 +---- crates/wit-component/tests/merge.rs | 2 +- .../tests/merge/bad-interface1/error.txt | 6 +----- .../tests/merge/bad-interface2/error.txt | 6 +----- .../tests/merge/bad-world1/error.txt | 6 +----- .../tests/merge/bad-world2/error.txt | 6 +----- .../tests/merge/bad-world3/error.txt | 6 +----- .../tests/merge/bad-world4/error.txt | 6 +----- .../tests/merge/bad-world5/error.txt | 6 +----- crates/wit-component/tests/targets.rs | 2 +- .../tests/targets/error-missing-export/error.txt | 7 ++----- .../tests/targets/error-missing-import/error.txt | 7 ++----- crates/wit-parser/tests/all.rs | 2 +- .../tests/ui/parse-fail/bad-gate3.wit.result | 13 +++++-------- .../tests/ui/parse-fail/bad-gate4.wit.result | 13 +++++-------- .../tests/ui/parse-fail/bad-gate5.wit.result | 13 +++++-------- .../tests/ui/parse-fail/bad-pkg1.wit.result | 14 +++++--------- .../tests/ui/parse-fail/bad-pkg2.wit.result | 13 +++++-------- .../tests/ui/parse-fail/bad-pkg3.wit.result | 13 +++++-------- .../tests/ui/parse-fail/bad-pkg4.wit.result | 13 +++++-------- .../tests/ui/parse-fail/bad-pkg5.wit.result | 13 +++++-------- .../tests/ui/parse-fail/bad-pkg6.wit.result | 13 +++++-------- .../tests/ui/parse-fail/bad-resource15.wit.result | 13 +++++-------- .../ui/parse-fail/conflicting-package.wit.result | 15 +++++---------- .../ui/parse-fail/duplicate-interface2.wit.result | 14 +++++--------- .../ui/parse-fail/include-foreign.wit.result | 13 +++++-------- .../multi-file-missing-delimiter.wit.result | 14 +++++--------- .../multi-package-deps-share-nest.wit.result | 9 +++------ .../parse-fail/multiple-package-docs.wit.result | 15 +++++---------- .../no-access-to-sibling-use.wit.result | 14 +++++--------- .../non-existance-world-include.wit.result | 13 +++++-------- .../tests/ui/parse-fail/pkg-cycle.wit.result | 13 +++++-------- .../tests/ui/parse-fail/pkg-cycle2.wit.result | 13 +++++-------- .../resources-multiple-returns-borrow.wit.result | 13 +++++-------- .../parse-fail/resources-return-borrow.wit.result | 13 +++++-------- .../tests/ui/parse-fail/return-borrow1.wit.result | 13 +++++-------- .../tests/ui/parse-fail/return-borrow2.wit.result | 13 +++++-------- .../tests/ui/parse-fail/return-borrow6.wit.result | 13 +++++-------- .../tests/ui/parse-fail/return-borrow7.wit.result | 13 +++++-------- .../tests/ui/parse-fail/return-borrow8.wit.result | 14 +++++--------- .../type-and-resource-same-name.wit.result | 13 +++++-------- .../ui/parse-fail/unresolved-use10.wit.result | 14 +++++--------- .../parse-fail/use-and-include-world.wit.result | 14 +++++--------- .../tests/ui/parse-fail/use-world.wit.result | 13 +++++-------- .../ui/parse-fail/very-nested-packages.wit.result | 13 +++++-------- 58 files changed, 192 insertions(+), 376 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3e5bebcd61..df414bbca5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -92,6 +92,13 @@ jobs: # want this to break. - os: ubuntu-latest rust: nightly-2024-02-12 + # test that if `RUST_BACKTRACE=1` is set in the environment that all + # tests with blessed error messages still pass. + - os: ubuntu-latest + rust: default + env: + RUST_BACKTRACE: 1 + env: ${{ matrix.env || fromJSON('{}') }} steps: - uses: actions/checkout@v4 with: diff --git a/crates/wit-component/tests/components.rs b/crates/wit-component/tests/components.rs index 8f2951f927..3684b8ec33 100644 --- a/crates/wit-component/tests/components.rs +++ b/crates/wit-component/tests/components.rs @@ -147,7 +147,7 @@ fn run_test(path: &Path) -> Result<()> { if !test_case.starts_with("error-") { return Err(err); } - assert_output(&format!("{err:?}"), &error_path)?; + assert_output(&format!("{err:#}"), &error_path)?; return Ok(()); } }; diff --git a/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt b/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt index 904d1aef51..72264c4a30 100644 --- a/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt +++ b/crates/wit-component/tests/components/error-default-export-sig-mismatch/error.txt @@ -1,5 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: type mismatch for function `a`: expected `[I32, I32] -> [I32]` but found `[] -> []` \ No newline at end of file +failed to decode world from module: module was not valid: type mismatch for function `a`: expected `[I32, I32] -> [I32]` but found `[] -> []` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-empty-module-import/error.txt b/crates/wit-component/tests/components/error-empty-module-import/error.txt index 75f7337bf2..f68bb1b668 100644 --- a/crates/wit-component/tests/components/error-empty-module-import/error.txt +++ b/crates/wit-component/tests/components/error-empty-module-import/error.txt @@ -1,5 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: no top-level imported function `foo` specified \ No newline at end of file +failed to decode world from module: module was not valid: no top-level imported function `foo` specified \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt b/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt index 0588ebcf0d..3b1c6afaab 100644 --- a/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt +++ b/crates/wit-component/tests/components/error-export-sig-mismatch/error.txt @@ -1,6 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: failed to validate exported interface `foo` - 2: type mismatch for function `a`: expected `[I32, I32] -> [I32]` but found `[] -> []` \ No newline at end of file +failed to decode world from module: module was not valid: failed to validate exported interface `foo`: type mismatch for function `a`: expected `[I32, I32] -> [I32]` but found `[] -> []` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-import-resource-rep/error.txt b/crates/wit-component/tests/components/error-import-resource-rep/error.txt index f9f291d9f4..7dd176e603 100644 --- a/crates/wit-component/tests/components/error-import-resource-rep/error.txt +++ b/crates/wit-component/tests/components/error-import-resource-rep/error.txt @@ -1,5 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: no top-level imported function `[resource-rep]a` specified \ No newline at end of file +failed to decode world from module: module was not valid: no top-level imported function `[resource-rep]a` specified \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-import-resource-wrong-signature/error.txt b/crates/wit-component/tests/components/error-import-resource-wrong-signature/error.txt index e76b70fea7..d7eaac43fa 100644 --- a/crates/wit-component/tests/components/error-import-resource-wrong-signature/error.txt +++ b/crates/wit-component/tests/components/error-import-resource-wrong-signature/error.txt @@ -1,5 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: type mismatch for function `[resource-drop]a`: expected `[I32] -> []` but found `[I32] -> [I32]` \ No newline at end of file +failed to decode world from module: module was not valid: type mismatch for function `[resource-drop]a`: expected `[I32] -> []` but found `[I32] -> [I32]` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-import-sig-mismatch/error.txt b/crates/wit-component/tests/components/error-import-sig-mismatch/error.txt index 57dae3991b..41ba5e7720 100644 --- a/crates/wit-component/tests/components/error-import-sig-mismatch/error.txt +++ b/crates/wit-component/tests/components/error-import-sig-mismatch/error.txt @@ -1,6 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: failed to validate import interface `foo` - 2: type mismatch for function `bar`: expected `[I32, I32] -> []` but found `[] -> []` \ No newline at end of file +failed to decode world from module: module was not valid: failed to validate import interface `foo`: type mismatch for function `bar`: expected `[I32, I32] -> []` but found `[] -> []` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-invalid-module-import/error.txt b/crates/wit-component/tests/components/error-invalid-module-import/error.txt index 4a54c8216d..4c5195ec6c 100644 --- a/crates/wit-component/tests/components/error-invalid-module-import/error.txt +++ b/crates/wit-component/tests/components/error-invalid-module-import/error.txt @@ -1,5 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: module is only allowed to import functions \ No newline at end of file +failed to decode world from module: module was not valid: module is only allowed to import functions \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-default-export/error.txt b/crates/wit-component/tests/components/error-missing-default-export/error.txt index 1dc1b01f63..cd0b78a041 100644 --- a/crates/wit-component/tests/components/error-missing-default-export/error.txt +++ b/crates/wit-component/tests/components/error-missing-default-export/error.txt @@ -1,5 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: module does not export required function `a` \ No newline at end of file +failed to decode world from module: module was not valid: module does not export required function `a` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-export/error.txt b/crates/wit-component/tests/components/error-missing-export/error.txt index 6d4148bd72..0829150ee5 100644 --- a/crates/wit-component/tests/components/error-missing-export/error.txt +++ b/crates/wit-component/tests/components/error-missing-export/error.txt @@ -1,6 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: failed to validate exported interface `foo` - 2: module does not export required function `foo#a` \ No newline at end of file +failed to decode world from module: module was not valid: failed to validate exported interface `foo`: module does not export required function `foo#a` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-import-func/error.txt b/crates/wit-component/tests/components/error-missing-import-func/error.txt index 388a6087bb..b6f4f0dd5d 100644 --- a/crates/wit-component/tests/components/error-missing-import-func/error.txt +++ b/crates/wit-component/tests/components/error-missing-import-func/error.txt @@ -1,5 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: module requires an import interface named `foo` \ No newline at end of file +failed to decode world from module: module was not valid: module requires an import interface named `foo` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-import/error.txt b/crates/wit-component/tests/components/error-missing-import/error.txt index 388a6087bb..b6f4f0dd5d 100644 --- a/crates/wit-component/tests/components/error-missing-import/error.txt +++ b/crates/wit-component/tests/components/error-missing-import/error.txt @@ -1,5 +1 @@ -failed to decode world from module - -Caused by: - 0: module was not valid - 1: module requires an import interface named `foo` \ No newline at end of file +failed to decode world from module: module was not valid: module requires an import interface named `foo` \ No newline at end of file diff --git a/crates/wit-component/tests/components/error-missing-module-metadata/error.txt b/crates/wit-component/tests/components/error-missing-module-metadata/error.txt index 16f7797650..a256db38dc 100644 --- a/crates/wit-component/tests/components/error-missing-module-metadata/error.txt +++ b/crates/wit-component/tests/components/error-missing-module-metadata/error.txt @@ -1,4 +1 @@ -failed to register indirect shims for main module - -Caused by: - missing component metadata for import of `new::log` \ No newline at end of file +failed to register indirect shims for main module: missing component metadata for import of `new::log` \ No newline at end of file diff --git a/crates/wit-component/tests/merge.rs b/crates/wit-component/tests/merge.rs index f3b3918bd6..f7f72f2f65 100644 --- a/crates/wit-component/tests/merge.rs +++ b/crates/wit-component/tests/merge.rs @@ -52,7 +52,7 @@ fn merging() -> Result<()> { } Err(e) => { assert!(test_case.starts_with("bad-"), "failed to merge with {e:?}"); - assert_output(&path.join("error.txt"), &format!("{e:?}"))?; + assert_output(&path.join("error.txt"), &format!("{e:#}"))?; } } } diff --git a/crates/wit-component/tests/merge/bad-interface1/error.txt b/crates/wit-component/tests/merge/bad-interface1/error.txt index 951bb365d3..0558df13d3 100644 --- a/crates/wit-component/tests/merge/bad-interface1/error.txt +++ b/crates/wit-component/tests/merge/bad-interface1/error.txt @@ -1,5 +1 @@ -failed to merge package `foo:foo` into existing copy - -Caused by: - 0: failed to merge interface `a` - 1: expected type `a` to be present \ No newline at end of file +failed to merge package `foo:foo` into existing copy: failed to merge interface `a`: expected type `a` to be present \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-interface2/error.txt b/crates/wit-component/tests/merge/bad-interface2/error.txt index bbb5f232b2..0b3f674bf8 100644 --- a/crates/wit-component/tests/merge/bad-interface2/error.txt +++ b/crates/wit-component/tests/merge/bad-interface2/error.txt @@ -1,5 +1 @@ -failed to merge package `foo:foo` into existing copy - -Caused by: - 0: failed to merge interface `a` - 1: expected function `a` to be present \ No newline at end of file +failed to merge package `foo:foo` into existing copy: failed to merge interface `a`: expected function `a` to be present \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-world1/error.txt b/crates/wit-component/tests/merge/bad-world1/error.txt index f04e2ed0c2..059b1e3daf 100644 --- a/crates/wit-component/tests/merge/bad-world1/error.txt +++ b/crates/wit-component/tests/merge/bad-world1/error.txt @@ -1,5 +1 @@ -failed to merge package `foo:foo` into existing copy - -Caused by: - 0: failed to merge world `foo` - 1: import `b` not found in target world \ No newline at end of file +failed to merge package `foo:foo` into existing copy: failed to merge world `foo`: import `b` not found in target world \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-world2/error.txt b/crates/wit-component/tests/merge/bad-world2/error.txt index bca74e7b04..5f636c1394 100644 --- a/crates/wit-component/tests/merge/bad-world2/error.txt +++ b/crates/wit-component/tests/merge/bad-world2/error.txt @@ -1,5 +1 @@ -failed to merge package `foo:foo` into existing copy - -Caused by: - 0: failed to merge world `foo` - 1: world contains different number of imports than expected \ No newline at end of file +failed to merge package `foo:foo` into existing copy: failed to merge world `foo`: world contains different number of imports than expected \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-world3/error.txt b/crates/wit-component/tests/merge/bad-world3/error.txt index daf6860fff..1311233fa0 100644 --- a/crates/wit-component/tests/merge/bad-world3/error.txt +++ b/crates/wit-component/tests/merge/bad-world3/error.txt @@ -1,5 +1 @@ -failed to merge package `foo:foo` into existing copy - -Caused by: - 0: failed to merge world `foo` - 1: world contains different number of exports than expected \ No newline at end of file +failed to merge package `foo:foo` into existing copy: failed to merge world `foo`: world contains different number of exports than expected \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-world4/error.txt b/crates/wit-component/tests/merge/bad-world4/error.txt index 5cf21c9247..9b95070316 100644 --- a/crates/wit-component/tests/merge/bad-world4/error.txt +++ b/crates/wit-component/tests/merge/bad-world4/error.txt @@ -1,5 +1 @@ -failed to merge package `foo:foo` into existing copy - -Caused by: - 0: failed to merge world `foo` - 1: export `b` not found in target world \ No newline at end of file +failed to merge package `foo:foo` into existing copy: failed to merge world `foo`: export `b` not found in target world \ No newline at end of file diff --git a/crates/wit-component/tests/merge/bad-world5/error.txt b/crates/wit-component/tests/merge/bad-world5/error.txt index 9eb40e7551..38c83bb951 100644 --- a/crates/wit-component/tests/merge/bad-world5/error.txt +++ b/crates/wit-component/tests/merge/bad-world5/error.txt @@ -1,5 +1 @@ -failed to merge package `foo:foo` into existing copy - -Caused by: - 0: failed to merge world `foo` - 1: import `a` not found in target world \ No newline at end of file +failed to merge package `foo:foo` into existing copy: failed to merge world `foo`: import `a` not found in target world \ No newline at end of file diff --git a/crates/wit-component/tests/targets.rs b/crates/wit-component/tests/targets.rs index 7bbd96ff52..ff257285c1 100644 --- a/crates/wit-component/tests/targets.rs +++ b/crates/wit-component/tests/targets.rs @@ -50,7 +50,7 @@ fn targets() -> Result<()> { } Err(e) => { assert!(test_case.starts_with("error-"), "{e:?}"); - assert_output(&path.join("error.txt"), &format!("{e:?}"))?; + assert_output(&path.join("error.txt"), &format!("{e:#}"))?; } } } diff --git a/crates/wit-component/tests/targets/error-missing-export/error.txt b/crates/wit-component/tests/targets/error-missing-export/error.txt index ebfccba10d..5751a1062e 100644 --- a/crates/wit-component/tests/targets/error-missing-export/error.txt +++ b/crates/wit-component/tests/targets/error-missing-export/error.txt @@ -1,5 +1,2 @@ -failed to validate encoded bytes - -Caused by: - type mismatch for import `foobar` - missing export named `test:foo/bar` (at offset 0x1d5) \ No newline at end of file +failed to validate encoded bytes: type mismatch for import `foobar` +missing export named `test:foo/bar` (at offset 0x1d5) \ No newline at end of file diff --git a/crates/wit-component/tests/targets/error-missing-import/error.txt b/crates/wit-component/tests/targets/error-missing-import/error.txt index 3a55fb02c5..d5d32ff920 100644 --- a/crates/wit-component/tests/targets/error-missing-import/error.txt +++ b/crates/wit-component/tests/targets/error-missing-import/error.txt @@ -1,5 +1,2 @@ -failed to validate encoded bytes - -Caused by: - type mismatch for import `foobar` - missing import named `test:foo/foo` (at offset 0x175) \ No newline at end of file +failed to validate encoded bytes: type mismatch for import `foobar` +missing import named `test:foo/foo` (at offset 0x175) \ No newline at end of file diff --git a/crates/wit-parser/tests/all.rs b/crates/wit-parser/tests/all.rs index 6c7af1f75b..ec9d4be941 100644 --- a/crates/wit-parser/tests/all.rs +++ b/crates/wit-parser/tests/all.rs @@ -87,7 +87,7 @@ impl Runner { "some generic platform-agnostic error message", ); } - format!("{:?}", e) + format!("{:#}", e) } } } else { diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-gate3.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-gate3.wit.result index e8e4df1dfe..181a55f67e 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-gate3.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-gate3.wit.result @@ -1,8 +1,5 @@ -this type is not gated by a feature but its interface is gated by a feature - -Caused by: - found a reference to a interface which is excluded due to its feature not being activated - --> tests/ui/parse-fail/bad-gate3.wit:5:8 - | - 5 | type a = u32; - | ^ \ No newline at end of file +this type is not gated by a feature but its interface is gated by a feature: found a reference to a interface which is excluded due to its feature not being activated + --> tests/ui/parse-fail/bad-gate3.wit:5:8 + | + 5 | type a = u32; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-gate4.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-gate4.wit.result index 8b47145a4a..956ba063aa 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-gate4.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-gate4.wit.result @@ -1,8 +1,5 @@ -failed to update function `[constructor]a` - -Caused by: - found a reference to a type which is excluded due to its feature not being activated - --> tests/ui/parse-fail/bad-gate4.wit:6:5 - | - 6 | constructor(); - | ^---------- \ No newline at end of file +failed to update function `[constructor]a`: found a reference to a type which is excluded due to its feature not being activated + --> tests/ui/parse-fail/bad-gate4.wit:6:5 + | + 6 | constructor(); + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-gate5.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-gate5.wit.result index df063dd334..6c36fb3f80 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-gate5.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-gate5.wit.result @@ -1,8 +1,5 @@ -failed to update function `[static]a.x` - -Caused by: - found a reference to a type which is excluded due to its feature not being activated - --> tests/ui/parse-fail/bad-gate5.wit:9:5 - | - 9 | x: static func(); - | ^ \ No newline at end of file +failed to update function `[static]a.x`: found a reference to a type which is excluded due to its feature not being activated + --> tests/ui/parse-fail/bad-gate5.wit:9:5 + | + 9 | x: static func(); + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result index e366b72989..ddc7c7c307 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg1.wit.result @@ -1,9 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg1] - -Caused by: - 0: failed to parse package: tests/ui/parse-fail/bad-pkg1 - 1: interface or world `nonexistent` not found in package - --> tests/ui/parse-fail/bad-pkg1/root.wit:4:7 - | - 4 | use nonexistent.{}; - | ^---------- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg1]: failed to parse package: tests/ui/parse-fail/bad-pkg1: interface or world `nonexistent` not found in package + --> tests/ui/parse-fail/bad-pkg1/root.wit:4:7 + | + 4 | use nonexistent.{}; + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result index 3827d5db46..235a806d21 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg2.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg2] - -Caused by: - interface not found in package - --> tests/ui/parse-fail/bad-pkg2/root.wit:4:15 - | - 4 | use foo:bar/nonexistent.{}; - | ^---------- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg2]: interface not found in package + --> tests/ui/parse-fail/bad-pkg2/root.wit:4:15 + | + 4 | use foo:bar/nonexistent.{}; + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result index f5d61a284e..d3d2102d7b 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg3.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg3] - -Caused by: - interface not found in package - --> tests/ui/parse-fail/bad-pkg3/root.wit:4:15 - | - 4 | use foo:bar/baz.{}; - | ^-- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg3]: interface not found in package + --> tests/ui/parse-fail/bad-pkg3/root.wit:4:15 + | + 4 | use foo:bar/baz.{}; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result index dac51efa32..e4522856ea 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg4.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg4] - -Caused by: - type `a-name` not defined in interface - --> tests/ui/parse-fail/bad-pkg4/root.wit:3:20 - | - 3 | use foo:bar/baz.{a-name}; - | ^----- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg4]: type `a-name` not defined in interface + --> tests/ui/parse-fail/bad-pkg4/root.wit:3:20 + | + 3 | use foo:bar/baz.{a-name}; + | ^----- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result index 2d37060f97..0251000c35 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg5.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg5] - -Caused by: - type `nonexistent` not defined in interface - --> tests/ui/parse-fail/bad-pkg5/root.wit:3:20 - | - 3 | use foo:bar/baz.{nonexistent}; - | ^---------- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg5]: type `nonexistent` not defined in interface + --> tests/ui/parse-fail/bad-pkg5/root.wit:3:20 + | + 3 | use foo:bar/baz.{nonexistent}; + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result index c0fdc9d90e..56b5c85e8f 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-pkg6.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg6] - -Caused by: - package not found - --> tests/ui/parse-fail/bad-pkg6/root.wit:3:7 - | - 3 | use foo:bar/baz.{}; - | ^------ \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-pkg6]: package not found + --> tests/ui/parse-fail/bad-pkg6/root.wit:3:7 + | + 3 | use foo:bar/baz.{}; + | ^------ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-resource15.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-resource15.wit.result index c26467f896..1ed0a4f50b 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-resource15.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/bad-resource15.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-resource15] - -Caused by: - type used in a handle must be a resource - --> tests/ui/parse-fail/bad-resource15/foo.wit:6:16 - | - 6 | type t = own; - | ^ \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/bad-resource15]: type used in a handle must be a resource + --> tests/ui/parse-fail/bad-resource15/foo.wit:6:16 + | + 6 | type t = own; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/conflicting-package.wit.result b/crates/wit-parser/tests/ui/parse-fail/conflicting-package.wit.result index bffa1fc4f1..dc9dcee416 100644 --- a/crates/wit-parser/tests/ui/parse-fail/conflicting-package.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/conflicting-package.wit.result @@ -1,10 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/conflicting-package] - -Caused by: - 0: failed to parse package: tests/ui/parse-fail/conflicting-package - 1: failed to start resolving path: tests/ui/parse-fail/conflicting-package/b.wit - 2: package identifier `foo:b` does not match previous package name of `foo:a` - --> tests/ui/parse-fail/conflicting-package/b.wit:1:9 - | - 1 | package foo:b; - | ^---- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/conflicting-package]: failed to parse package: tests/ui/parse-fail/conflicting-package: failed to start resolving path: tests/ui/parse-fail/conflicting-package/b.wit: package identifier `foo:b` does not match previous package name of `foo:a` + --> tests/ui/parse-fail/conflicting-package/b.wit:1:9 + | + 1 | package foo:b; + | ^---- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2.wit.result b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2.wit.result index 81735c7684..8eb038bf4b 100644 --- a/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/duplicate-interface2.wit.result @@ -1,9 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/duplicate-interface2] - -Caused by: - 0: failed to parse package: tests/ui/parse-fail/duplicate-interface2 - 1: duplicate item named `foo` - --> tests/ui/parse-fail/duplicate-interface2/foo2.wit:3:11 - | - 3 | interface foo {} - | ^-- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/duplicate-interface2]: failed to parse package: tests/ui/parse-fail/duplicate-interface2: duplicate item named `foo` + --> tests/ui/parse-fail/duplicate-interface2/foo2.wit:3:11 + | + 3 | interface foo {} + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/include-foreign.wit.result b/crates/wit-parser/tests/ui/parse-fail/include-foreign.wit.result index 00257283a7..495d331006 100644 --- a/crates/wit-parser/tests/ui/parse-fail/include-foreign.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/include-foreign.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/include-foreign] - -Caused by: - world not found in package - --> tests/ui/parse-fail/include-foreign/root.wit:4:19 - | - 4 | include foo:bar/bar; - | ^-- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/include-foreign]: world not found in package + --> tests/ui/parse-fail/include-foreign/root.wit:4:19 + | + 4 | include foo:bar/bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/multi-file-missing-delimiter.wit.result b/crates/wit-parser/tests/ui/parse-fail/multi-file-missing-delimiter.wit.result index 45400e6389..8182a1a49c 100644 --- a/crates/wit-parser/tests/ui/parse-fail/multi-file-missing-delimiter.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/multi-file-missing-delimiter.wit.result @@ -1,9 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/multi-file-missing-delimiter] - -Caused by: - 0: failed to parse package: tests/ui/parse-fail/multi-file-missing-delimiter - 1: expected `type`, `resource` or `func`, found eof - --> tests/ui/parse-fail/multi-file-missing-delimiter/observe.wit:6:1 - | - 6 | - | ^ \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/multi-file-missing-delimiter]: failed to parse package: tests/ui/parse-fail/multi-file-missing-delimiter: expected `type`, `resource` or `func`, found eof + --> tests/ui/parse-fail/multi-file-missing-delimiter/observe.wit:6:1 + | + 6 | + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/multi-package-deps-share-nest.wit.result b/crates/wit-parser/tests/ui/parse-fail/multi-package-deps-share-nest.wit.result index 31c994e78b..053a98b163 100644 --- a/crates/wit-parser/tests/ui/parse-fail/multi-package-deps-share-nest.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/multi-package-deps-share-nest.wit.result @@ -1,6 +1,3 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/multi-package-deps-share-nest] - -Caused by: - package foo:shared is defined in two different locations: - * tests/ui/parse-fail/multi-package-deps-share-nest/deps/dep2/types.wit:3:9 - * tests/ui/parse-fail/multi-package-deps-share-nest/deps/dep1/types.wit:3:9 \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/multi-package-deps-share-nest]: package foo:shared is defined in two different locations: +* tests/ui/parse-fail/multi-package-deps-share-nest/deps/dep2/types.wit:3:9 +* tests/ui/parse-fail/multi-package-deps-share-nest/deps/dep1/types.wit:3:9 \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs.wit.result b/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs.wit.result index 4ce4423875..fd70371f39 100644 --- a/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/multiple-package-docs.wit.result @@ -1,10 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/multiple-package-docs] - -Caused by: - 0: failed to parse package: tests/ui/parse-fail/multiple-package-docs - 1: failed to start resolving path: tests/ui/parse-fail/multiple-package-docs/b.wit - 2: found doc comments on multiple 'package' items - --> tests/ui/parse-fail/multiple-package-docs/b.wit:1:1 - | - 1 | /// Multiple package docs, B - | ^--------------------------- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/multiple-package-docs]: failed to parse package: tests/ui/parse-fail/multiple-package-docs: failed to start resolving path: tests/ui/parse-fail/multiple-package-docs/b.wit: found doc comments on multiple 'package' items + --> tests/ui/parse-fail/multiple-package-docs/b.wit:1:1 + | + 1 | /// Multiple package docs, B + | ^--------------------------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use.wit.result b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use.wit.result index 72830f2be4..91c398043d 100644 --- a/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/no-access-to-sibling-use.wit.result @@ -1,9 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/no-access-to-sibling-use] - -Caused by: - 0: failed to parse package: tests/ui/parse-fail/no-access-to-sibling-use - 1: interface or world `bar-renamed` does not exist - --> tests/ui/parse-fail/no-access-to-sibling-use/foo.wit:3:5 - | - 3 | use bar-renamed; - | ^---------- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/no-access-to-sibling-use]: failed to parse package: tests/ui/parse-fail/no-access-to-sibling-use: interface or world `bar-renamed` does not exist + --> tests/ui/parse-fail/no-access-to-sibling-use/foo.wit:3:5 + | + 3 | use bar-renamed; + | ^---------- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include.wit.result b/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include.wit.result index 13a112277d..f7c853c8be 100644 --- a/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/non-existance-world-include.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/non-existance-world-include] - -Caused by: - world not found in package - --> tests/ui/parse-fail/non-existance-world-include/root.wit:4:19 - | - 4 | include foo:baz/non-existance; - | ^------------ \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/non-existance-world-include]: world not found in package + --> tests/ui/parse-fail/non-existance-world-include/root.wit:4:19 + | + 4 | include foo:baz/non-existance; + | ^------------ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result index f64970931d..250e158141 100644 --- a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/pkg-cycle] - -Caused by: - package depends on itself - --> tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit:3:7 - | - 3 | use foo:a1/foo.{}; - | ^----- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/pkg-cycle]: package depends on itself + --> tests/ui/parse-fail/pkg-cycle/deps/a1/root.wit:3:7 + | + 3 | use foo:a1/foo.{}; + | ^----- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result index 53054871c2..ec10e18c27 100644 --- a/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/pkg-cycle2.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/pkg-cycle2] - -Caused by: - package depends on itself - --> tests/ui/parse-fail/pkg-cycle2/deps/a1/root.wit:3:7 - | - 3 | use foo:a2/foo.{}; - | ^----- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/pkg-cycle2]: package depends on itself + --> tests/ui/parse-fail/pkg-cycle2/deps/a1/root.wit:3:7 + | + 3 | use foo:a2/foo.{}; + | ^----- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/resources-multiple-returns-borrow.wit.result b/crates/wit-parser/tests/ui/parse-fail/resources-multiple-returns-borrow.wit.result index 2094237fa4..ba5d4f7ff4 100644 --- a/crates/wit-parser/tests/ui/parse-fail/resources-multiple-returns-borrow.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/resources-multiple-returns-borrow.wit.result @@ -1,8 +1,5 @@ -failed to update function `[method]r1.f1` - -Caused by: - function returns a type which contains a `borrow` which is not supported - --> tests/ui/parse-fail/resources-multiple-returns-borrow.wit:7:5 - | - 7 | f1: func() -> (a: s32, handle: borrow); - | ^- \ No newline at end of file +failed to update function `[method]r1.f1`: function returns a type which contains a `borrow` which is not supported + --> tests/ui/parse-fail/resources-multiple-returns-borrow.wit:7:5 + | + 7 | f1: func() -> (a: s32, handle: borrow); + | ^- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/resources-return-borrow.wit.result b/crates/wit-parser/tests/ui/parse-fail/resources-return-borrow.wit.result index 79de329242..b6a7361b67 100644 --- a/crates/wit-parser/tests/ui/parse-fail/resources-return-borrow.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/resources-return-borrow.wit.result @@ -1,8 +1,5 @@ -failed to update function `[method]r1.f1` - -Caused by: - function returns a type which contains a `borrow` which is not supported - --> tests/ui/parse-fail/resources-return-borrow.wit:7:5 - | - 7 | f1: func() -> borrow; - | ^- \ No newline at end of file +failed to update function `[method]r1.f1`: function returns a type which contains a `borrow` which is not supported + --> tests/ui/parse-fail/resources-return-borrow.wit:7:5 + | + 7 | f1: func() -> borrow; + | ^- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/return-borrow1.wit.result b/crates/wit-parser/tests/ui/parse-fail/return-borrow1.wit.result index 0a0468dd60..a4ddb59f1a 100644 --- a/crates/wit-parser/tests/ui/parse-fail/return-borrow1.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/return-borrow1.wit.result @@ -1,8 +1,5 @@ -failed to update function `x` - -Caused by: - function returns a type which contains a `borrow` which is not supported - --> tests/ui/parse-fail/return-borrow1.wit:6:3 - | - 6 | x: func() -> borrow; - | ^ \ No newline at end of file +failed to update function `x`: function returns a type which contains a `borrow` which is not supported + --> tests/ui/parse-fail/return-borrow1.wit:6:3 + | + 6 | x: func() -> borrow; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/return-borrow2.wit.result b/crates/wit-parser/tests/ui/parse-fail/return-borrow2.wit.result index b46631bb96..01c7f6dad1 100644 --- a/crates/wit-parser/tests/ui/parse-fail/return-borrow2.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/return-borrow2.wit.result @@ -1,8 +1,5 @@ -failed to update function `[method]y.x` - -Caused by: - function returns a type which contains a `borrow` which is not supported - --> tests/ui/parse-fail/return-borrow2.wit:5:5 - | - 5 | x: func() -> borrow; - | ^ \ No newline at end of file +failed to update function `[method]y.x`: function returns a type which contains a `borrow` which is not supported + --> tests/ui/parse-fail/return-borrow2.wit:5:5 + | + 5 | x: func() -> borrow; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/return-borrow6.wit.result b/crates/wit-parser/tests/ui/parse-fail/return-borrow6.wit.result index 13d61fba84..e1264b574d 100644 --- a/crates/wit-parser/tests/ui/parse-fail/return-borrow6.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/return-borrow6.wit.result @@ -1,8 +1,5 @@ -failed to update function `x` - -Caused by: - function returns a type which contains a `borrow` which is not supported - --> tests/ui/parse-fail/return-borrow6.wit:6:3 - | - 6 | x: func() -> tuple>; - | ^ \ No newline at end of file +failed to update function `x`: function returns a type which contains a `borrow` which is not supported + --> tests/ui/parse-fail/return-borrow6.wit:6:3 + | + 6 | x: func() -> tuple>; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/return-borrow7.wit.result b/crates/wit-parser/tests/ui/parse-fail/return-borrow7.wit.result index 3caaf3feae..f2175ae6d6 100644 --- a/crates/wit-parser/tests/ui/parse-fail/return-borrow7.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/return-borrow7.wit.result @@ -1,8 +1,5 @@ -failed to update function `x` - -Caused by: - function returns a type which contains a `borrow` which is not supported - --> tests/ui/parse-fail/return-borrow7.wit:10:3 - | - 10 | x: func() -> y2; - | ^ \ No newline at end of file +failed to update function `x`: function returns a type which contains a `borrow` which is not supported + --> tests/ui/parse-fail/return-borrow7.wit:10:3 + | + 10 | x: func() -> y2; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/return-borrow8.wit.result b/crates/wit-parser/tests/ui/parse-fail/return-borrow8.wit.result index 9fd1f02711..3ace7b8be7 100644 --- a/crates/wit-parser/tests/ui/parse-fail/return-borrow8.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/return-borrow8.wit.result @@ -1,9 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/return-borrow8] - -Caused by: - 0: failed to update function `x` - 1: function returns a type which contains a `borrow` which is not supported - --> tests/ui/parse-fail/return-borrow8/foo.wit:6:3 - | - 6 | x: func() -> r; - | ^ \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/return-borrow8]: failed to update function `x`: function returns a type which contains a `borrow` which is not supported + --> tests/ui/parse-fail/return-borrow8/foo.wit:6:3 + | + 6 | x: func() -> r; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name.wit.result b/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name.wit.result index d86ebfb39c..782921c6f2 100644 --- a/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/type-and-resource-same-name.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/type-and-resource-same-name] - -Caused by: - type used in a handle must be a resource - --> tests/ui/parse-fail/type-and-resource-same-name/foo.wit:7:20 - | - 7 | type t2 = borrow; - | ^ \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/type-and-resource-same-name]: type used in a handle must be a resource + --> tests/ui/parse-fail/type-and-resource-same-name/foo.wit:7:20 + | + 7 | type t2 = borrow; + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result index 75343de663..8d36b21d13 100644 --- a/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/unresolved-use10.wit.result @@ -1,9 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/unresolved-use10] - -Caused by: - 0: failed to parse package: tests/ui/parse-fail/unresolved-use10 - 1: name `thing` is not defined - --> tests/ui/parse-fail/unresolved-use10/bar.wit:4:12 - | - 4 | use foo.{thing}; - | ^---- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/unresolved-use10]: failed to parse package: tests/ui/parse-fail/unresolved-use10: name `thing` is not defined + --> tests/ui/parse-fail/unresolved-use10/bar.wit:4:12 + | + 4 | use foo.{thing}; + | ^---- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-and-include-world.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-and-include-world.wit.result index 0d4fcd91ff..e61a285a51 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-and-include-world.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/use-and-include-world.wit.result @@ -1,9 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/use-and-include-world] - -Caused by: - 0: failed to parse package: tests/ui/parse-fail/use-and-include-world - 1: name `bar` is defined as an interface, not a world - --> tests/ui/parse-fail/use-and-include-world/root.wit:6:21 - | - 6 | include foo:baz/bar; - | ^-- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/use-and-include-world]: failed to parse package: tests/ui/parse-fail/use-and-include-world: name `bar` is defined as an interface, not a world + --> tests/ui/parse-fail/use-and-include-world/root.wit:6:21 + | + 6 | include foo:baz/bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/use-world.wit.result b/crates/wit-parser/tests/ui/parse-fail/use-world.wit.result index df56488b01..a85972579b 100644 --- a/crates/wit-parser/tests/ui/parse-fail/use-world.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/use-world.wit.result @@ -1,8 +1,5 @@ -failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/use-world] - -Caused by: - interface not found in package - --> tests/ui/parse-fail/use-world/root.wit:3:13 - | - 3 | use foo:baz/bar; - | ^-- \ No newline at end of file +failed to resolve directory while parsing WIT for path [tests/ui/parse-fail/use-world]: interface not found in package + --> tests/ui/parse-fail/use-world/root.wit:3:13 + | + 3 | use foo:baz/bar; + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/very-nested-packages.wit.result b/crates/wit-parser/tests/ui/parse-fail/very-nested-packages.wit.result index eaf0e67081..3109de9582 100644 --- a/crates/wit-parser/tests/ui/parse-fail/very-nested-packages.wit.result +++ b/crates/wit-parser/tests/ui/parse-fail/very-nested-packages.wit.result @@ -1,8 +1,5 @@ -failed to handle nested package in: tests/ui/parse-fail/very-nested-packages.wit - -Caused by: - nested packages must be placed at the top-level - --> tests/ui/parse-fail/very-nested-packages.wit:4:11 - | - 4 | package a:c2 { - | ^--- \ No newline at end of file +failed to handle nested package in: tests/ui/parse-fail/very-nested-packages.wit: nested packages must be placed at the top-level + --> tests/ui/parse-fail/very-nested-packages.wit:4:11 + | + 4 | package a:c2 { + | ^--- \ No newline at end of file From 97fe512379ca5e9acce9c147a1724746a0a3a08d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Sep 2024 12:44:28 -0500 Subject: [PATCH 10/18] Proceed to the next step in the "remove `interface`" transition (#1753) * Proceed to the next step in the "remove `interface`" transition Starting in WebAssembly/component-model#263 the component model binary specification was updated in a technically breaking way to encode binaries differently. This was intended to be rolled out in a manner that minimized breakage however so bytecodealliance/wasm-tools#1262 implemented validation where the prefix byte which changed was actually ignored if it was 0 or 1. The encoder at the time still emitted 1 as the prefix byte, however. The intention was that once the validator had percolated enough the encoder would switch to using 0. Unfortunately this change was basically forgotten about until now with WebAssembly/component-model#391, but now's probably "enough time passed" so the encoder is updated to emit a 0x00 leading byte in this situation instead of the historical 0x01 byte. This will start the transition period to eventually removing the validator's acceptance of the 0x01 byte. * Update test expectation --- crates/wasm-encoder/src/component/exports.rs | 9 ++++-- crates/wasm-encoder/src/component/imports.rs | 30 ++++++++----------- .../wasm-encoder/src/component/instances.rs | 3 +- crates/wasm-encoder/src/component/types.rs | 8 ++--- .../src/readers/component/imports.rs | 23 +++++++++++--- tests/local/component-model/import.wast | 21 +++++++++++++ tests/roundtrip.rs | 6 +++- .../local/component-model/import.wast.json | 5 ++++ .../component-model/import.wast/75.print | 4 +++ 9 files changed, 77 insertions(+), 32 deletions(-) create mode 100644 tests/snapshots/local/component-model/import.wast/75.print diff --git a/crates/wasm-encoder/src/component/exports.rs b/crates/wasm-encoder/src/component/exports.rs index e4fcfee055..4d988e574b 100644 --- a/crates/wasm-encoder/src/component/exports.rs +++ b/crates/wasm-encoder/src/component/exports.rs @@ -93,8 +93,7 @@ impl ComponentExportSection { index: u32, ty: Option, ) -> &mut Self { - crate::component::imports::push_extern_name_byte(&mut self.bytes, name); - name.encode(&mut self.bytes); + crate::encode_component_export_name(&mut self.bytes, name); kind.encode(&mut self.bytes); index.encode(&mut self.bytes); match ty { @@ -122,3 +121,9 @@ impl ComponentSection for ComponentExportSection { ComponentSectionId::Export.into() } } + +/// For more information on this see `encode_component_import_name`. +pub(crate) fn encode_component_export_name(bytes: &mut Vec, name: &str) { + bytes.push(0x00); + name.encode(bytes); +} diff --git a/crates/wasm-encoder/src/component/imports.rs b/crates/wasm-encoder/src/component/imports.rs index 6337a0625d..b818a17814 100644 --- a/crates/wasm-encoder/src/component/imports.rs +++ b/crates/wasm-encoder/src/component/imports.rs @@ -131,8 +131,7 @@ impl ComponentImportSection { /// Define an import in the component import section. pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { - push_extern_name_byte(&mut self.bytes, name); - name.encode(&mut self.bytes); + encode_component_import_name(&mut self.bytes, name); ty.encode(&mut self.bytes); self.num_added += 1; self @@ -155,21 +154,16 @@ impl ComponentSection for ComponentImportSection { /// discriminated with a leading byte indicating what kind of import they are. /// After that PR though names are always prefixed with a 0x00 byte. /// -/// This function is a compatibility shim for the time being while this change -/// is being rolled out. That PR is technically a spec-breaking change relative -/// to prior but we want old tooling to continue to work with new modules. To -/// handle that names that look like IDs, `a:b/c`, get an 0x01 prefix instead of -/// the spec-defined 0x00 prefix. That makes components produced by current -/// versions of this crate compatible with older parsers. +/// On 2023-10-28 in bytecodealliance/wasm-tools#1262 was landed to start +/// transitioning to "always lead with 0x00". That updated the validator/parser +/// to accept either 0x00 or 0x01 but the encoder wasn't updated at the time. /// -/// Note that wasmparser has a similar case where it parses either 0x01 or 0x00. -/// That means that the selection of a byte here doesn't actually matter for -/// wasmparser's own validation. Eventually this will go away and an 0x00 byte -/// will always be emitted to align with the spec. -pub(crate) fn push_extern_name_byte(bytes: &mut Vec, name: &str) { - if name.contains(':') { - bytes.push(0x01); - } else { - bytes.push(0x00); - } +/// On 2024-09-03 in bytecodealliance/wasm-tools#TODO this encoder was updated +/// to always emit 0x00 as a leading byte. +/// +/// This function corresponds with the `importname'` production in the +/// specification. +pub(crate) fn encode_component_import_name(bytes: &mut Vec, name: &str) { + bytes.push(0x00); + name.encode(bytes); } diff --git a/crates/wasm-encoder/src/component/instances.rs b/crates/wasm-encoder/src/component/instances.rs index e0877d1661..fd3fc3c3af 100644 --- a/crates/wasm-encoder/src/component/instances.rs +++ b/crates/wasm-encoder/src/component/instances.rs @@ -177,8 +177,7 @@ impl ComponentInstanceSection { self.bytes.push(0x01); exports.len().encode(&mut self.bytes); for (name, kind, index) in exports { - crate::push_extern_name_byte(&mut self.bytes, name); - name.encode(&mut self.bytes); + crate::encode_component_export_name(&mut self.bytes, name); kind.encode(&mut self.bytes); index.encode(&mut self.bytes); } diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index 006b9a33e2..aa79d69c94 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -20,7 +20,7 @@ impl ModuleType { /// Defines an import in this module type. pub fn import(&mut self, module: &str, name: &str, ty: EntityType) -> &mut Self { - crate::component::imports::push_extern_name_byte(&mut self.bytes, name); + self.bytes.push(0x00); module.encode(&mut self.bytes); name.encode(&mut self.bytes); ty.encode(&mut self.bytes); @@ -252,8 +252,7 @@ impl ComponentType { /// Defines an import in this component type. pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { self.bytes.push(0x03); - crate::component::imports::push_extern_name_byte(&mut self.bytes, name); - name.encode(&mut self.bytes); + crate::encode_component_import_name(&mut self.bytes, name); ty.encode(&mut self.bytes); self.num_added += 1; match ty { @@ -267,8 +266,7 @@ impl ComponentType { /// Defines an export in this component type. pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { self.bytes.push(0x04); - crate::component::imports::push_extern_name_byte(&mut self.bytes, name); - name.encode(&mut self.bytes); + crate::encode_component_export_name(&mut self.bytes, name); ty.encode(&mut self.bytes); self.num_added += 1; match ty { diff --git a/crates/wasmparser/src/readers/component/imports.rs b/crates/wasmparser/src/readers/component/imports.rs index f62c109310..bd14428d85 100644 --- a/crates/wasmparser/src/readers/component/imports.rs +++ b/crates/wasmparser/src/readers/component/imports.rs @@ -117,12 +117,27 @@ pub struct ComponentImportName<'a>(pub &'a str); impl<'a> FromReader<'a> for ComponentImportName<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result { match reader.read_u8()? { + // This is the spec-required byte as of this time. 0x00 => {} - // Historically export names used a discriminator byte of 0x01 to - // indicate an "interface" of the form `a:b/c` but nowadays that's - // inferred from string syntax. Ignore 0-vs-1 to continue to parse - // older binaries. Eventually this will go away. + + // Prior to WebAssembly/component-model#263 export names used a + // discriminator byte of 0x01 to indicate an "interface" of the + // form `a:b/c` but nowadays that's inferred from string syntax. + // Ignore 0-vs-1 to continue to parse older binaries. Eventually + // this will go away. + // + // This logic to ignore 0x01 was landed on 2023-10-28 in + // bytecodealliance/wasm-tools#1262 and the encoder at the time + // still emitted 0x01 to have better compatibility with prior + // validators. + // + // On 2024-09-03 in bytecodealliance/wasm-tools#TODO the encoder + // was updated to always emit 0x00 as a leading byte. After enough + // time has passed this case may be able to be removed. When + // removing this it's probably best to do it with a `WasmFeatures` + // flag first to ensure there's an opt-in way of fixing things. 0x01 => {} + x => return reader.invalid_leading_byte(x, "import name"), } Ok(ComponentImportName(reader.read_string()?)) diff --git a/tests/local/component-model/import.wast b/tests/local/component-model/import.wast index a04823cf55..b12eca5e53 100644 --- a/tests/local/component-model/import.wast +++ b/tests/local/component-model/import.wast @@ -341,3 +341,24 @@ (assert_invalid (component (import "integrity=" (func))) "unrecognized hash algorithm") + +;; Prior to WebAssembly/component-model#263 this was a valid component. +;; Specifically the 0x01 prefix byte on the import was valid. Nowadays that's +;; not valid in the spec but it's accepted for backwards compatibility. This +;; tests is here to ensure such compatibility. In the future this test should +;; be changed to `(assert_invalid ...)` +(component binary + "\00asm" "\0d\00\01\00" ;; component header + + "\07\05" ;; type section, 5 bytes large + "\01" ;; 1 count + "\40" ;; function + "\00" ;; parameters, 0 count + "\01\00" ;; results, named, 0 count + + "\0a\06" ;; import section, 6 bytes large + "\01" ;; 1 count + "\01" ;; prefix byte of 0x01 (invalid by the spec nowadays) + "\01a" ;; name = "a" + "\01\00" ;; type = func ($type 0) +) diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs index bd40b897e7..5861c6b46e 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -32,6 +32,7 @@ use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use std::sync::Arc; use wasm_encoder::reencode::{Reencode, ReencodeComponent, RoundtripReencoder}; use wasmparser::*; +use wast::component::{Component, ComponentKind}; use wast::core::{Module, ModuleKind}; use wast::lexer::Lexer; use wast::parser::ParseBuffer; @@ -301,8 +302,11 @@ impl TestState { QuoteWat::Wat(Wat::Module(Module { kind: ModuleKind::Binary(_), .. + })) + | QuoteWat::Wat(Wat::Component(Component { + kind: ComponentKind::Binary(_), + .. })) => false, - _ => true, }; diff --git a/tests/snapshots/local/component-model/import.wast.json b/tests/snapshots/local/component-model/import.wast.json index ad84643248..4b291d20ba 100644 --- a/tests/snapshots/local/component-model/import.wast.json +++ b/tests/snapshots/local/component-model/import.wast.json @@ -509,6 +509,11 @@ "filename": "import.74.wasm", "text": "unrecognized hash algorithm", "module_type": "binary" + }, + { + "type": "module", + "line": 350, + "filename": "import.75.wasm" } ] } \ No newline at end of file diff --git a/tests/snapshots/local/component-model/import.wast/75.print b/tests/snapshots/local/component-model/import.wast/75.print new file mode 100644 index 0000000000..e601555176 --- /dev/null +++ b/tests/snapshots/local/component-model/import.wast/75.print @@ -0,0 +1,4 @@ +(component + (type (;0;) (func)) + (import "a" (func (;0;) (type 0))) +) From b1766fbb4042ad525ef5dc4ff45f509d01dd0ae3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Sep 2024 12:45:05 -0500 Subject: [PATCH 11/18] Start moving toward `wasm_encoder` in `wast`'s core wasm encoding (#1767) The `wast` crate is responsible for turning textual WebAssembly into binary WebAssembly. This crate predates the existence of `wasm-encoder` and as such had its own implementation of converting the textual AST to binary. This works by effectively having a method for most AST nodes which says "put yourself into this list of bytes" and then making sure to carefully call everything in the correct order to ensure that the final bytes are indeed valid. Since `wast` was originally created, however, the `wasm-encoder` crate was created. This crate provides a static API and guarantee that the created module will be at least syntactically valid if not semantically valid. This makes emission less error prone and additionally deduplicates the encoding details between `wast` and the `wasm-encoder` crate. For quite some time now the `component` support in the `wast` crate has already been using the `wasm-encoder` crate to encode components. This is done by implementing conversions of AST fragments in `wast` to equivalent fragments in `wasm-encoder`. These conversions are then used to feed data into the right sections to produce the final binary. The purpose of this commit is to start moving in the same direction for core wasm. This commit itself doesn't update all of `binary.rs` but instead only replaces the top-level module with `wasm_encoder::Module`. This updates a few other minor locations too but the bulk of the work is left for a future commit. This is done to ensure there's support for this direction first before completing this work. One downside to this approach is that it might mean that the `wast` crate's binary size grows a bit since the `wasm-encoder` crate isn't quite as "tight" as the encoding in `wast` today. That being said the binary size of `wast` itself has not so far been a concern for anyone and this concern is mostly theoretical and can hopefully be worked around with alternative API design in `wasm-encoder` if needed. Another downside of this approach is that it's coupling `wast` to `wasm-encoder` more tightly, meaning change is harder. That is a good thing in that it reduces duplication but it's a bad thing where if you're only interested in text parsing then it means that adding new features would also require adding features to `wasm-encoder`. This downside is somewhat inescapable though and the only mitigating factor I'd have to offer is that so far most minor wasm extensions have already been coupled with sibling changes to the parser/validator/printer/encoder/etc. This does mean that it's less likely that a new contributor could implement a major proposal like Wasm GC which required large refactorings in all crates (whereas GC was initially implemented in `wast` by an external contributor as it was relatively localized). Overall I personally at least feel that the benefit of not having a duplicate encoder is the worth the tradeoffs here. All other crates in this repository are already deeply intertwined in terms of testing and feature support, and this is continuing that trend for the `wast` crate as well. --- crates/wast/src/core/binary.rs | 89 +++++++++++++++++----------- crates/wast/src/core/binary/dwarf.rs | 5 +- 2 files changed, 57 insertions(+), 37 deletions(-) diff --git a/crates/wast/src/core/binary.rs b/crates/wast/src/core/binary.rs index b64e559a06..8758270936 100644 --- a/crates/wast/src/core/binary.rs +++ b/crates/wast/src/core/binary.rs @@ -6,6 +6,7 @@ use crate::Wat; use std::marker; #[cfg(feature = "dwarf")] use std::path::Path; +use wasm_encoder::SectionId; /// Options that can be specified when encoding a component or a module to /// customize what the final binary looks like. @@ -135,33 +136,35 @@ pub(crate) fn encode( } let mut e = Encoder { - wasm: Vec::new(), + wasm: wasm_encoder::Module::new(), tmp: Vec::new(), customs: &customs, }; - e.wasm.extend(b"\0asm"); - e.wasm.extend(b"\x01\0\0\0"); e.custom_sections(BeforeFirst); - e.section_list(1, Type, &types); - e.section_list(2, Import, &imports); + e.section_list(SectionId::Type, Type, &types); + e.section_list(SectionId::Import, Import, &imports); let functys = funcs.iter().map(|f| &f.ty).collect::>(); - e.section_list(3, Func, &functys); - e.section_list(4, Table, &tables); - e.section_list(5, Memory, &memories); - e.section_list(13, Tag, &tags); - e.section_list(6, Global, &globals); - e.section_list(7, Export, &exports); + e.section_list(SectionId::Function, Func, &functys); + e.section_list(SectionId::Table, Table, &tables); + e.section_list(SectionId::Memory, Memory, &memories); + e.section_list(SectionId::Tag, Tag, &tags); + e.section_list(SectionId::Global, Global, &globals); + e.section_list(SectionId::Export, Export, &exports); e.custom_sections(Before(Start)); if let Some(start) = start.get(0) { - e.section(8, start); + e.wasm.section(&wasm_encoder::StartSection { + function_index: start.unwrap_u32(), + }); } e.custom_sections(After(Start)); - e.section_list(9, Elem, &elem); + e.section_list(SectionId::Element, Elem, &elem); if needs_data_count(&funcs) { - e.section(12, &data.len()); + e.wasm.section(&wasm_encoder::DataCountSection { + count: data.len().try_into().unwrap(), + }); } // Prepare to and emit the code section. This is where DWARF may optionally @@ -175,17 +178,17 @@ pub(crate) fn encode( let mut dwarf = dwarf::Dwarf::new(num_import_funcs, opts, &names, &types); e.code_section(&funcs, num_import_funcs, dwarf.as_mut()); - e.section_list(11, Data, &data); + e.section_list(SectionId::Data, Data, &data); if !names.is_empty() { - e.section(0, &("name", names)); + e.custom_section("name", &names); } e.custom_sections(AfterLast); if let Some(dwarf) = &mut dwarf { dwarf.emit(&mut e); } - return e.wasm; + return e.wasm.finish(); fn needs_data_count(funcs: &[&crate::core::Func<'_>]) -> bool { funcs @@ -200,38 +203,44 @@ pub(crate) fn encode( } struct Encoder<'a> { - wasm: Vec, + wasm: wasm_encoder::Module, tmp: Vec, customs: &'a [&'a Custom<'a>], } impl Encoder<'_> { - fn section(&mut self, id: u8, section: &dyn Encode) { + fn section(&mut self, id: SectionId, section: &dyn Encode) { self.tmp.truncate(0); section.encode(&mut self.tmp); - self.wasm.push(id); - self.tmp.encode(&mut self.wasm); + self.wasm.section(&wasm_encoder::RawSection { + id: id as u8, + data: &self.tmp, + }); } fn custom_sections(&mut self, place: CustomPlace) { for entry in self.customs.iter() { if entry.place() == place { - let mut data = Vec::new(); - entry.encode(&mut data); - self.custom_section(entry.name(), &data); + self.custom_section(entry.name(), entry); } } } - fn custom_section(&mut self, name: &str, data: &[u8]) { + fn custom_section(&mut self, name: &str, data: &dyn Encode) { self.tmp.truncate(0); - name.encode(&mut self.tmp); - self.tmp.extend_from_slice(data); - self.wasm.push(0); - self.tmp.encode(&mut self.wasm); - } - - fn section_list(&mut self, id: u8, anchor: CustomPlaceAnchor, list: &[impl Encode]) { + data.encode(&mut self.tmp); + self.wasm.section(&wasm_encoder::CustomSection { + name: name.into(), + data: (&self.tmp).into(), + }); + } + + fn section_list( + &mut self, + id: wasm_encoder::SectionId, + anchor: CustomPlaceAnchor, + list: &[impl Encode], + ) { self.custom_sections(CustomPlace::Before(anchor)); if !list.is_empty() { self.section(id, &list) @@ -276,12 +285,14 @@ impl Encoder<'_> { // Branch hints section has to be inserted before the Code section // Insert the section only if we have some hints if !branch_hints.is_empty() { - self.section(0, &("metadata.code.branch_hint", branch_hints)); + self.custom_section("metadata.code.branch_hint", &branch_hints); } // Finally, insert the Code section from the tmp buffer - self.wasm.push(10); - code_section.encode(&mut self.wasm); + self.wasm.section(&wasm_encoder::RawSection { + id: wasm_encoder::SectionId::Code as u8, + data: &code_section, + }); if let Some(dwarf) = &mut dwarf { dwarf.set_code_section_size(code_section.len()); @@ -542,8 +553,14 @@ impl Encode for TypeUse<'_, T> { impl Encode for Index<'_> { fn encode(&self, e: &mut Vec) { + self.unwrap_u32().encode(e) + } +} + +impl Index<'_> { + fn unwrap_u32(&self) -> u32 { match self { - Index::Num(n, _) => n.encode(e), + Index::Num(n, _) => *n, Index::Id(n) => panic!("unresolved index in emission: {:?}", n), } } diff --git a/crates/wast/src/core/binary/dwarf.rs b/crates/wast/src/core/binary/dwarf.rs index b6aa086ef9..b080f255c3 100644 --- a/crates/wast/src/core/binary/dwarf.rs +++ b/crates/wast/src/core/binary/dwarf.rs @@ -432,7 +432,10 @@ impl<'a> Dwarf<'a> { sections .for_each(|id, writer| { if !writer.bytes.is_empty() { - dst.custom_section(id.name(), &writer.bytes); + dst.wasm.section(&wasm_encoder::CustomSection { + name: id.name().into(), + data: (&writer.bytes).into(), + }); } Ok::<_, std::convert::Infallible>(()) }) From 50f63d4866515909aef7509282a093576f32713f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Sep 2024 15:40:18 -0500 Subject: [PATCH 12/18] Share more core type infrastructure in components (#1765) This commit chiefly fixes the validator panic found in #1763. This is done by sharing more infrastructure when validating types between the core module validator and the component validator. This sharing is done by extracting a new trait and moving methods from the core module to the trait and then implementing the trait for both component and core contexts. When writing tests this additionally discovered that name resolution on core types wasn't happening within components. The fix there was the same as the core module validator which was to extract shared bits to a trait and then implement the trait in both locations. Closes #1763 --- crates/wasmparser/src/validator/component.rs | 48 ++-- crates/wasmparser/src/validator/core.rs | 207 ++--------------- .../src/validator/core/canonical.rs | 216 ++++++++++++++++-- crates/wast/src/component/binary.rs | 34 +-- crates/wast/src/component/resolve.rs | 12 +- crates/wast/src/core/resolve/mod.rs | 2 + crates/wast/src/core/resolve/names.rs | 117 ++++++---- tests/local/component-model/types.wast | 42 ++++ .../component-model/types.wast | 18 ++ .../local/component-model/types.wast.json | 19 ++ .../local/component-model/types.wast/42.print | 19 ++ .../component-model/types.wast.json | 26 +++ 12 files changed, 472 insertions(+), 288 deletions(-) create mode 100644 tests/local/missing-features/component-model/types.wast create mode 100644 tests/snapshots/local/component-model/types.wast/42.print create mode 100644 tests/snapshots/local/missing-features/component-model/types.wast.json diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 405a03c573..d29f896d74 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -2,7 +2,7 @@ use super::{ check_max, - core::Module, + core::{InternRecGroup, Module}, types::{ AliasableResourceId, ComponentCoreInstanceTypeId, ComponentDefinedTypeId, ComponentFuncType, ComponentFuncTypeId, ComponentInstanceType, ComponentInstanceTypeId, @@ -261,12 +261,18 @@ impl ComponentState { offset: usize, check_limit: bool, ) -> Result<()> { - let id = match ty { + let current = components.last_mut().unwrap(); + if check_limit { + check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; + } + match ty { crate::CoreType::Sub(sub) => { - let (_is_new, group_id) = - types.intern_canonical_rec_group(RecGroup::implicit(offset, sub)); - let id = types[group_id].start; - ComponentCoreTypeId::Sub(id) + current.canonicalize_and_intern_rec_group( + features, + types, + RecGroup::implicit(offset, sub), + offset, + )?; } crate::CoreType::Module(decls) => { let mod_ty = Self::create_module_type( @@ -276,16 +282,11 @@ impl ComponentState { types, offset, )?; - let id = types.push_ty(mod_ty); - ComponentCoreTypeId::Module(id) + let id = ComponentCoreTypeId::Module(types.push_ty(mod_ty)); + components.last_mut().unwrap().core_types.push(id); } - }; - - let current = components.last_mut().unwrap(); - if check_limit { - check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; } - current.core_types.push(id); + Ok(()) } @@ -3036,6 +3037,25 @@ impl ComponentState { } } +impl InternRecGroup for ComponentState { + fn add_type_id(&mut self, id: CoreTypeId) { + self.core_types.push(ComponentCoreTypeId::Sub(id)); + } + + fn type_id_at(&self, idx: u32, offset: usize) -> Result { + match self.core_type_at(idx, offset)? { + ComponentCoreTypeId::Sub(id) => Ok(id), + ComponentCoreTypeId::Module(_) => { + bail!(offset, "type index {idx} is a module type, not a sub type"); + } + } + } + + fn types_len(&self) -> u32 { + u32::try_from(self.core_types.len()).unwrap() + } +} + impl ComponentNameContext { /// Registers that the resource `id` is named `name` within this context. fn register(&mut self, name: &str, id: AliasableResourceId) { diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index 88ec740b53..51ad09a7ae 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -2,18 +2,18 @@ //! mod canonical; +pub(crate) use canonical::InternRecGroup; -use self::{arc::MaybeOwned, canonical::canonicalize_and_intern_rec_group}; +use self::arc::MaybeOwned; use super::{ check_max, combine_type_sizes, operators::{ty_to_str, OperatorValidator, OperatorValidatorAllocations}, types::{CoreTypeId, EntityType, RecGroupId, TypeAlloc, TypeList}, }; use crate::{ - limits::*, validator::types::TypeIdentifier, BinaryReaderError, CompositeType, ConstExpr, Data, - DataKind, Element, ElementKind, ExternalKind, FuncType, Global, GlobalType, HeapType, - MemoryType, PackedIndex, RecGroup, RefType, Result, StorageType, SubType, Table, TableInit, - TableType, TagType, TypeRef, UnpackedIndex, ValType, VisitOperator, WasmFeatures, + limits::*, BinaryReaderError, ConstExpr, Data, DataKind, Element, ElementKind, ExternalKind, + FuncType, Global, GlobalType, HeapType, MemoryType, RecGroup, RefType, Result, SubType, Table, + TableInit, TableType, TagType, TypeRef, UnpackedIndex, ValType, VisitOperator, WasmFeatures, WasmModuleResources, }; use crate::{prelude::*, CompositeInnerType}; @@ -552,21 +552,6 @@ pub(crate) struct Module { } impl Module { - /// Get the `CoreTypeId` of the type at the given packed index. - pub(crate) fn at_packed_index( - &self, - types: &TypeList, - rec_group: RecGroupId, - index: PackedIndex, - offset: usize, - ) -> Result { - match index.unpack() { - UnpackedIndex::Id(id) => Ok(id), - UnpackedIndex::Module(idx) => self.type_id_at(idx, offset), - UnpackedIndex::RecGroup(idx) => types.rec_group_local_id(rec_group, idx, offset), - } - } - pub fn add_types( &mut self, rec_group: RecGroup, @@ -575,14 +560,6 @@ impl Module { offset: usize, check_limit: bool, ) -> Result<()> { - debug_assert!(rec_group.is_explicit_rec_group() || rec_group.types().len() == 1); - if rec_group.is_explicit_rec_group() && !features.gc() { - bail!( - offset, - "rec group usage requires `gc` proposal to be enabled" - ); - } - if check_limit { check_max( self.types.len(), @@ -592,155 +569,7 @@ impl Module { offset, )?; } - - let (is_new, rec_group_id) = - canonicalize_and_intern_rec_group(features, types, self, rec_group, offset)?; - - let range = &types[rec_group_id]; - let start = range.start.index(); - let end = range.end.index(); - - for i in start..end { - let i = u32::try_from(i).unwrap(); - let id = CoreTypeId::from_index(i); - debug_assert!(types.get(id).is_some()); - self.types.push(id); - if is_new { - self.check_subtype(rec_group_id, id, features, types, offset)?; - } - } - - Ok(()) - } - - fn check_subtype( - &mut self, - rec_group: RecGroupId, - id: CoreTypeId, - features: &WasmFeatures, - types: &mut TypeAlloc, - offset: usize, - ) -> Result<()> { - let ty = &types[id]; - if !features.gc() && (!ty.is_final || ty.supertype_idx.is_some()) { - bail!(offset, "gc proposal must be enabled to use subtypes"); - } - - self.check_composite_type(&ty.composite_type, features, &types, offset)?; - - let depth = if let Some(supertype_index) = ty.supertype_idx { - debug_assert!(supertype_index.is_canonical()); - let sup_id = self.at_packed_index(types, rec_group, supertype_index, offset)?; - if types[sup_id].is_final { - bail!(offset, "sub type cannot have a final super type"); - } - if !types.matches(id, sup_id) { - bail!(offset, "sub type must match super type"); - } - let depth = types.get_subtyping_depth(sup_id) + 1; - if usize::from(depth) > crate::limits::MAX_WASM_SUBTYPING_DEPTH { - bail!( - offset, - "sub type hierarchy too deep: found depth {}, cannot exceed depth {}", - depth, - crate::limits::MAX_WASM_SUBTYPING_DEPTH, - ); - } - depth - } else { - 0 - }; - types.set_subtyping_depth(id, depth); - - Ok(()) - } - - fn check_composite_type( - &mut self, - ty: &CompositeType, - features: &WasmFeatures, - types: &TypeList, - offset: usize, - ) -> Result<()> { - let check = |ty: &ValType, shared: bool| { - features - .check_value_type(*ty) - .map_err(|e| BinaryReaderError::new(e, offset))?; - if shared && !types.valtype_is_shared(*ty) { - return Err(BinaryReaderError::new( - "shared composite type must contain shared types", - offset, - )); - // The other cases are fine: - // - both shared or unshared: good to go - // - the func type is unshared, `ty` is shared: though - // odd, we _can_ in fact use shared values in - // unshared composite types (e.g., functions). - } - Ok(()) - }; - if !features.shared_everything_threads() && ty.shared { - return Err(BinaryReaderError::new( - "shared composite types require the shared-everything-threads proposal", - offset, - )); - } - match &ty.inner { - CompositeInnerType::Func(t) => { - for vt in t.params().iter().chain(t.results()) { - check(vt, ty.shared)?; - } - if t.results().len() > 1 && !features.multi_value() { - return Err(BinaryReaderError::new( - "func type returns multiple values but the multi-value feature is not enabled", - offset, - )); - } - } - CompositeInnerType::Array(t) => { - if !features.gc() { - bail!( - offset, - "array indexed types not supported without the gc feature", - ); - } - if !features.gc_types() { - bail!( - offset, - "cannot define array types when gc types are disabled", - ); - } - match &t.0.element_type { - StorageType::I8 | StorageType::I16 => { - // Note: scalar types are always `shared`. - } - StorageType::Val(value_type) => check(value_type, ty.shared)?, - }; - } - CompositeInnerType::Struct(t) => { - if !features.gc() { - bail!( - offset, - "struct indexed types not supported without the gc feature", - ); - } - if !features.gc_types() { - bail!( - offset, - "cannot define struct types when gc types are disabled", - ); - } - for ft in t.fields.iter() { - match &ft.element_type { - StorageType::I8 | StorageType::I16 => { - // Note: scalar types are always `shared`. - } - StorageType::Val(value_type) => check(value_type, ty.shared)?, - } - } - } - } - Ok(()) + self.canonicalize_and_intern_rec_group(features, types, rec_group, offset) } pub fn add_import( @@ -859,13 +688,6 @@ impl Module { Ok(()) } - pub fn type_id_at(&self, idx: u32, offset: usize) -> Result { - self.types - .get(idx as usize) - .copied() - .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds")) - } - fn sub_type_at<'a>(&self, types: &'a TypeList, idx: u32, offset: usize) -> Result<&'a SubType> { let id = self.type_id_at(idx, offset)?; Ok(&types[id]) @@ -1276,6 +1098,23 @@ impl Module { } } +impl InternRecGroup for Module { + fn add_type_id(&mut self, id: CoreTypeId) { + self.types.push(id); + } + + fn type_id_at(&self, idx: u32, offset: usize) -> Result { + self.types + .get(idx as usize) + .copied() + .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds")) + } + + fn types_len(&self) -> u32 { + u32::try_from(self.types.len()).unwrap() + } +} + impl Default for Module { fn default() -> Self { Self { diff --git a/crates/wasmparser/src/validator/core/canonical.rs b/crates/wasmparser/src/validator/core/canonical.rs index 01358d9986..fafb35d338 100644 --- a/crates/wasmparser/src/validator/core/canonical.rs +++ b/crates/wasmparser/src/validator/core/canonical.rs @@ -67,26 +67,202 @@ //! perform additional expensive checks to see if the types match or not //! (since the whole point of canonicalization is to avoid that!). -use super::{Module, RecGroupId, TypeAlloc}; +use super::{RecGroupId, TypeAlloc, TypeList}; use crate::{ types::{CoreTypeId, TypeIdentifier}, - PackedIndex, RecGroup, Result, UnpackedIndex, WasmFeatures, + BinaryReaderError, CompositeInnerType, CompositeType, PackedIndex, RecGroup, Result, + StorageType, UnpackedIndex, ValType, WasmFeatures, }; -/// Canonicalize the rec group and return its id and whether it is a new group -/// (we added its types to the `TypeAlloc`) or not (we deduplicated it with an -/// existing canonical rec group). -pub(crate) fn canonicalize_and_intern_rec_group( - features: &WasmFeatures, - types: &mut TypeAlloc, - module: &Module, - mut rec_group: RecGroup, - offset: usize, -) -> Result<(bool, RecGroupId)> { - TypeCanonicalizer::new(module, offset) - .with_features(features) - .canonicalize_rec_group(&mut rec_group)?; - Ok(types.intern_canonical_rec_group(rec_group)) +pub(crate) trait InternRecGroup { + fn add_type_id(&mut self, id: CoreTypeId); + fn type_id_at(&self, idx: u32, offset: usize) -> Result; + fn types_len(&self) -> u32; + + /// Canonicalize the rec group and return its id and whether it is a new group + /// (we added its types to the `TypeAlloc`) or not (we deduplicated it with an + /// existing canonical rec group). + fn canonicalize_and_intern_rec_group( + &mut self, + features: &WasmFeatures, + types: &mut TypeAlloc, + mut rec_group: RecGroup, + offset: usize, + ) -> Result<()> + where + Self: Sized, + { + debug_assert!(rec_group.is_explicit_rec_group() || rec_group.types().len() == 1); + if rec_group.is_explicit_rec_group() && !features.gc() { + bail!( + offset, + "rec group usage requires `gc` proposal to be enabled" + ); + } + TypeCanonicalizer::new(self, offset) + .with_features(features) + .canonicalize_rec_group(&mut rec_group)?; + let (is_new, rec_group_id) = types.intern_canonical_rec_group(rec_group); + let range = &types[rec_group_id]; + let start = range.start.index(); + let end = range.end.index(); + + for i in start..end { + let i = u32::try_from(i).unwrap(); + let id = CoreTypeId::from_index(i); + debug_assert!(types.get(id).is_some()); + self.add_type_id(id); + if is_new { + self.check_subtype(rec_group_id, id, features, types, offset)?; + } + } + + Ok(()) + } + + fn check_subtype( + &mut self, + rec_group: RecGroupId, + id: CoreTypeId, + features: &WasmFeatures, + types: &mut TypeAlloc, + offset: usize, + ) -> Result<()> { + let ty = &types[id]; + if !features.gc() && (!ty.is_final || ty.supertype_idx.is_some()) { + bail!(offset, "gc proposal must be enabled to use subtypes"); + } + + self.check_composite_type(&ty.composite_type, features, &types, offset)?; + + let depth = if let Some(supertype_index) = ty.supertype_idx { + debug_assert!(supertype_index.is_canonical()); + let sup_id = self.at_packed_index(types, rec_group, supertype_index, offset)?; + if types[sup_id].is_final { + bail!(offset, "sub type cannot have a final super type"); + } + if !types.matches(id, sup_id) { + bail!(offset, "sub type must match super type"); + } + let depth = types.get_subtyping_depth(sup_id) + 1; + if usize::from(depth) > crate::limits::MAX_WASM_SUBTYPING_DEPTH { + bail!( + offset, + "sub type hierarchy too deep: found depth {}, cannot exceed depth {}", + depth, + crate::limits::MAX_WASM_SUBTYPING_DEPTH, + ); + } + depth + } else { + 0 + }; + types.set_subtyping_depth(id, depth); + + Ok(()) + } + + fn check_composite_type( + &mut self, + ty: &CompositeType, + features: &WasmFeatures, + types: &TypeList, + offset: usize, + ) -> Result<()> { + let check = |ty: &ValType, shared: bool| { + features + .check_value_type(*ty) + .map_err(|e| BinaryReaderError::new(e, offset))?; + if shared && !types.valtype_is_shared(*ty) { + return Err(BinaryReaderError::new( + "shared composite type must contain shared types", + offset, + )); + // The other cases are fine: + // - both shared or unshared: good to go + // - the func type is unshared, `ty` is shared: though + // odd, we _can_ in fact use shared values in + // unshared composite types (e.g., functions). + } + Ok(()) + }; + if !features.shared_everything_threads() && ty.shared { + return Err(BinaryReaderError::new( + "shared composite types require the shared-everything-threads proposal", + offset, + )); + } + match &ty.inner { + CompositeInnerType::Func(t) => { + for vt in t.params().iter().chain(t.results()) { + check(vt, ty.shared)?; + } + if t.results().len() > 1 && !features.multi_value() { + return Err(BinaryReaderError::new( + "func type returns multiple values but the multi-value feature is not enabled", + offset, + )); + } + } + CompositeInnerType::Array(t) => { + if !features.gc() { + bail!( + offset, + "array indexed types not supported without the gc feature", + ); + } + if !features.gc_types() { + bail!( + offset, + "cannot define array types when gc types are disabled", + ); + } + match &t.0.element_type { + StorageType::I8 | StorageType::I16 => { + // Note: scalar types are always `shared`. + } + StorageType::Val(value_type) => check(value_type, ty.shared)?, + }; + } + CompositeInnerType::Struct(t) => { + if !features.gc() { + bail!( + offset, + "struct indexed types not supported without the gc feature", + ); + } + if !features.gc_types() { + bail!( + offset, + "cannot define struct types when gc types are disabled", + ); + } + for ft in t.fields.iter() { + match &ft.element_type { + StorageType::I8 | StorageType::I16 => { + // Note: scalar types are always `shared`. + } + StorageType::Val(value_type) => check(value_type, ty.shared)?, + } + } + } + } + Ok(()) + } + + fn at_packed_index( + &self, + types: &TypeList, + rec_group: RecGroupId, + index: PackedIndex, + offset: usize, + ) -> Result { + match index.unpack() { + UnpackedIndex::Id(id) => Ok(id), + UnpackedIndex::Module(idx) => self.type_id_at(idx, offset), + UnpackedIndex::RecGroup(idx) => types.rec_group_local_id(rec_group, idx, offset), + } + } } /// The kind of canonicalization we are doing. @@ -105,7 +281,7 @@ enum CanonicalizationMode { } pub(crate) struct TypeCanonicalizer<'a> { - module: &'a Module, + module: &'a dyn InternRecGroup, features: Option<&'a WasmFeatures>, rec_group_start: u32, rec_group_len: u32, @@ -115,7 +291,7 @@ pub(crate) struct TypeCanonicalizer<'a> { } impl<'a> TypeCanonicalizer<'a> { - pub fn new(module: &'a Module, offset: usize) -> Self { + pub fn new(module: &'a dyn InternRecGroup, offset: usize) -> Self { // These defaults will work for when we are canonicalizing types from // outside of a rec group definition, forcing all `PackedIndex`es to be // canonicalized to `CoreTypeId`s. @@ -147,7 +323,7 @@ impl<'a> TypeCanonicalizer<'a> { // Re-initialize these fields so that we properly canonicalize // intra-rec-group type references into indices into the rec group // rather than as `CoreTypeId`s. - self.rec_group_start = u32::try_from(self.module.types.len()).unwrap(); + self.rec_group_start = self.module.types_len(); self.rec_group_len = u32::try_from(rec_group.types().len()).unwrap(); for (rec_group_local_index, ty) in rec_group.types_mut().enumerate() { @@ -168,7 +344,7 @@ impl<'a> TypeCanonicalizer<'a> { fn canonicalize_type_index(&self, ty: &mut PackedIndex) -> Result<()> { match ty.unpack() { - UnpackedIndex::Id(_) => return Ok(()), + UnpackedIndex::Id(_) => Ok(()), UnpackedIndex::Module(index) => { if index < self.rec_group_start || self.mode == CanonicalizationMode::OnlyIds { let id = self.module.type_id_at(index, self.offset)?; diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index 19806666e1..db1b8b5343 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -606,23 +606,23 @@ impl From> for wasm_encoder::HeapType { fn from(r: core::HeapType<'_>) -> Self { use wasm_encoder::AbstractHeapType::*; match r { - core::HeapType::Abstract { shared, ty } => match ty { - core::AbstractHeapType::Func => Self::Abstract { shared, ty: Func }, - core::AbstractHeapType::Extern => Self::Abstract { shared, ty: Extern }, - core::AbstractHeapType::Exn | core::AbstractHeapType::NoExn => { - todo!("encoding of exceptions proposal types not yet implemented") - } - core::AbstractHeapType::Any - | core::AbstractHeapType::Eq - | core::AbstractHeapType::Struct - | core::AbstractHeapType::Array - | core::AbstractHeapType::NoFunc - | core::AbstractHeapType::NoExtern - | core::AbstractHeapType::None - | core::AbstractHeapType::I31 => { - todo!("encoding of GC proposal types not yet implemented") - } - }, + core::HeapType::Abstract { shared, ty } => { + let ty = match ty { + core::AbstractHeapType::Func => Func, + core::AbstractHeapType::Extern => Extern, + core::AbstractHeapType::Exn => Exn, + core::AbstractHeapType::NoExn => NoExn, + core::AbstractHeapType::Any => Any, + core::AbstractHeapType::Eq => Eq, + core::AbstractHeapType::Struct => Struct, + core::AbstractHeapType::Array => Array, + core::AbstractHeapType::NoFunc => NoFunc, + core::AbstractHeapType::NoExtern => NoExtern, + core::AbstractHeapType::None => None, + core::AbstractHeapType::I31 => I31, + }; + Self::Abstract { shared, ty } + } core::HeapType::Concrete(Index::Num(i, _)) => Self::Concrete(i), core::HeapType::Concrete(_) => panic!("unresolved index"), } diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index ac072c5bf1..1dfd260ad8 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -1,5 +1,5 @@ use crate::component::*; -use crate::core::{self, ValType}; +use crate::core::{self, resolve::ResolveCoreType, ValType}; use crate::kw; use crate::names::Namespace; use crate::token::Span; @@ -475,7 +475,7 @@ impl<'a> Resolver<'a> { fn core_ty(&mut self, field: &mut CoreType<'a>) -> Result<(), Error> { match &mut field.def { - CoreTypeDef::Def(_) => {} + CoreTypeDef::Def(ty) => self.stack.last_mut().unwrap().resolve_type_def(ty)?, CoreTypeDef::Module(t) => { self.stack.push(ComponentState::new(field.id)); self.module_type(t)?; @@ -766,7 +766,7 @@ impl<'a> Resolver<'a> { } impl<'a> ComponentState<'a> { - fn resolve(&mut self, ns: Ns, idx: &mut Index<'a>) -> Result { + fn resolve(&self, ns: Ns, idx: &mut Index<'a>) -> Result { match ns { Ns::CoreFunc => self.core_funcs.resolve(idx, "core func"), Ns::CoreGlobal => self.core_globals.resolve(idx, "core global"), @@ -868,6 +868,12 @@ impl<'a> ComponentState<'a> { } } +impl<'a> ResolveCoreType<'a> for ComponentState<'a> { + fn resolve_type_name(&self, name: &mut Index<'a>) -> Result { + self.resolve(Ns::CoreType, name) + } +} + #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] enum Ns { CoreFunc, diff --git a/crates/wast/src/core/resolve/mod.rs b/crates/wast/src/core/resolve/mod.rs index 7b3ba2b1e3..a5bcf623db 100644 --- a/crates/wast/src/core/resolve/mod.rs +++ b/crates/wast/src/core/resolve/mod.rs @@ -6,6 +6,8 @@ mod deinline_import_export; mod names; pub(crate) mod types; +pub(crate) use names::ResolveCoreType; + #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] pub enum Ns { Func, diff --git a/crates/wast/src/core/resolve/names.rs b/crates/wast/src/core/resolve/names.rs index d84cd9fb35..e1ec617a31 100644 --- a/crates/wast/src/core/resolve/names.rs +++ b/crates/wast/src/core/resolve/names.rs @@ -119,22 +119,6 @@ impl<'a> Resolver<'a> { Ok(()) } - fn resolve_type(&self, ty: &mut Type<'a>) -> Result<(), Error> { - match &mut ty.def.kind { - InnerTypeKind::Func(func) => func.resolve(self)?, - InnerTypeKind::Struct(struct_) => { - for field in &mut struct_.fields { - self.resolve_storagetype(&mut field.ty)?; - } - } - InnerTypeKind::Array(array) => self.resolve_storagetype(&mut array.ty)?, - } - if let Some(parent) = &mut ty.parent { - self.resolve(parent, Ns::Type)?; - } - Ok(()) - } - fn resolve_field(&self, field: &mut ModuleField<'a>) -> Result<(), Error> { match field { ModuleField::Import(i) => { @@ -279,36 +263,6 @@ impl<'a> Resolver<'a> { } } - fn resolve_valtype(&self, ty: &mut ValType<'a>) -> Result<(), Error> { - match ty { - ValType::Ref(ty) => self.resolve_heaptype(&mut ty.heap)?, - _ => {} - } - Ok(()) - } - - fn resolve_reftype(&self, ty: &mut RefType<'a>) -> Result<(), Error> { - self.resolve_heaptype(&mut ty.heap) - } - - fn resolve_heaptype(&self, ty: &mut HeapType<'a>) -> Result<(), Error> { - match ty { - HeapType::Concrete(i) => { - self.resolve(i, Ns::Type)?; - } - _ => {} - } - Ok(()) - } - - fn resolve_storagetype(&self, ty: &mut StorageType<'a>) -> Result<(), Error> { - match ty { - StorageType::Val(ty) => self.resolve_valtype(ty)?, - _ => {} - } - Ok(()) - } - fn resolve_item_sig(&self, item: &mut ItemSig<'a>) -> Result<(), Error> { match &mut item.kind { ItemKind::Func(t) | ItemKind::Tag(TagType::Exception(t)) => { @@ -779,13 +733,76 @@ impl<'a> TypeReference<'a> for FunctionType<'a> { } fn resolve(&mut self, cx: &Resolver<'a>) -> Result<(), Error> { + cx.resolve_type_func(self) + } +} + +pub(crate) trait ResolveCoreType<'a> { + fn resolve_type_name(&self, name: &mut Index<'a>) -> Result; + + fn resolve_type(&self, ty: &mut Type<'a>) -> Result<(), Error> { + self.resolve_type_def(&mut ty.def)?; + if let Some(parent) = &mut ty.parent { + self.resolve_type_name(parent)?; + } + Ok(()) + } + + fn resolve_type_def(&self, ty: &mut TypeDef<'a>) -> Result<(), Error> { + match &mut ty.kind { + InnerTypeKind::Func(func) => self.resolve_type_func(func), + InnerTypeKind::Struct(struct_) => { + for field in &mut struct_.fields { + self.resolve_storagetype(&mut field.ty)?; + } + Ok(()) + } + InnerTypeKind::Array(array) => self.resolve_storagetype(&mut array.ty), + } + } + + fn resolve_type_func(&self, ty: &mut FunctionType<'a>) -> Result<(), Error> { // Resolve the (ref T) value types in the final function type - for param in self.params.iter_mut() { - cx.resolve_valtype(&mut param.2)?; + for param in ty.params.iter_mut() { + self.resolve_valtype(&mut param.2)?; } - for result in self.results.iter_mut() { - cx.resolve_valtype(result)?; + for result in ty.results.iter_mut() { + self.resolve_valtype(result)?; } Ok(()) } + + fn resolve_valtype(&self, ty: &mut ValType<'a>) -> Result<(), Error> { + match ty { + ValType::Ref(ty) => self.resolve_reftype(ty), + ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => Ok(()), + } + } + + fn resolve_reftype(&self, ty: &mut RefType<'a>) -> Result<(), Error> { + self.resolve_heaptype(&mut ty.heap) + } + + fn resolve_heaptype(&self, ty: &mut HeapType<'a>) -> Result<(), Error> { + match ty { + HeapType::Concrete(i) => { + self.resolve_type_name(i)?; + } + HeapType::Abstract { .. } => {} + } + Ok(()) + } + + fn resolve_storagetype(&self, ty: &mut StorageType<'a>) -> Result<(), Error> { + match ty { + StorageType::Val(ty) => self.resolve_valtype(ty), + StorageType::I8 | StorageType::I16 => Ok(()), + } + } +} + +impl<'a> ResolveCoreType<'a> for Resolver<'a> { + fn resolve_type_name(&self, name: &mut Index<'a>) -> Result { + self.resolve(name, Ns::Type) + } } diff --git a/tests/local/component-model/types.wast b/tests/local/component-model/types.wast index 34115c942f..0323cab8e7 100644 --- a/tests/local/component-model/types.wast +++ b/tests/local/component-model/types.wast @@ -357,3 +357,45 @@ )) ) "cannot have more than 32 flags") + +;; test components with non-mvp types +(component + ;; all abstract heap types work + (core type (func (param (ref any)))) + (core type (func (param (ref func)))) + (core type (func (param (ref extern)))) + (core type (func (param (ref exn)))) + (core type (func (param (ref noexn)))) + (core type (func (param (ref eq)))) + (core type (func (param (ref struct)))) + (core type (func (param (ref array)))) + (core type (func (param (ref nofunc)))) + (core type (func (param (ref noextern)))) + (core type (func (param (ref none)))) + (core type (func (param (ref i31)))) + + ;; some shorthands work + (core type (func (param anyref))) + (core type (func (param eqref))) + + ;; simd types work + (core type (func (param v128))) + + ;; types-pointing-to-types works + (core type $t (func)) + (core type (func (param (ref $t)))) + +) + +(assert_invalid + (component + (core type $t (module)) + (core type (func (param (ref $t)))) + ) + "type index 0 is a module type") + +(assert_invalid + (component + (core type (func (param (ref 100)))) + ) + "type index out of bounds") diff --git a/tests/local/missing-features/component-model/types.wast b/tests/local/missing-features/component-model/types.wast new file mode 100644 index 0000000000..b4d4772d3d --- /dev/null +++ b/tests/local/missing-features/component-model/types.wast @@ -0,0 +1,18 @@ +(assert_invalid + (component + (core type (func (param v128))) + ) + "SIMD support is not enabled") + +(assert_invalid + (component + (core type (func (param (ref 0)))) + ) + "unknown type 0: type index out of bounds") + +(assert_invalid + (component + (core type (func)) + (core type (func (param (ref 0)))) + ) + "reference types support is not enabled") diff --git a/tests/snapshots/local/component-model/types.wast.json b/tests/snapshots/local/component-model/types.wast.json index 8279f094ca..a606256226 100644 --- a/tests/snapshots/local/component-model/types.wast.json +++ b/tests/snapshots/local/component-model/types.wast.json @@ -283,6 +283,25 @@ "filename": "types.41.wasm", "text": "cannot have more than 32 flags", "module_type": "binary" + }, + { + "type": "module", + "line": 362, + "filename": "types.42.wasm" + }, + { + "type": "assert_invalid", + "line": 391, + "filename": "types.43.wasm", + "text": "type index 0 is a module type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 398, + "filename": "types.44.wasm", + "text": "type index out of bounds", + "module_type": "binary" } ] } \ No newline at end of file diff --git a/tests/snapshots/local/component-model/types.wast/42.print b/tests/snapshots/local/component-model/types.wast/42.print new file mode 100644 index 0000000000..233982b2c2 --- /dev/null +++ b/tests/snapshots/local/component-model/types.wast/42.print @@ -0,0 +1,19 @@ +(component + (core type (;0;) (func (param (ref any)))) + (core type (;1;) (func (param (ref func)))) + (core type (;2;) (func (param (ref extern)))) + (core type (;3;) (func (param (ref exn)))) + (core type (;4;) (func (param (ref noexn)))) + (core type (;5;) (func (param (ref eq)))) + (core type (;6;) (func (param (ref struct)))) + (core type (;7;) (func (param (ref array)))) + (core type (;8;) (func (param (ref nofunc)))) + (core type (;9;) (func (param (ref noextern)))) + (core type (;10;) (func (param (ref none)))) + (core type (;11;) (func (param (ref i31)))) + (core type (;12;) (func (param anyref))) + (core type (;13;) (func (param eqref))) + (core type (;14;) (func (param v128))) + (core type $t (;15;) (func)) + (core type (;16;) (func (param (ref $t)))) +) diff --git a/tests/snapshots/local/missing-features/component-model/types.wast.json b/tests/snapshots/local/missing-features/component-model/types.wast.json new file mode 100644 index 0000000000..876d023287 --- /dev/null +++ b/tests/snapshots/local/missing-features/component-model/types.wast.json @@ -0,0 +1,26 @@ +{ + "source_filename": "tests/local/missing-features/component-model/types.wast", + "commands": [ + { + "type": "assert_invalid", + "line": 2, + "filename": "types.0.wasm", + "text": "SIMD support is not enabled", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 8, + "filename": "types.1.wasm", + "text": "unknown type 0: type index out of bounds", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 14, + "filename": "types.2.wasm", + "text": "reference types support is not enabled", + "module_type": "binary" + } + ] +} \ No newline at end of file From 346f26c1d7e58b15316efbf5a58e6a2618c70f22 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 9 Sep 2024 13:46:21 -0700 Subject: [PATCH 13/18] Rename `MaybeType` variants, tweak documentation (#1737) * Rename `MaybeType` variants, tweak documentation This tweaks #1734 to use terms I consider a bit more clear. It also updates the documentation to explain some more of the context that I currently have paged in but may not later. * review: tweak naming for @fitzgen --- crates/wasmparser/src/validator/operators.rs | 132 ++++++++++--------- 1 file changed, 70 insertions(+), 62 deletions(-) diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index cd94153bb0..2e8e2ac416 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -163,23 +163,31 @@ pub struct OperatorValidatorAllocations { /// Type storage within the validator. /// -/// This is used to manage the operand stack and notably isn't just `ValType` -/// to handle unreachable code and the "bottom" type. +/// When managing the operand stack in unreachable code, the validator may not +/// fully know an operand's type. this unknown state is known as the `bottom` +/// type in the WebAssembly specification. Validating further instructions may +/// give us more information; either partial (`PartialRef`) or fully known. #[derive(Debug, Copy, Clone)] enum MaybeType { - /// A "bottom" type which represents unconstrained unreachable code. There - /// are no constraints on what this type may be. - Bot, - /// A "bottom" type for specifically heap types. + /// The operand has no available type information due to unreachable code. /// - /// This type is known to be a reference type, optionally the specific - /// abstract heap type listed. This type can be interpeted as either - /// `shared` or not-`shared`. Additionally it can be either nullable or - /// not. Currently no further refinements are required for wasm - /// instructions today, but this may grow in the future. - HeapBot(Option), - /// A known type with the type `T`. - Type(T), + /// This state represents "unknown" and corresponds to the `bottom` type in + /// the WebAssembly specification. There are no constraints on what this + /// type may be and it can match any other type during validation. + Bottom, + /// The operand is known to be a reference and we may know its abstract + /// type. + /// + /// This state is not fully `Known`, however, because its type can be + /// interpreted as either: + /// - `shared` or not-`shared` + /// - nullable or not nullable + /// + /// No further refinements are required for WebAssembly instructions today + /// but this may grow in the future. + UnknownRef(Option), + /// The operand is known to have type `T`. + Known(T), } // The validator is pretty performance-sensitive and `MaybeType` is the main @@ -192,8 +200,8 @@ const _: () = { impl core::fmt::Display for MaybeType { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - MaybeType::Bot => write!(f, "bot"), - MaybeType::HeapBot(ty) => { + MaybeType::Bottom => write!(f, "bot"), + MaybeType::UnknownRef(ty) => { write!(f, "(ref shared? ")?; match ty { Some(ty) => write!(f, "{}bot", ty.as_str(true))?, @@ -201,14 +209,14 @@ impl core::fmt::Display for MaybeType { } write!(f, ")") } - MaybeType::Type(ty) => core::fmt::Display::fmt(ty, f), + MaybeType::Known(ty) => core::fmt::Display::fmt(ty, f), } } } impl From for MaybeType { fn from(ty: ValType) -> MaybeType { - MaybeType::Type(ty) + MaybeType::Known(ty) } } @@ -221,9 +229,9 @@ impl From for MaybeType { impl From> for MaybeType { fn from(ty: MaybeType) -> MaybeType { match ty { - MaybeType::Bot => MaybeType::Bot, - MaybeType::HeapBot(ty) => MaybeType::HeapBot(ty), - MaybeType::Type(t) => MaybeType::Type(t.into()), + MaybeType::Bottom => MaybeType::Bottom, + MaybeType::UnknownRef(ty) => MaybeType::UnknownRef(ty), + MaybeType::Known(t) => MaybeType::Known(t.into()), } } } @@ -231,17 +239,17 @@ impl From> for MaybeType { impl MaybeType { fn as_non_null(&self) -> MaybeType { match self { - MaybeType::Bot => MaybeType::Bot, - MaybeType::HeapBot(ty) => MaybeType::HeapBot(*ty), - MaybeType::Type(ty) => MaybeType::Type(ty.as_non_null()), + MaybeType::Bottom => MaybeType::Bottom, + MaybeType::UnknownRef(ty) => MaybeType::UnknownRef(*ty), + MaybeType::Known(ty) => MaybeType::Known(ty.as_non_null()), } } fn is_maybe_shared(&self, resources: &impl WasmModuleResources) -> Option { match self { - MaybeType::Bot => None, - MaybeType::HeapBot(_) => None, - MaybeType::Type(ty) => Some(resources.is_shared(*ty)), + MaybeType::Bottom => None, + MaybeType::UnknownRef(_) => None, + MaybeType::Known(ty) => Some(resources.is_shared(*ty)), } } } @@ -390,8 +398,8 @@ impl OperatorValidator { /// A `depth` of 0 will refer to the last operand on the stack. pub fn peek_operand_at(&self, depth: usize) -> Option> { Some(match self.operands.iter().rev().nth(depth)? { - MaybeType::Type(t) => Some(*t), - MaybeType::Bot | MaybeType::HeapBot(..) => None, + MaybeType::Known(t) => Some(*t), + MaybeType::Bottom | MaybeType::UnknownRef(..) => None, }) } @@ -490,7 +498,7 @@ where if cfg!(debug_assertions) { match maybe_ty { - MaybeType::Type(ValType::Ref(r)) => match r.heap_type() { + MaybeType::Known(ValType::Ref(r)) => match r.heap_type() { HeapType::Concrete(index) => { debug_assert!( matches!(index, UnpackedIndex::Id(_)), @@ -582,15 +590,15 @@ where // pop it. If we shouldn't have popped it then it's passed to the slow // path to get pushed back onto the stack. let popped = match self.operands.pop() { - Some(MaybeType::Type(actual_ty)) => { + Some(MaybeType::Known(actual_ty)) => { if Some(actual_ty) == expected { if let Some(control) = self.control.last() { if self.operands.len() >= control.height { - return Ok(MaybeType::Type(actual_ty)); + return Ok(MaybeType::Known(actual_ty)); } } } - Some(MaybeType::Type(actual_ty)) + Some(MaybeType::Known(actual_ty)) } other => other, }; @@ -613,7 +621,7 @@ where None => return Err(self.err_beyond_end(self.offset)), }; let actual = if self.operands.len() == control.height && control.unreachable { - MaybeType::Bot + MaybeType::Bottom } else { if self.operands.len() == control.height { let desc = match expected { @@ -631,13 +639,13 @@ where if let Some(expected) = expected { match (actual, expected) { // The bottom type matches all expectations - (MaybeType::Bot, _) => {} + (MaybeType::Bottom, _) => {} // The "heap bottom" type only matches other references types, // but not any integer types. Note that if the heap bottom is // known to have a specific abstract heap type then a subtype // check is performed against hte expected type. - (MaybeType::HeapBot(actual_ty), ValType::Ref(expected)) => { + (MaybeType::UnknownRef(actual_ty), ValType::Ref(expected)) => { if let Some(actual) = actual_ty { let expected_shared = self.resources.is_shared(expected); let actual = RefType::new( @@ -661,7 +669,7 @@ where // Use the `is_subtype` predicate to test if a found type matches // the expectation. - (MaybeType::Type(actual), expected) => { + (MaybeType::Known(actual), expected) => { if !self.resources.is_subtype(actual, expected) { bail!( self.offset, @@ -674,7 +682,7 @@ where // A "heap bottom" type cannot match any numeric types. ( - MaybeType::HeapBot(..), + MaybeType::UnknownRef(..), ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128, ) => { bail!( @@ -691,10 +699,10 @@ where /// Pop a reference type from the operand stack. fn pop_ref(&mut self, expected: Option) -> Result> { match self.pop_operand(expected.map(|t| t.into()))? { - MaybeType::Bot => Ok(MaybeType::HeapBot(None)), - MaybeType::HeapBot(ty) => Ok(MaybeType::HeapBot(ty)), - MaybeType::Type(ValType::Ref(rt)) => Ok(MaybeType::Type(rt)), - MaybeType::Type(ty) => bail!( + MaybeType::Bottom => Ok(MaybeType::UnknownRef(None)), + MaybeType::UnknownRef(ty) => Ok(MaybeType::UnknownRef(ty)), + MaybeType::Known(ValType::Ref(rt)) => Ok(MaybeType::Known(rt)), + MaybeType::Known(ty) => bail!( self.offset, "type mismatch: expected ref but found {}", ty_to_str(ty) @@ -709,9 +717,9 @@ where /// saving extra lookups for concrete types. fn pop_maybe_shared_ref(&mut self, expected: AbstractHeapType) -> Result> { let actual = match self.pop_ref(None)? { - MaybeType::Bot => return Ok(MaybeType::Bot), - MaybeType::HeapBot(None) => return Ok(MaybeType::HeapBot(None)), - MaybeType::HeapBot(Some(actual)) => { + MaybeType::Bottom => return Ok(MaybeType::Bottom), + MaybeType::UnknownRef(None) => return Ok(MaybeType::UnknownRef(None)), + MaybeType::UnknownRef(Some(actual)) => { if !actual.is_subtype_of(expected) { bail!( self.offset, @@ -720,9 +728,9 @@ where actual.as_str(false), ) } - return Ok(MaybeType::HeapBot(Some(actual))); + return Ok(MaybeType::UnknownRef(Some(actual))); } - MaybeType::Type(ty) => ty, + MaybeType::Known(ty) => ty, }; // Change our expectation based on whether we're dealing with an actual // shared or unshared type. @@ -745,7 +753,7 @@ where "type mismatch: expected subtype of {expected}, found {actual}", ) } - Ok(MaybeType::Type(actual)) + Ok(MaybeType::Known(actual)) } /// Fetches the type for the local at `idx`, returning an error if it's out @@ -1824,10 +1832,10 @@ where let ty = match (ty1, ty2) { // All heap-related types aren't allowed with the `select` // instruction - (MaybeType::HeapBot(..), _) - | (_, MaybeType::HeapBot(..)) - | (MaybeType::Type(ValType::Ref(_)), _) - | (_, MaybeType::Type(ValType::Ref(_))) => { + (MaybeType::UnknownRef(..), _) + | (_, MaybeType::UnknownRef(..)) + | (MaybeType::Known(ValType::Ref(_)), _) + | (_, MaybeType::Known(ValType::Ref(_))) => { bail!( self.offset, "type mismatch: select only takes integral types" @@ -1836,11 +1844,11 @@ where // If one operand is the "bottom" type then whatever the other // operand is is the result of the `select` - (MaybeType::Bot, t) | (t, MaybeType::Bot) => t, + (MaybeType::Bottom, t) | (t, MaybeType::Bottom) => t, // Otherwise these are two integral types and they must match for // `select` to typecheck. - (t @ MaybeType::Type(t1), MaybeType::Type(t2)) => { + (t @ MaybeType::Known(t1), MaybeType::Known(t2)) => { if t1 != t2 { bail!( self.offset, @@ -4508,34 +4516,34 @@ where } fn visit_any_convert_extern(&mut self) -> Self::Output { let any_ref = match self.pop_maybe_shared_ref(AbstractHeapType::Extern)? { - MaybeType::Bot | MaybeType::HeapBot(_) => { - MaybeType::HeapBot(Some(AbstractHeapType::Any)) + MaybeType::Bottom | MaybeType::UnknownRef(_) => { + MaybeType::UnknownRef(Some(AbstractHeapType::Any)) } - MaybeType::Type(ty) => { + MaybeType::Known(ty) => { let shared = self.resources.is_shared(ty); let heap_type = HeapType::Abstract { shared, ty: AbstractHeapType::Any, }; let any_ref = RefType::new(ty.is_nullable(), heap_type).unwrap(); - MaybeType::Type(any_ref) + MaybeType::Known(any_ref) } }; self.push_operand(any_ref) } fn visit_extern_convert_any(&mut self) -> Self::Output { let extern_ref = match self.pop_maybe_shared_ref(AbstractHeapType::Any)? { - MaybeType::Bot | MaybeType::HeapBot(_) => { - MaybeType::HeapBot(Some(AbstractHeapType::Extern)) + MaybeType::Bottom | MaybeType::UnknownRef(_) => { + MaybeType::UnknownRef(Some(AbstractHeapType::Extern)) } - MaybeType::Type(ty) => { + MaybeType::Known(ty) => { let shared = self.resources.is_shared(ty); let heap_type = HeapType::Abstract { shared, ty: AbstractHeapType::Extern, }; let extern_ref = RefType::new(ty.is_nullable(), heap_type).unwrap(); - MaybeType::Type(extern_ref) + MaybeType::Known(extern_ref) } }; self.push_operand(extern_ref) From 668cb31a5acead65240da7433a08875e8c6ba5a4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Sep 2024 16:58:38 -0500 Subject: [PATCH 14/18] Fix wasm-smith's page_size calculation (#1770) Pointed out in [this comment] this should help `wasm-smith` generate offsets/data segments with a wider range of valid values in wasm-smith rather than accidentally thinking the page size is much smaller than it actually is. [this comment]: https://github.com/bytecodealliance/wasm-tools/commit/fe1307be46d0a30b5332ae12b219dd90cc90fbe4#r146408758 --- crates/wasm-smith/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/wasm-smith/src/lib.rs b/crates/wasm-smith/src/lib.rs index 59d4ddb640..d1669853f1 100644 --- a/crates/wasm-smith/src/lib.rs +++ b/crates/wasm-smith/src/lib.rs @@ -69,8 +69,8 @@ use wasm_encoder::MemoryType; pub use config::InternalOptionalConfig; pub(crate) fn page_size(mem: &MemoryType) -> u32 { - const DEFAULT_WASM_PAGE_SIZE: u32 = 65_536; - mem.page_size_log2.unwrap_or(DEFAULT_WASM_PAGE_SIZE) + const DEFAULT_WASM_PAGE_SIZE_LOG2: u32 = 16; + 1 << mem.page_size_log2.unwrap_or(DEFAULT_WASM_PAGE_SIZE_LOG2) } /// Do something an arbitrary number of times. From ebfd6a04d548cab0cf56fb33b51f19f75053af49 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Sep 2024 18:16:05 -0500 Subject: [PATCH 15/18] Tweak printing page sizes in text format (#1769) Put a space before `(pagesize ...)` and additionally use `start_group`/`end_group` so it gets colors automatically applied. --- crates/wasmprinter/src/lib.rs | 6 +++++- .../local/custom-page-sizes/custom-page-sizes.wast/0.print | 2 +- .../local/custom-page-sizes/custom-page-sizes.wast/1.print | 2 +- .../local/custom-page-sizes/custom-page-sizes.wast/19.print | 2 +- .../local/custom-page-sizes/custom-page-sizes.wast/2.print | 2 +- .../local/custom-page-sizes/custom-page-sizes.wast/23.print | 4 ++-- .../local/custom-page-sizes/custom-page-sizes.wast/3.print | 2 +- .../local/custom-page-sizes/custom-page-sizes.wast/4.print | 2 +- 8 files changed, 13 insertions(+), 9 deletions(-) diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index 4c54dc8c87..c682e92d58 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -1159,7 +1159,11 @@ impl Printer<'_, '_> { let p = 1_u64 .checked_shl(p) .ok_or_else(|| anyhow!("left shift overflow").context("invalid page size"))?; - write!(self.result, "(pagesize {p:#x})")?; + + self.result.write_str(" ")?; + self.start_group("pagesize ")?; + write!(self.result, "{p:#x}")?; + self.end_group()?; } Ok(()) } diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/0.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/0.print index bdb1afc777..01f8bab139 100644 --- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/0.print +++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/0.print @@ -1,3 +1,3 @@ (module - (memory (;0;) 1(pagesize 0x1)) + (memory (;0;) 1 (pagesize 0x1)) ) diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/1.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/1.print index c263f1833f..a86edfbcef 100644 --- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/1.print +++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/1.print @@ -1,3 +1,3 @@ (module - (memory (;0;) 1(pagesize 0x10000)) + (memory (;0;) 1 (pagesize 0x10000)) ) diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/19.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/19.print index 2f377e5a28..9d393fba79 100644 --- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/19.print +++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/19.print @@ -4,6 +4,6 @@ local.get 0 memory.grow ) - (memory (;0;) 0(pagesize 0x10000)) + (memory (;0;) 0 (pagesize 0x10000)) (export "grow" (func 0)) ) diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/2.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/2.print index b28b44796e..fccfed30d0 100644 --- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/2.print +++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/2.print @@ -1,3 +1,3 @@ (module - (memory (;0;) 1 2(pagesize 0x1)) + (memory (;0;) 1 2 (pagesize 0x1)) ) diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/23.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/23.print index 1c3b7326d8..c247b5f533 100644 --- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/23.print +++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/23.print @@ -21,8 +21,8 @@ local.get 0 i32.load8_u ) - (memory $small (;0;) 10(pagesize 0x1)) - (memory $large (;1;) 1(pagesize 0x10000)) + (memory $small (;0;) 10 (pagesize 0x1)) + (memory $large (;1;) 1 (pagesize 0x10000)) (export "copy-small-to-large" (func 0)) (export "copy-large-to-small" (func 1)) (export "load8-small" (func 2)) diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/3.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/3.print index afb7ad5c56..f8915ffd73 100644 --- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/3.print +++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/3.print @@ -1,3 +1,3 @@ (module - (memory (;0;) 1 2(pagesize 0x10000)) + (memory (;0;) 1 2 (pagesize 0x10000)) ) diff --git a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/4.print b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/4.print index 388265c290..71c30c5fdc 100644 --- a/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/4.print +++ b/tests/snapshots/local/custom-page-sizes/custom-page-sizes.wast/4.print @@ -18,7 +18,7 @@ local.get 1 i32.store ) - (memory (;0;) 0(pagesize 0x1)) + (memory (;0;) 0 (pagesize 0x1)) (export "size" (func 0)) (export "grow" (func 1)) (export "load" (func 2)) From dabd1cdc0a1cfa3fa87a5d49681ae060359e0855 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 10 Sep 2024 09:33:21 -0500 Subject: [PATCH 16/18] Update `*.wast` parser with recently added directives (#1762) * Update `*.wast` parser with recently added directives Parsing them is a bit wonky because it looks like this crate isn't architected the same way as the reference interpreter, but this so far otherwise seems to work. I've copied the upstream test added in WebAssembly/spec#1796 here for reference. * Fix compile of benches * Minor fixes --- crates/wasmparser/benches/benchmark.rs | 3 +- crates/wast/src/component/component.rs | 24 +- crates/wast/src/core/module.rs | 25 +- crates/wast/src/lib.rs | 1 + crates/wast/src/parser.rs | 13 + crates/wast/src/wast.rs | 147 +++++++++-- crates/wast/src/wat.rs | 36 ++- src/bin/wasm-tools/json_from_wast.rs | 39 ++- tests/local/instance.wast | 170 +++++++++++++ tests/roundtrip.rs | 5 +- tests/snapshots/local/instance.wast.json | 245 +++++++++++++++++++ tests/snapshots/local/instance.wast/0.print | 11 + tests/snapshots/local/instance.wast/10.print | 52 ++++ tests/snapshots/local/instance.wast/15.print | 15 ++ tests/snapshots/local/instance.wast/18.print | 52 ++++ tests/snapshots/local/instance.wast/5.print | 52 ++++ 16 files changed, 812 insertions(+), 78 deletions(-) create mode 100644 tests/local/instance.wast create mode 100644 tests/snapshots/local/instance.wast.json create mode 100644 tests/snapshots/local/instance.wast/0.print create mode 100644 tests/snapshots/local/instance.wast/10.print create mode 100644 tests/snapshots/local/instance.wast/15.print create mode 100644 tests/snapshots/local/instance.wast/18.print create mode 100644 tests/snapshots/local/instance.wast/5.print diff --git a/crates/wasmparser/benches/benchmark.rs b/crates/wasmparser/benches/benchmark.rs index e5cdd4b495..8ec6e45612 100644 --- a/crates/wasmparser/benches/benchmark.rs +++ b/crates/wasmparser/benches/benchmark.rs @@ -58,7 +58,8 @@ fn collect_test_files(path: &Path, list: &mut Vec) -> Result<()> }; for directive in wast.directives { match directive { - wast::WastDirective::Wat(mut module) => { + wast::WastDirective::Module(mut module) + | wast::WastDirective::ModuleDefinition(mut module) => { let wasm = module.encode()?; list.push(BenchmarkInput::new(path.clone(), wasm)); } diff --git a/crates/wast/src/component/component.rs b/crates/wast/src/component/component.rs index 1660a8740f..36c823190f 100644 --- a/crates/wast/src/component/component.rs +++ b/crates/wast/src/component/component.rs @@ -103,16 +103,11 @@ impl<'a> Component<'a> { } Ok(()) } -} - -impl<'a> Parse<'a> for Component<'a> { - fn parse(parser: Parser<'a>) -> Result { - let _r = parser.register_annotation("custom"); - let _r = parser.register_annotation("producers"); - let _r = parser.register_annotation("name"); - let _r = parser.register_annotation("metadata.code.branch_hint"); - let span = parser.parse::()?.0; + pub(crate) fn parse_without_component_keyword( + component_keyword_span: Span, + parser: Parser<'a>, + ) -> Result { let id = parser.parse()?; let name = parser.parse()?; @@ -127,7 +122,7 @@ impl<'a> Parse<'a> for Component<'a> { ComponentKind::Text(ComponentField::parse_remaining(parser)?) }; Ok(Component { - span, + span: component_keyword_span, id, name, kind, @@ -135,6 +130,15 @@ impl<'a> Parse<'a> for Component<'a> { } } +impl<'a> Parse<'a> for Component<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.with_standard_annotations_registered(|parser| { + let span = parser.parse::()?.0; + Component::parse_without_component_keyword(span, parser) + }) + } +} + /// A listing of all possible fields that can make up a WebAssembly component. #[allow(missing_docs)] #[derive(Debug)] diff --git a/crates/wast/src/core/module.rs b/crates/wast/src/core/module.rs index 39a60f519c..e80719630b 100644 --- a/crates/wast/src/core/module.rs +++ b/crates/wast/src/core/module.rs @@ -103,17 +103,11 @@ impl<'a> Module<'a> { } Ok(()) } -} -impl<'a> Parse<'a> for Module<'a> { - fn parse(parser: Parser<'a>) -> Result { - let _r = parser.register_annotation("custom"); - let _r = parser.register_annotation("producers"); - let _r = parser.register_annotation("name"); - let _r = parser.register_annotation("dylink.0"); - let _r = parser.register_annotation("metadata.code.branch_hint"); - - let span = parser.parse::()?.0; + pub(crate) fn parse_without_module_keyword( + module_keyword_span: Span, + parser: Parser<'a>, + ) -> Result { let id = parser.parse()?; let name = parser.parse()?; @@ -128,7 +122,7 @@ impl<'a> Parse<'a> for Module<'a> { ModuleKind::Text(ModuleField::parse_remaining(parser)?) }; Ok(Module { - span, + span: module_keyword_span, id, name, kind, @@ -136,6 +130,15 @@ impl<'a> Parse<'a> for Module<'a> { } } +impl<'a> Parse<'a> for Module<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.with_standard_annotations_registered(|parser| { + let span = parser.parse::()?.0; + Self::parse_without_module_keyword(span, parser) + }) + } +} + /// A listing of all possible fields that can make up a WebAssembly module. #[allow(missing_docs)] #[derive(Debug)] diff --git a/crates/wast/src/lib.rs b/crates/wast/src/lib.rs index 9fbb5c6431..c757c0f48f 100644 --- a/crates/wast/src/lib.rs +++ b/crates/wast/src/lib.rs @@ -544,6 +544,7 @@ pub mod kw { custom_keyword!(import_info = "import-info"); custom_keyword!(thread); custom_keyword!(wait); + custom_keyword!(definition); } /// Common annotations used to parse WebAssembly text files. diff --git a/crates/wast/src/parser.rs b/crates/wast/src/parser.rs index 305abe9eaf..8af058338b 100644 --- a/crates/wast/src/parser.rs +++ b/crates/wast/src/parser.rs @@ -993,6 +993,19 @@ impl<'a> Parser<'a> { pub(crate) fn track_instr_spans(&self) -> bool { self.buf.track_instr_spans } + + #[cfg(feature = "wasm-module")] + pub(crate) fn with_standard_annotations_registered( + self, + f: impl FnOnce(Self) -> Result, + ) -> Result { + let _r = self.register_annotation("custom"); + let _r = self.register_annotation("producers"); + let _r = self.register_annotation("name"); + let _r = self.register_annotation("dylink.0"); + let _r = self.register_annotation("metadata.code.branch_hint"); + f(self) + } } impl<'a> Cursor<'a> { diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs index 418bc83fc7..88b27e1c19 100644 --- a/crates/wast/src/wast.rs +++ b/crates/wast/src/wast.rs @@ -20,17 +20,19 @@ impl<'a> Parse<'a> for Wast<'a> { fn parse(parser: Parser<'a>) -> Result { let mut directives = Vec::new(); - // If it looks like a directive token is in the stream then we parse a - // bunch of directives, otherwise assume this is an inline module. - if parser.peek2::()? { - while !parser.is_empty() { - directives.push(parser.parens(|p| p.parse())?); + parser.with_standard_annotations_registered(|parser| { + // If it looks like a directive token is in the stream then we parse a + // bunch of directives, otherwise assume this is an inline module. + if parser.peek2::()? { + while !parser.is_empty() { + directives.push(parser.parens(|p| p.parse())?); + } + } else { + let module = parser.parse::()?; + directives.push(WastDirective::Module(QuoteWat::Wat(module))); } - } else { - let module = parser.parse::()?; - directives.push(WastDirective::Wat(QuoteWat::Wat(module))); - } - Ok(Wast { directives }) + Ok(Wast { directives }) + }) } } @@ -56,67 +58,103 @@ impl Peek for WastDirectiveToken { /// The different kinds of directives found in a `*.wast` file. /// -/// It's not entirely clear to me what all of these are per se, but they're only -/// really interesting to test harnesses mostly. +/// +/// Some more information about these various branches can be found at +/// . #[allow(missing_docs)] #[derive(Debug)] pub enum WastDirective<'a> { - Wat(QuoteWat<'a>), + /// The provided module is defined, validated, and then instantiated. + Module(QuoteWat<'a>), + + /// The provided module is defined and validated. + /// + /// This module is not instantiated automatically. + ModuleDefinition(QuoteWat<'a>), + + /// The named module is instantiated under the instance name provided. + ModuleInstance { + span: Span, + instance: Option>, + module: Option>, + }, + + /// Asserts the module cannot be decoded with the given error. AssertMalformed { span: Span, module: QuoteWat<'a>, message: &'a str, }, + + /// Asserts the module cannot be validated with the given error. AssertInvalid { span: Span, module: QuoteWat<'a>, message: &'a str, }, + + /// Registers the `module` instance with the given `name` to be available + /// for importing in future module instances. Register { span: Span, name: &'a str, module: Option>, }, + + /// Invokes the specified export. Invoke(WastInvoke<'a>), + + /// The invocation provided should trap with the specified error. AssertTrap { span: Span, exec: WastExecute<'a>, message: &'a str, }, + + /// The invocation provided should succeed with the specified results. AssertReturn { span: Span, exec: WastExecute<'a>, results: Vec>, }, + + /// The invocation provided should exhaust system resources (e.g. stack + /// overflow). AssertExhaustion { span: Span, call: WastInvoke<'a>, message: &'a str, }, + + /// The provided module should fail to link when instantiation is attempted. AssertUnlinkable { span: Span, module: Wat<'a>, message: &'a str, }, - AssertException { - span: Span, - exec: WastExecute<'a>, - }, + + /// The invocation provided should throw an exception. + AssertException { span: Span, exec: WastExecute<'a> }, + + /// Creates a new system thread which executes the given commands. Thread(WastThread<'a>), - Wait { - span: Span, - thread: Id<'a>, - }, + + /// Waits for the specified thread to exit. + Wait { span: Span, thread: Id<'a> }, } impl WastDirective<'_> { /// Returns the location in the source that this directive was defined at pub fn span(&self) -> Span { match self { - WastDirective::Wat(QuoteWat::Wat(w)) => w.span(), - WastDirective::Wat(QuoteWat::QuoteModule(span, _)) => *span, - WastDirective::Wat(QuoteWat::QuoteComponent(span, _)) => *span, - WastDirective::AssertMalformed { span, .. } + WastDirective::Module(QuoteWat::Wat(w)) + | WastDirective::ModuleDefinition(QuoteWat::Wat(w)) => w.span(), + WastDirective::Module(QuoteWat::QuoteModule(span, _)) + | WastDirective::ModuleDefinition(QuoteWat::QuoteModule(span, _)) => *span, + WastDirective::Module(QuoteWat::QuoteComponent(span, _)) + | WastDirective::ModuleDefinition(QuoteWat::QuoteComponent(span, _)) => *span, + WastDirective::ModuleInstance { span, .. } + | WastDirective::AssertMalformed { span, .. } | WastDirective::Register { span, .. } | WastDirective::AssertTrap { span, .. } | WastDirective::AssertReturn { span, .. } @@ -135,7 +173,7 @@ impl<'a> Parse<'a> for WastDirective<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); if l.peek::()? || l.peek::()? { - Ok(WastDirective::Wat(parser.parse()?)) + parse_wast_module(parser) } else if l.peek::()? { let span = parser.parse::()?.0; Ok(WastDirective::AssertMalformed { @@ -296,6 +334,52 @@ impl<'a> Parse<'a> for WastInvoke<'a> { } } +fn parse_wast_module<'a>(parser: Parser<'a>) -> Result> { + if parser.peek2::()? { + QuoteWat::parse(parser).map(WastDirective::Module) + } else if parser.peek2::()? { + fn parse_module(span: Span, parser: Parser<'_>) -> Result> { + Ok(Wat::Module( + crate::core::Module::parse_without_module_keyword(span, parser)?, + )) + } + fn parse_component(span: Span, parser: Parser<'_>) -> Result> { + Ok(Wat::Component( + crate::component::Component::parse_without_component_keyword(span, parser)?, + )) + } + let (span, ctor) = if parser.peek::()? { + ( + parser.parse::()?.0, + parse_component as fn(_, _) -> _, + ) + } else { + ( + parser.parse::()?.0, + parse_module as fn(_, _) -> _, + ) + }; + parser.parse::()?; + Ok(WastDirective::ModuleDefinition(QuoteWat::Wat(ctor( + span, parser, + )?))) + } else if parser.peek2::()? { + let span = if parser.peek::()? { + parser.parse::()?.0 + } else { + parser.parse::()?.0 + }; + parser.parse::()?; + Ok(WastDirective::ModuleInstance { + span, + instance: parser.parse()?, + module: parser.parse()?, + }) + } else { + QuoteWat::parse(parser).map(WastDirective::Module) + } +} + #[allow(missing_docs)] #[derive(Debug)] pub enum QuoteWat<'a> { @@ -304,7 +388,7 @@ pub enum QuoteWat<'a> { QuoteComponent(Span, Vec<(Span, &'a [u8])>), } -impl QuoteWat<'_> { +impl<'a> QuoteWat<'a> { /// Encodes this module to bytes, either by encoding the module directly or /// parsing the contents and then encoding it. pub fn encode(&mut self) -> Result, Error> { @@ -342,6 +426,15 @@ impl QuoteWat<'_> { Ok(QuoteWatTest::Text(ret)) } + /// Returns the identifier, if registered, for this module. + pub fn name(&self) -> Option> { + match self { + QuoteWat::Wat(Wat::Module(m)) => m.id, + QuoteWat::Wat(Wat::Component(m)) => m.id, + QuoteWat::QuoteModule(..) | QuoteWat::QuoteComponent(..) => None, + } + } + /// Returns the defining span of this module. pub fn span(&self) -> Span { match self { diff --git a/crates/wast/src/wat.rs b/crates/wast/src/wat.rs index 3673c849f1..cf4b532b78 100644 --- a/crates/wast/src/wat.rs +++ b/crates/wast/src/wat.rs @@ -45,24 +45,22 @@ impl<'a> Parse<'a> for Wat<'a> { return Err(parser.error("expected at least one module field")); } - let _r = parser.register_annotation("custom"); - let _r = parser.register_annotation("producers"); - let _r = parser.register_annotation("name"); - let _r = parser.register_annotation("metadata.code.branch_hint"); - let wat = if parser.peek2::()? { - Wat::Module(parser.parens(|parser| parser.parse())?) - } else if parser.peek2::()? { - Wat::Component(parser.parens(|parser| parser.parse())?) - } else { - let fields = ModuleField::parse_remaining(parser)?; - Wat::Module(Module { - span: Span { offset: 0 }, - id: None, - name: None, - kind: ModuleKind::Text(fields), - }) - }; - wat.validate(parser)?; - Ok(wat) + parser.with_standard_annotations_registered(|parser| { + let wat = if parser.peek2::()? { + Wat::Module(parser.parens(|parser| parser.parse())?) + } else if parser.peek2::()? { + Wat::Component(parser.parens(|parser| parser.parse())?) + } else { + let fields = ModuleField::parse_remaining(parser)?; + Wat::Module(Module { + span: Span { offset: 0 }, + id: None, + name: None, + kind: ModuleKind::Text(fields), + }) + }; + wat.validate(parser)?; + Ok(wat) + }) } } diff --git a/src/bin/wasm-tools/json_from_wast.rs b/src/bin/wasm-tools/json_from_wast.rs index 02ff170d32..b423ebe4d7 100644 --- a/src/bin/wasm-tools/json_from_wast.rs +++ b/src/bin/wasm-tools/json_from_wast.rs @@ -6,7 +6,7 @@ use wast::lexer::Lexer; use wast::parser::{self, ParseBuffer}; use wast::token::{Span, F32, F64}; use wast::{ - QuoteWat, QuoteWatTest, Wast, WastArg, WastDirective, WastExecute, WastInvoke, WastRet, Wat, + QuoteWat, QuoteWatTest, Wast, WastArg, WastDirective, WastExecute, WastInvoke, WastRet, }; /// Convert a `*.wast` WebAssembly spec test into a `*.json` file and `*.wasm` @@ -130,7 +130,7 @@ impl<'a> JsonBuilder<'a> { fn directive(&mut self, directive: WastDirective<'a>) -> Result> { let line = self.lineno(directive.span()); let command = match directive { - WastDirective::Wat(module) => { + WastDirective::Module(module) => { let (name, _module_type, filename) = self.emit_file(module)?; json::Command::Module { line, @@ -138,6 +138,21 @@ impl<'a> JsonBuilder<'a> { filename, } } + WastDirective::ModuleDefinition(module) => { + let (name, _module_type, filename) = self.emit_file(module)?; + json::Command::ModuleDefinition { + line, + name: name.map(|s| self.module_name(s)), + filename, + } + } + WastDirective::ModuleInstance { + instance, module, .. + } => json::Command::ModuleInstance { + line, + instance: instance.map(|s| self.module_name(s.name())), + module: module.map(|s| self.module_name(s.name())), + }, WastDirective::AssertMalformed { span: _, module, @@ -274,12 +289,7 @@ impl<'a> JsonBuilder<'a> { &mut self, mut module: QuoteWat<'a>, ) -> Result<(Option<&'a str>, &'a str, String)> { - let name = match &module { - QuoteWat::Wat(Wat::Module(m)) => m.id, - QuoteWat::Wat(Wat::Component(m)) => m.id, - QuoteWat::QuoteModule(..) | QuoteWat::QuoteComponent(..) => None, - }; - let name = name.map(|i| i.name()); + let name = module.name().map(|i| i.name()); let (contents, module_type, ext) = match module.to_test()? { QuoteWatTest::Text(s) => (s, "text", "wat"), QuoteWatTest::Binary(s) => (s, "binary", "wasm"), @@ -557,6 +567,19 @@ mod json { name: Option, filename: String, }, + ModuleDefinition { + line: u32, + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + filename: String, + }, + ModuleInstance { + line: u32, + #[serde(skip_serializing_if = "Option::is_none")] + instance: Option, + #[serde(skip_serializing_if = "Option::is_none")] + module: Option, + }, AssertMalformed { line: u32, filename: String, diff --git a/tests/local/instance.wast b/tests/local/instance.wast new file mode 100644 index 0000000000..b88025d699 --- /dev/null +++ b/tests/local/instance.wast @@ -0,0 +1,170 @@ +;; Instantiation is generative + +(module definition $M + (global (export "glob") (mut i32) (i32.const 0)) + (table (export "tab") 10 funcref (ref.null func)) + (memory (export "mem") 1) + (tag (export "tag")) +) + +(module instance $I1 $M) +(module instance $I2 $M) +(register "I1" $I1) +(register "I2" $I2) + +(module + (import "I1" "glob" (global $glob1 (mut i32))) + (import "I2" "glob" (global $glob2 (mut i32))) + (import "I1" "tab" (table $tab1 10 funcref)) + (import "I2" "tab" (table $tab2 10 funcref)) + (import "I1" "mem" (memory $mem1 1)) + (import "I2" "mem" (memory $mem2 1)) + (import "I1" "tag" (tag $tag1)) + (import "I2" "tag" (tag $tag2)) + + (func $f) + (elem declare func $f) + + (func (export "glob") (result i32) + (global.set $glob1 (i32.const 1)) + (global.get $glob2) + ) + (func (export "tab") (result funcref) + (table.set $tab1 (i32.const 0) (ref.func $f)) + (table.get $tab2 (i32.const 0)) + ) + (func (export "mem") (result i32) + (i32.store $mem1 (i32.const 0) (i32.const 1)) + (i32.load $mem2 (i32.const 0)) + ) + (func (export "tag") (result i32) + (block $on_tag1 + (block $on_other + (try_table (catch $tag1 $on_tag1) (catch_all $on_other) + (throw $tag2) + ) + (unreachable) + ) + (return (i32.const 0)) + ) + (return (i32.const 1)) + ) +) + +(assert_return (invoke "glob") (i32.const 0)) +(assert_return (invoke "tab") (ref.null)) +(assert_return (invoke "mem") (i32.const 0)) +(assert_return (invoke "tag") (i32.const 0)) + + +;; Import is not generative + +(module + (import "I1" "glob" (global $glob1 (mut i32))) + (import "I1" "glob" (global $glob2 (mut i32))) + (import "I1" "tab" (table $tab1 10 funcref)) + (import "I1" "tab" (table $tab2 10 funcref)) + (import "I1" "mem" (memory $mem1 1)) + (import "I1" "mem" (memory $mem2 1)) + (import "I1" "tag" (tag $tag1)) + (import "I1" "tag" (tag $tag2)) + + (func $f) + (elem declare func $f) + + (func (export "glob") (result i32) + (global.set $glob1 (i32.const 1)) + (global.get $glob2) + ) + (func (export "tab") (result funcref) + (table.set $tab1 (i32.const 0) (ref.func $f)) + (table.get $tab2 (i32.const 0)) + ) + (func (export "mem") (result i32) + (i32.store $mem1 (i32.const 0) (i32.const 1)) + (i32.load $mem2 (i32.const 0)) + ) + (func (export "tag") (result i32) + (block $on_tag1 + (block $on_other + (try_table (catch $tag1 $on_tag1) (catch_all $on_other) + (throw $tag2) + ) + (unreachable) + ) + (return (i32.const 0)) + ) + (return (i32.const 1)) + ) +) + +(assert_return (invoke "glob") (i32.const 1)) +(assert_return (invoke "tab") (ref.func)) +(assert_return (invoke "mem") (i32.const 1)) +(assert_return (invoke "tag") (i32.const 1)) + + +;; Export is not generative + +(module definition $N + (global $glob (mut i32) (i32.const 0)) + (table $tab 10 funcref (ref.null func)) + (memory $mem 1) + (tag $tag) + + (export "glob1" (global $glob)) + (export "glob2" (global $glob)) + (export "tab1" (table $tab)) + (export "tab2" (table $tab)) + (export "mem1" (memory $mem)) + (export "mem2" (memory $mem)) + (export "tag1" (tag $tag)) + (export "tag2" (tag $tag)) +) + +(module instance $I $N) +(register "I" $I) + +(module + (import "I" "glob1" (global $glob1 (mut i32))) + (import "I" "glob2" (global $glob2 (mut i32))) + (import "I" "tab1" (table $tab1 10 funcref)) + (import "I" "tab2" (table $tab2 10 funcref)) + (import "I" "mem1" (memory $mem1 1)) + (import "I" "mem2" (memory $mem2 1)) + (import "I" "tag1" (tag $tag1)) + (import "I" "tag2" (tag $tag2)) + + (func $f) + (elem declare func $f) + + (func (export "glob") (result i32) + (global.set $glob1 (i32.const 1)) + (global.get $glob2) + ) + (func (export "tab") (result funcref) + (table.set $tab1 (i32.const 0) (ref.func $f)) + (table.get $tab2 (i32.const 0)) + ) + (func (export "mem") (result i32) + (i32.store $mem1 (i32.const 0) (i32.const 1)) + (i32.load $mem2 (i32.const 0)) + ) + (func (export "tag") (result i32) + (block $on_tag1 + (block $on_other + (try_table (catch $tag1 $on_tag1) (catch_all $on_other) + (throw $tag2) + ) + (unreachable) + ) + (return (i32.const 0)) + ) + (return (i32.const 1)) + ) +) + +(assert_return (invoke "glob") (i32.const 1)) +(assert_return (invoke "tab") (ref.func)) +(assert_return (invoke "mem") (i32.const 1)) +(assert_return (invoke "tag") (i32.const 1)) diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs index 5861c6b46e..cb358aeba3 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -286,7 +286,7 @@ impl TestState { fn test_wast_directive(&self, test: &Path, directive: WastDirective, idx: usize) -> Result<()> { match directive { - WastDirective::Wat(mut module) => { + WastDirective::Module(mut module) | WastDirective::ModuleDefinition(mut module) => { let actual = module.encode()?; self.bump_ntests(); // testing encode @@ -375,7 +375,8 @@ impl TestState { // This test suite doesn't actually execute any wasm code, so ignore // all of these assertions. - WastDirective::Register { .. } + WastDirective::ModuleInstance { .. } + | WastDirective::Register { .. } | WastDirective::Invoke(_) | WastDirective::AssertTrap { .. } | WastDirective::AssertReturn { .. } diff --git a/tests/snapshots/local/instance.wast.json b/tests/snapshots/local/instance.wast.json new file mode 100644 index 0000000000..0533572429 --- /dev/null +++ b/tests/snapshots/local/instance.wast.json @@ -0,0 +1,245 @@ +{ + "source_filename": "tests/local/instance.wast", + "commands": [ + { + "type": "module_definition", + "line": 3, + "name": "M", + "filename": "instance.0.wasm" + }, + { + "type": "module_instance", + "line": 10, + "instance": "I1", + "module": "M" + }, + { + "type": "module_instance", + "line": 11, + "instance": "I2", + "module": "M" + }, + { + "type": "register", + "line": 12, + "name": "I1", + "as": "I1" + }, + { + "type": "register", + "line": 13, + "name": "I2", + "as": "I2" + }, + { + "type": "module", + "line": 15, + "filename": "instance.1.wasm" + }, + { + "type": "assert_return", + "line": 54, + "action": { + "type": "invoke", + "field": "glob", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "0" + } + ] + }, + { + "type": "assert_return", + "line": 55, + "action": { + "type": "invoke", + "field": "tab", + "args": [] + }, + "expected": [ + { + "type": "refnull" + } + ] + }, + { + "type": "assert_return", + "line": 56, + "action": { + "type": "invoke", + "field": "mem", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "0" + } + ] + }, + { + "type": "assert_return", + "line": 57, + "action": { + "type": "invoke", + "field": "tag", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "0" + } + ] + }, + { + "type": "module", + "line": 62, + "filename": "instance.2.wasm" + }, + { + "type": "assert_return", + "line": 101, + "action": { + "type": "invoke", + "field": "glob", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_return", + "line": 102, + "action": { + "type": "invoke", + "field": "tab", + "args": [] + }, + "expected": [ + { + "type": "funcref" + } + ] + }, + { + "type": "assert_return", + "line": 103, + "action": { + "type": "invoke", + "field": "mem", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_return", + "line": 104, + "action": { + "type": "invoke", + "field": "tag", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "module_definition", + "line": 109, + "name": "N", + "filename": "instance.3.wasm" + }, + { + "type": "module_instance", + "line": 125, + "instance": "I", + "module": "N" + }, + { + "type": "register", + "line": 126, + "name": "I", + "as": "I" + }, + { + "type": "module", + "line": 128, + "filename": "instance.4.wasm" + }, + { + "type": "assert_return", + "line": 167, + "action": { + "type": "invoke", + "field": "glob", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_return", + "line": 168, + "action": { + "type": "invoke", + "field": "tab", + "args": [] + }, + "expected": [ + { + "type": "funcref" + } + ] + }, + { + "type": "assert_return", + "line": 169, + "action": { + "type": "invoke", + "field": "mem", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_return", + "line": 170, + "action": { + "type": "invoke", + "field": "tag", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/instance.wast/0.print b/tests/snapshots/local/instance.wast/0.print new file mode 100644 index 0000000000..5ef681d317 --- /dev/null +++ b/tests/snapshots/local/instance.wast/0.print @@ -0,0 +1,11 @@ +(module $M + (type (;0;) (func)) + (table (;0;) 10 funcref ref.null func) + (memory (;0;) 1) + (tag (;0;) (type 0)) + (global (;0;) (mut i32) i32.const 0) + (export "glob" (global 0)) + (export "tab" (table 0)) + (export "mem" (memory 0)) + (export "tag" (tag 0)) +) diff --git a/tests/snapshots/local/instance.wast/10.print b/tests/snapshots/local/instance.wast/10.print new file mode 100644 index 0000000000..e847b035f5 --- /dev/null +++ b/tests/snapshots/local/instance.wast/10.print @@ -0,0 +1,52 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (result funcref))) + (import "I1" "glob" (global $glob1 (;0;) (mut i32))) + (import "I1" "glob" (global $glob2 (;1;) (mut i32))) + (import "I1" "tab" (table $tab1 (;0;) 10 funcref)) + (import "I1" "tab" (table $tab2 (;1;) 10 funcref)) + (import "I1" "mem" (memory $mem1 (;0;) 1)) + (import "I1" "mem" (memory $mem2 (;1;) 1)) + (import "I1" "tag" (tag $tag1 (;0;) (type 0))) + (import "I1" "tag" (tag $tag2 (;1;) (type 0))) + (func $f (;0;) (type 0)) + (func (;1;) (type 1) (result i32) + i32.const 1 + global.set $glob1 + global.get $glob2 + ) + (func (;2;) (type 2) (result funcref) + i32.const 0 + ref.func $f + table.set $tab1 + i32.const 0 + table.get $tab2 + ) + (func (;3;) (type 1) (result i32) + i32.const 0 + i32.const 1 + i32.store + i32.const 0 + i32.load $mem2 + ) + (func (;4;) (type 1) (result i32) + block $on_tag1 + block $on_other + try_table (catch $tag1 $on_tag1) (catch_all $on_other) ;; label = @3 + throw $tag2 + end + unreachable + end + i32.const 0 + return + end + i32.const 1 + return + ) + (export "glob" (func 1)) + (export "tab" (func 2)) + (export "mem" (func 3)) + (export "tag" (func 4)) + (elem (;0;) declare func $f) +) diff --git a/tests/snapshots/local/instance.wast/15.print b/tests/snapshots/local/instance.wast/15.print new file mode 100644 index 0000000000..db1c4225d9 --- /dev/null +++ b/tests/snapshots/local/instance.wast/15.print @@ -0,0 +1,15 @@ +(module $N + (type (;0;) (func)) + (table $tab (;0;) 10 funcref ref.null func) + (memory $mem (;0;) 1) + (tag $tag (;0;) (type 0)) + (global $glob (;0;) (mut i32) i32.const 0) + (export "glob1" (global $glob)) + (export "glob2" (global $glob)) + (export "tab1" (table $tab)) + (export "tab2" (table $tab)) + (export "mem1" (memory $mem)) + (export "mem2" (memory $mem)) + (export "tag1" (tag 0)) + (export "tag2" (tag 0)) +) diff --git a/tests/snapshots/local/instance.wast/18.print b/tests/snapshots/local/instance.wast/18.print new file mode 100644 index 0000000000..7b9f2a497c --- /dev/null +++ b/tests/snapshots/local/instance.wast/18.print @@ -0,0 +1,52 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (result funcref))) + (import "I" "glob1" (global $glob1 (;0;) (mut i32))) + (import "I" "glob2" (global $glob2 (;1;) (mut i32))) + (import "I" "tab1" (table $tab1 (;0;) 10 funcref)) + (import "I" "tab2" (table $tab2 (;1;) 10 funcref)) + (import "I" "mem1" (memory $mem1 (;0;) 1)) + (import "I" "mem2" (memory $mem2 (;1;) 1)) + (import "I" "tag1" (tag $tag1 (;0;) (type 0))) + (import "I" "tag2" (tag $tag2 (;1;) (type 0))) + (func $f (;0;) (type 0)) + (func (;1;) (type 1) (result i32) + i32.const 1 + global.set $glob1 + global.get $glob2 + ) + (func (;2;) (type 2) (result funcref) + i32.const 0 + ref.func $f + table.set $tab1 + i32.const 0 + table.get $tab2 + ) + (func (;3;) (type 1) (result i32) + i32.const 0 + i32.const 1 + i32.store + i32.const 0 + i32.load $mem2 + ) + (func (;4;) (type 1) (result i32) + block $on_tag1 + block $on_other + try_table (catch $tag1 $on_tag1) (catch_all $on_other) ;; label = @3 + throw $tag2 + end + unreachable + end + i32.const 0 + return + end + i32.const 1 + return + ) + (export "glob" (func 1)) + (export "tab" (func 2)) + (export "mem" (func 3)) + (export "tag" (func 4)) + (elem (;0;) declare func $f) +) diff --git a/tests/snapshots/local/instance.wast/5.print b/tests/snapshots/local/instance.wast/5.print new file mode 100644 index 0000000000..fe723dcfab --- /dev/null +++ b/tests/snapshots/local/instance.wast/5.print @@ -0,0 +1,52 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (result funcref))) + (import "I1" "glob" (global $glob1 (;0;) (mut i32))) + (import "I2" "glob" (global $glob2 (;1;) (mut i32))) + (import "I1" "tab" (table $tab1 (;0;) 10 funcref)) + (import "I2" "tab" (table $tab2 (;1;) 10 funcref)) + (import "I1" "mem" (memory $mem1 (;0;) 1)) + (import "I2" "mem" (memory $mem2 (;1;) 1)) + (import "I1" "tag" (tag $tag1 (;0;) (type 0))) + (import "I2" "tag" (tag $tag2 (;1;) (type 0))) + (func $f (;0;) (type 0)) + (func (;1;) (type 1) (result i32) + i32.const 1 + global.set $glob1 + global.get $glob2 + ) + (func (;2;) (type 2) (result funcref) + i32.const 0 + ref.func $f + table.set $tab1 + i32.const 0 + table.get $tab2 + ) + (func (;3;) (type 1) (result i32) + i32.const 0 + i32.const 1 + i32.store + i32.const 0 + i32.load $mem2 + ) + (func (;4;) (type 1) (result i32) + block $on_tag1 + block $on_other + try_table (catch $tag1 $on_tag1) (catch_all $on_other) ;; label = @3 + throw $tag2 + end + unreachable + end + i32.const 0 + return + end + i32.const 1 + return + ) + (export "glob" (func 1)) + (export "tab" (func 2)) + (export "mem" (func 3)) + (export "tag" (func 4)) + (elem (;0;) declare func $f) +) From 46cb2e80abe9e57c422a3496032dd4c49bdefcd9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:46:27 +0000 Subject: [PATCH 17/18] Release wasm-tools 1.217.0 (#1772) [automatically-tag-and-release-this-commit] Co-authored-by: Auto Release Process --- Cargo.lock | 128 ++++++++++++++++++++--------------------- Cargo.toml | 32 +++++------ crates/wast/Cargo.toml | 2 +- crates/wat/Cargo.toml | 2 +- 4 files changed, 82 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bea35ec67e..212235a66a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -295,7 +295,7 @@ checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" name = "component" version = "0.0.0" dependencies = [ - "wasmprinter 0.216.0", + "wasmprinter 0.217.0", "wat", "wit-bindgen-rt", ] @@ -1593,7 +1593,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-compose" -version = "0.216.0" +version = "0.217.0" dependencies = [ "anyhow", "glob", @@ -1607,11 +1607,11 @@ dependencies = [ "serde_derive", "serde_yaml", "smallvec", - "wasm-encoder 0.216.0", - "wasmparser 0.216.0", - "wasmprinter 0.216.0", + "wasm-encoder 0.217.0", + "wasmparser 0.217.0", + "wasmprinter 0.217.0", "wat", - "wit-component 0.216.0", + "wit-component 0.217.0", ] [[package]] @@ -1635,12 +1635,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.216.0" +version = "0.217.0" dependencies = [ "anyhow", "leb128", "tempfile", - "wasmparser 0.216.0", + "wasmparser 0.217.0", ] [[package]] @@ -1661,7 +1661,7 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.216.0" +version = "0.217.0" dependencies = [ "anyhow", "clap", @@ -1670,14 +1670,14 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.216.0", - "wasmparser 0.216.0", + "wasm-encoder 0.217.0", + "wasmparser 0.217.0", "wat", ] [[package]] name = "wasm-mutate" -version = "0.216.0" +version = "0.217.0" dependencies = [ "anyhow", "clap", @@ -1686,9 +1686,9 @@ dependencies = [ "log", "rand", "thiserror", - "wasm-encoder 0.216.0", - "wasmparser 0.216.0", - "wasmprinter 0.216.0", + "wasm-encoder 0.217.0", + "wasmparser 0.217.0", + "wasmprinter 0.217.0", "wat", ] @@ -1705,14 +1705,14 @@ dependencies = [ "num_cpus", "rand", "wasm-mutate", - "wasmparser 0.216.0", - "wasmprinter 0.216.0", + "wasmparser 0.217.0", + "wasmprinter 0.217.0", "wasmtime", ] [[package]] name = "wasm-shrink" -version = "0.216.0" +version = "0.217.0" dependencies = [ "anyhow", "blake3", @@ -1721,14 +1721,14 @@ dependencies = [ "log", "rand", "wasm-mutate", - "wasmparser 0.216.0", - "wasmprinter 0.216.0", + "wasmparser 0.217.0", + "wasmprinter 0.217.0", "wat", ] [[package]] name = "wasm-smith" -version = "0.216.0" +version = "0.217.0" dependencies = [ "anyhow", "arbitrary", @@ -1741,15 +1741,15 @@ dependencies = [ "rand", "serde", "serde_derive", - "wasm-encoder 0.216.0", - "wasmparser 0.216.0", - "wasmprinter 0.216.0", + "wasm-encoder 0.217.0", + "wasmparser 0.217.0", + "wasmprinter 0.217.0", "wat", ] [[package]] name = "wasm-tools" -version = "1.216.0" +version = "1.217.0" dependencies = [ "addr2line", "anyhow", @@ -1774,18 +1774,18 @@ dependencies = [ "tempfile", "termcolor", "wasm-compose", - "wasm-encoder 0.216.0", - "wasm-metadata 0.216.0", + "wasm-encoder 0.217.0", + "wasm-metadata 0.217.0", "wasm-mutate", "wasm-shrink", "wasm-smith", - "wasmparser 0.216.0", - "wasmprinter 0.216.0", + "wasmparser 0.217.0", + "wasmprinter 0.217.0", "wast", "wat", - "wit-component 0.216.0", + "wit-component 0.217.0", "wit-encoder", - "wit-parser 0.216.0", + "wit-parser 0.217.0", "wit-smith", ] @@ -1797,8 +1797,8 @@ dependencies = [ "wasm-mutate", "wasm-shrink", "wasm-smith", - "wasmparser 0.216.0", - "wasmprinter 0.216.0", + "wasmparser 0.217.0", + "wasmprinter 0.217.0", "wast", "wat", ] @@ -1813,30 +1813,30 @@ dependencies = [ "libfuzzer-sys", "log", "tempfile", - "wasm-encoder 0.216.0", + "wasm-encoder 0.217.0", "wasm-mutate", "wasm-smith", - "wasmparser 0.216.0", - "wasmprinter 0.216.0", + "wasmparser 0.217.0", + "wasmprinter 0.217.0", "wasmtime", "wast", "wat", "wit-component 0.214.0", - "wit-component 0.216.0", + "wit-component 0.217.0", "wit-parser 0.214.0", - "wit-parser 0.216.0", + "wit-parser 0.217.0", "wit-smith", ] [[package]] name = "wasm-wave" -version = "0.216.0" +version = "0.217.0" dependencies = [ "anyhow", "indexmap 2.4.0", "logos", "thiserror", - "wit-parser 0.216.0", + "wit-parser 0.217.0", ] [[package]] @@ -1868,7 +1868,7 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.216.0" +version = "0.217.0" dependencies = [ "ahash", "anyhow", @@ -1882,7 +1882,7 @@ dependencies = [ "rayon", "semver", "serde", - "wasm-encoder 0.216.0", + "wasm-encoder 0.217.0", "wast", "wat", ] @@ -1900,14 +1900,14 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.216.0" +version = "0.217.0" dependencies = [ "anyhow", "diff", "rayon", "tempfile", "termcolor", - "wasmparser 0.216.0", + "wasmparser 0.217.0", "wast", "wat", ] @@ -2109,7 +2109,7 @@ dependencies = [ [[package]] name = "wast" -version = "216.0.0" +version = "217.0.0" dependencies = [ "anyhow", "bumpalo", @@ -2119,14 +2119,14 @@ dependencies = [ "memchr", "rand", "unicode-width", - "wasm-encoder 0.216.0", - "wasmparser 0.216.0", + "wasm-encoder 0.217.0", + "wasmparser 0.217.0", "wat", ] [[package]] name = "wat" -version = "1.216.0" +version = "1.217.0" dependencies = [ "wast", ] @@ -2357,7 +2357,7 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.216.0" +version = "0.217.0" dependencies = [ "anyhow", "bitflags", @@ -2370,26 +2370,26 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.216.0", - "wasm-metadata 0.216.0", - "wasmparser 0.216.0", - "wasmprinter 0.216.0", + "wasm-encoder 0.217.0", + "wasm-metadata 0.217.0", + "wasmparser 0.217.0", + "wasmprinter 0.217.0", "wasmtime", "wast", "wat", - "wit-parser 0.216.0", + "wit-parser 0.217.0", ] [[package]] name = "wit-encoder" -version = "0.216.0" +version = "0.217.0" dependencies = [ "id-arena", "indoc", "pretty_assertions", "semver", "serde", - "wit-parser 0.216.0", + "wit-parser 0.217.0", ] [[package]] @@ -2430,7 +2430,7 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.216.0" +version = "0.217.0" dependencies = [ "anyhow", "env_logger", @@ -2444,9 +2444,9 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.216.0", + "wasmparser 0.217.0", "wat", - "wit-parser 0.216.0", + "wit-parser 0.217.0", ] [[package]] @@ -2457,21 +2457,21 @@ dependencies = [ "env_logger", "libfuzzer-sys", "log", - "wasmprinter 0.216.0", - "wit-parser 0.216.0", + "wasmprinter 0.217.0", + "wit-parser 0.217.0", ] [[package]] name = "wit-smith" -version = "0.216.0" +version = "0.217.0" dependencies = [ "arbitrary", "clap", "indexmap 2.4.0", "log", "semver", - "wit-component 0.216.0", - "wit-parser 0.216.0", + "wit-component 0.217.0", + "wit-parser 0.217.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f722bf0158..0e24742a42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-tools" -version = "1.216.0" +version = "1.217.0" authors = ["The Wasmtime Project Developers"] edition.workspace = true description = "CLI tools for interoperating with WebAssembly files" @@ -60,7 +60,7 @@ manual_strip = 'warn' [workspace.package] edition = '2021' license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" -version = "0.216.0" +version = "0.217.0" # Current policy for wasm-tools is the same as Wasmtime which is that this # number can be no larger than the current stable release of Rust minus 2. rust-version = "1.76.0" @@ -96,20 +96,20 @@ indoc = "2.0.5" gimli = "0.30.0" id-arena = "2" -wasm-compose = { version = "0.216.0", path = "crates/wasm-compose" } -wasm-encoder = { version = "0.216.0", path = "crates/wasm-encoder" } -wasm-metadata = { version = "0.216.0", path = "crates/wasm-metadata" } -wasm-mutate = { version = "0.216.0", path = "crates/wasm-mutate" } -wasm-shrink = { version = "0.216.0", path = "crates/wasm-shrink" } -wasm-smith = { version = "0.216.0", path = "crates/wasm-smith" } -wasmparser = { version = "0.216.0", path = "crates/wasmparser", default-features = false, features = ['std'] } -wasmprinter = { version = "0.216.0", path = "crates/wasmprinter" } -wast = { version = "216.0.0", path = "crates/wast" } -wat = { version = "1.216.0", path = "crates/wat" } -wit-component = { version = "0.216.0", path = "crates/wit-component" } -wit-encoder = { version = "0.216.0", path = "crates/wit-encoder" } -wit-parser = { version = "0.216.0", path = "crates/wit-parser" } -wit-smith = { version = "0.216.0", path = "crates/wit-smith" } +wasm-compose = { version = "0.217.0", path = "crates/wasm-compose" } +wasm-encoder = { version = "0.217.0", path = "crates/wasm-encoder" } +wasm-metadata = { version = "0.217.0", path = "crates/wasm-metadata" } +wasm-mutate = { version = "0.217.0", path = "crates/wasm-mutate" } +wasm-shrink = { version = "0.217.0", path = "crates/wasm-shrink" } +wasm-smith = { version = "0.217.0", path = "crates/wasm-smith" } +wasmparser = { version = "0.217.0", path = "crates/wasmparser", default-features = false, features = ['std'] } +wasmprinter = { version = "0.217.0", path = "crates/wasmprinter" } +wast = { version = "217.0.0", path = "crates/wast" } +wat = { version = "1.217.0", path = "crates/wat" } +wit-component = { version = "0.217.0", path = "crates/wit-component" } +wit-encoder = { version = "0.217.0", path = "crates/wit-encoder" } +wit-parser = { version = "0.217.0", path = "crates/wit-parser" } +wit-smith = { version = "0.217.0", path = "crates/wit-smith" } [dependencies] anyhow = { workspace = true } diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index 2ea999c3d2..c9b949c3a9 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wast" -version = "216.0.0" +version = "217.0.0" authors = ["Alex Crichton "] edition.workspace = true license.workspace = true diff --git a/crates/wat/Cargo.toml b/crates/wat/Cargo.toml index a064af2f24..db8ea337fd 100644 --- a/crates/wat/Cargo.toml +++ b/crates/wat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wat" -version = "1.216.0" +version = "1.217.0" authors = ["Alex Crichton "] edition.workspace = true license.workspace = true From 6d538a0e2d1e3ad55046e5e806f5eed98994c7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Hillerstr=C3=B6m?= Date: Thu, 12 Sep 2024 15:41:07 +0200 Subject: [PATCH 18/18] Fix check error --- crates/wasmparser/src/validator/core/canonical.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/wasmparser/src/validator/core/canonical.rs b/crates/wasmparser/src/validator/core/canonical.rs index 6f32f001a3..a444b3af2d 100644 --- a/crates/wasmparser/src/validator/core/canonical.rs +++ b/crates/wasmparser/src/validator/core/canonical.rs @@ -257,7 +257,7 @@ pub(crate) trait InternRecGroup { CompositeInnerType::Func(_) => (), _ => { return Err(BinaryReaderError::new( - format!("non-function type {}", id.index()), + crate::validator::format!("non-function type {}", id.index()), offset, )) }