diff --git a/crates/wasm-compose/src/encoding.rs b/crates/wasm-compose/src/encoding.rs index 2ef5a2b0ac..c1e1aec230 100644 --- a/crates/wasm-compose/src/encoding.rs +++ b/crates/wasm-compose/src/encoding.rs @@ -190,7 +190,6 @@ impl<'a> TypeEncoder<'a> { fn primitive(ty: wasmparser::PrimitiveValType) -> PrimitiveValType { match ty { - wasmparser::PrimitiveValType::Unit => PrimitiveValType::Unit, wasmparser::PrimitiveValType::Bool => PrimitiveValType::Bool, wasmparser::PrimitiveValType::S8 => PrimitiveValType::S8, wasmparser::PrimitiveValType::U8 => PrimitiveValType::U8, @@ -334,18 +333,43 @@ impl<'a> TypeEncoder<'a> { .as_component_func_type() .unwrap(); - let mut params = Vec::with_capacity(ty.params.len()); - for (name, ty) in ty.params.iter() { - params.push(( - name.as_deref(), - self.component_val_type(encodable, types, *ty), - )); - } + let params = ty + .params + .iter() + .map(|(name, ty)| { + ( + name.as_deref(), + self.component_val_type(encodable, types, *ty), + ) + }) + .collect::>(); - let result = self.component_val_type(encodable, types, ty.result); + let results = ty + .results + .iter() + .map(|(name, ty)| { + ( + name.as_deref(), + self.component_val_type(encodable, types, *ty), + ) + }) + .collect::>(); let index = encodable.type_count(); - encodable.ty().function(params, result); + let mut f = encodable.ty().function(); + + if params.len() == 1 && params[0].0.is_none() { + f.param(params[0].1); + } else { + f.params(params.into_iter().map(|(name, ty)| (name.unwrap(), ty))); + } + + if results.len() == 1 && results[0].0.is_none() { + f.result(results[0].1); + } else { + f.results(results.into_iter().map(|(name, ty)| (name.unwrap(), ty))); + } + types.insert(id, index); index } @@ -425,8 +449,8 @@ impl<'a> TypeEncoder<'a> { wasmparser::types::ComponentDefinedType::Option(ty) => { self.option(encodable, types, *ty) } - wasmparser::types::ComponentDefinedType::Expected(ok, err) => { - self.expected(encodable, types, *ok, *err) + wasmparser::types::ComponentDefinedType::Result { ok, err } => { + self.result(encodable, types, *ok, *err) } }; @@ -463,7 +487,7 @@ impl<'a> TypeEncoder<'a> { .map(|(n, c)| { ( n.as_str(), - self.component_val_type(encodable, types, c.ty), + c.ty.map(|ty| self.component_val_type(encodable, types, ty)), c.refines .as_deref() .map(|r| variant.cases.iter().position(|(n, _)| n == r).unwrap() as u32), @@ -551,18 +575,18 @@ impl<'a> TypeEncoder<'a> { index } - fn expected( + fn result( &self, encodable: &mut impl Encodable, types: &mut HashMap, - ok: wasmparser::types::ComponentValType, - err: wasmparser::types::ComponentValType, + ok: Option, + err: Option, ) -> u32 { - let ok = self.component_val_type(encodable, types, ok); - let err = self.component_val_type(encodable, types, err); + let ok = ok.map(|ty| self.component_val_type(encodable, types, ty)); + let err = err.map(|ty| self.component_val_type(encodable, types, ty)); let index = encodable.type_count(); - encodable.ty().defined_type().expected(ok, err); + encodable.ty().defined_type().result(ok, err); index } } diff --git a/crates/wasm-compose/tests/compositions/complex-import/composed.wat b/crates/wasm-compose/tests/compositions/complex-import/composed.wat index 838260ecd2..7f8f56aa21 100644 --- a/crates/wasm-compose/tests/compositions/complex-import/composed.wat +++ b/crates/wasm-compose/tests/compositions/complex-import/composed.wat @@ -54,7 +54,7 @@ (type (;26;) (option 4)) (type (;27;) (func (param "x" 26))) (export "t" (func (type 27))) - (type (;28;) (expected 0 string)) + (type (;28;) (result 0 (error string))) (type (;29;) (func (result 28))) (export "u" (func (type 29))) ) @@ -117,7 +117,7 @@ (type (;26;) (option 25)) (type (;27;) (func (param "x" 26))) (export "t" (func (type 27))) - (type (;28;) (expected 13 string)) + (type (;28;) (result 13 (error string))) (type (;29;) (func (result 28))) (export "u" (func (type 29))) ) diff --git a/crates/wasm-compose/tests/compositions/complex/a.wat b/crates/wasm-compose/tests/compositions/complex/a.wat index 822768c19f..565ef650ea 100644 --- a/crates/wasm-compose/tests/compositions/complex/a.wat +++ b/crates/wasm-compose/tests/compositions/complex/a.wat @@ -27,7 +27,7 @@ (type (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 13))) (type (option 25)) (type (func (param "x" 26))) - (type (expected 13 string)) + (type (result 13 (error string))) (type (func (result 28))) (export "record1" (type 13)) (export "flags1" (type 19)) diff --git a/crates/wasm-compose/tests/compositions/complex/b.wat b/crates/wasm-compose/tests/compositions/complex/b.wat index 26189a83fe..2dd97e7f25 100644 --- a/crates/wasm-compose/tests/compositions/complex/b.wat +++ b/crates/wasm-compose/tests/compositions/complex/b.wat @@ -27,7 +27,7 @@ (type (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 13))) (type (option 25)) (type (func (param "x" 26))) - (type (expected 13 string)) + (type (result 13 (error string))) (type (func (result 28))) (type (instance diff --git a/crates/wasm-compose/tests/compositions/complex/composed.wat b/crates/wasm-compose/tests/compositions/complex/composed.wat index a905c3e0e1..cb274213f3 100644 --- a/crates/wasm-compose/tests/compositions/complex/composed.wat +++ b/crates/wasm-compose/tests/compositions/complex/composed.wat @@ -28,7 +28,7 @@ (type (;25;) (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 13))) (type (;26;) (option 25)) (type (;27;) (func (param "x" 26))) - (type (;28;) (expected 13 string)) + (type (;28;) (result 13 (error string))) (type (;29;) (func (result 28))) (export "record1" (type 13)) (export "flags1" (type 19)) @@ -235,7 +235,7 @@ (type (;25;) (variant (case "a" s8) (case "b" u8) (case "c" s16) (case "d" u16) (case "e" s32) (case "f" u32) (case "g" s64) (case "h" u64) (case "i" float32) (case "j" float64) (case "k" bool) (case "l" string) (case "m" 13))) (type (;26;) (option 25)) (type (;27;) (func (param "x" 26))) - (type (;28;) (expected 13 string)) + (type (;28;) (result 13 (error string))) (type (;29;) (func (result 28))) (type (;30;) (instance diff --git a/crates/wasm-compose/tests/compositions/component-not-valid/error.txt b/crates/wasm-compose/tests/compositions/component-not-valid/error.txt index 024e995d45..8311cbdd07 100644 --- a/crates/wasm-compose/tests/compositions/component-not-valid/error.txt +++ b/crates/wasm-compose/tests/compositions/component-not-valid/error.txt @@ -2,4 +2,4 @@ failed to parse component `tests/compositions/component-not-valid/a.wat` Caused by: 0: failed to validate WebAssembly component `tests/compositions/component-not-valid/a.wat` - 1: unknown core function 0: function index out of bounds (at offset 0x11) \ No newline at end of file + 1: unknown core function 0: function index out of bounds (at offset 0x13) \ No newline at end of file diff --git a/crates/wasm-encoder/src/component/imports.rs b/crates/wasm-encoder/src/component/imports.rs index f62c328941..641163f3f5 100644 --- a/crates/wasm-encoder/src/component/imports.rs +++ b/crates/wasm-encoder/src/component/imports.rs @@ -86,13 +86,15 @@ impl Encode for ComponentTypeRef { /// let mut types = ComponentTypeSection::new(); /// /// // Define a function type of `[string, string] -> string`. -/// types.function( -/// [ -/// (Some("a"), PrimitiveValType::String), -/// (Some("b"), PrimitiveValType::String) -/// ], -/// PrimitiveValType::String -/// ); +/// types +/// .function() +/// .params( +/// [ +/// ("a", PrimitiveValType::String), +/// ("b", PrimitiveValType::String) +/// ] +/// ) +/// .result(PrimitiveValType::String); /// /// // This imports a function named `f` with the type defined above /// let mut imports = ComponentImportSection::new(); diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index 40cd32d3d8..62f5c8afba 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -369,44 +369,95 @@ impl Encode for InstanceType { } } -/// Used to encode component and instance types. +/// Used to encode component function types. #[derive(Debug)] -pub struct ComponentTypeEncoder<'a>(&'a mut Vec); +pub struct ComponentFuncTypeEncoder<'a>(&'a mut Vec); -impl<'a> ComponentTypeEncoder<'a> { - /// Define a component type. - pub fn component(self, ty: &ComponentType) { - ty.encode(self.0); +impl<'a> ComponentFuncTypeEncoder<'a> { + fn new(sink: &'a mut Vec) -> Self { + sink.push(0x40); + Self(sink) } - /// Define an instance type. - pub fn instance(self, ty: &InstanceType) { - ty.encode(self.0); + /// Defines a single unnamed parameter. + /// + /// This method cannot be used with `params`. + /// + /// Parameters must be defined before defining results. + pub fn param(&mut self, ty: impl Into) -> &mut Self { + self.0.push(0x00); + ty.into().encode(self.0); + self } - /// Define a function type. - pub fn function<'b, P, T>(self, params: P, result: impl Into) + /// Defines named parameters. + /// + /// This method cannot be used with `param`. + /// + /// Parameters must be defined before defining results. + pub fn params<'b, P, T>(&mut self, params: P) -> &mut Self where - P: IntoIterator, T)>, + P: IntoIterator, P::IntoIter: ExactSizeIterator, T: Into, { + self.0.push(0x01); let params = params.into_iter(); - self.0.push(0x40); - params.len().encode(self.0); for (name, ty) in params { - match name { - Some(name) => { - self.0.push(0x01); - name.encode(self.0); - } - None => self.0.push(0x00), - } + name.encode(self.0); + ty.into().encode(self.0); + } + self + } + + /// Defines a single unnamed result. + /// + /// This method cannot be used with `results`. + pub fn result(&mut self, ty: impl Into) -> &mut Self { + self.0.push(0x00); + ty.into().encode(self.0); + self + } + + /// Defines named results. + /// + /// This method cannot be used with `result`. + pub fn results<'b, R, T>(&mut self, results: R) -> &mut Self + where + R: IntoIterator, + R::IntoIter: ExactSizeIterator, + T: Into, + { + self.0.push(0x01); + let results = results.into_iter(); + results.len().encode(self.0); + for (name, ty) in results { + name.encode(self.0); ty.into().encode(self.0); } + self + } +} + +/// Used to encode component and instance types. +#[derive(Debug)] +pub struct ComponentTypeEncoder<'a>(&'a mut Vec); - result.into().encode(self.0); +impl<'a> ComponentTypeEncoder<'a> { + /// Define a component type. + pub fn component(self, ty: &ComponentType) { + ty.encode(self.0); + } + + /// Define an instance type. + pub fn instance(self, ty: &InstanceType) { + ty.encode(self.0); + } + + /// Define a function type. + pub fn function(self) -> ComponentFuncTypeEncoder<'a> { + ComponentFuncTypeEncoder::new(self.0) } /// Define a defined component type. @@ -421,8 +472,6 @@ impl<'a> ComponentTypeEncoder<'a> { /// Represents a primitive component value type. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum PrimitiveValType { - /// The type is the unit type. - Unit, /// The type is a boolean. Bool, /// The type is a signed 8-bit integer. @@ -454,20 +503,19 @@ pub enum PrimitiveValType { impl Encode for PrimitiveValType { fn encode(&self, sink: &mut Vec) { sink.push(match self { - Self::Unit => 0x7f, - Self::Bool => 0x7e, - Self::S8 => 0x7d, - Self::U8 => 0x7c, - Self::S16 => 0x7b, - Self::U16 => 0x7a, - Self::S32 => 0x79, - Self::U32 => 0x78, - Self::S64 => 0x77, - Self::U64 => 0x76, - Self::Float32 => 0x75, - Self::Float64 => 0x74, - Self::Char => 0x73, - Self::String => 0x72, + Self::Bool => 0x7f, + Self::S8 => 0x7e, + Self::U8 => 0x7d, + Self::S16 => 0x7c, + Self::U16 => 0x7b, + Self::S32 => 0x7a, + Self::U32 => 0x79, + Self::S64 => 0x78, + Self::U64 => 0x77, + Self::Float32 => 0x76, + Self::Float64 => 0x75, + Self::Char => 0x74, + Self::String => 0x73, }); } } @@ -516,7 +564,7 @@ impl ComponentDefinedTypeEncoder<'_> { T: Into, { let fields = fields.into_iter(); - self.0.push(0x71); + self.0.push(0x72); fields.len().encode(self.0); for (name, ty) in fields { name.encode(self.0); @@ -525,30 +573,24 @@ impl ComponentDefinedTypeEncoder<'_> { } /// Define a variant type. - pub fn variant<'a, C, T>(self, cases: C) + pub fn variant<'a, C>(self, cases: C) where - C: IntoIterator)>, + C: IntoIterator, Option)>, C::IntoIter: ExactSizeIterator, - T: Into, { let cases = cases.into_iter(); - self.0.push(0x70); + self.0.push(0x71); cases.len().encode(self.0); for (name, ty, refines) in cases { name.encode(self.0); - ty.into().encode(self.0); - if let Some(default) = refines { - self.0.push(0x01); - default.encode(self.0); - } else { - self.0.push(0x00); - } + ty.encode(self.0); + refines.encode(self.0); } } /// Define a list type. pub fn list(self, ty: impl Into) { - self.0.push(0x6f); + self.0.push(0x70); ty.into().encode(self.0); } @@ -560,7 +602,7 @@ impl ComponentDefinedTypeEncoder<'_> { T: Into, { let types = types.into_iter(); - self.0.push(0x6E); + self.0.push(0x6F); types.len().encode(self.0); for ty in types { ty.into().encode(self.0); @@ -574,7 +616,7 @@ impl ComponentDefinedTypeEncoder<'_> { I::IntoIter: ExactSizeIterator, { let names = names.into_iter(); - self.0.push(0x6D); + self.0.push(0x6E); names.len().encode(self.0); for name in names { name.encode(self.0); @@ -588,7 +630,7 @@ impl ComponentDefinedTypeEncoder<'_> { I::IntoIter: ExactSizeIterator, { let tags = tags.into_iter(); - self.0.push(0x6C); + self.0.push(0x6D); tags.len().encode(self.0); for tag in tags { tag.encode(self.0); @@ -603,7 +645,7 @@ impl ComponentDefinedTypeEncoder<'_> { T: Into, { let types = types.into_iter(); - self.0.push(0x6B); + self.0.push(0x6C); types.len().encode(self.0); for ty in types { ty.into().encode(self.0); @@ -612,15 +654,15 @@ impl ComponentDefinedTypeEncoder<'_> { /// Define an option type. pub fn option(self, ty: impl Into) { - self.0.push(0x6A); + self.0.push(0x6B); ty.into().encode(self.0); } - /// Define an expected type. - pub fn expected(self, ok: impl Into, error: impl Into) { - self.0.push(0x69); - ok.into().encode(self.0); - error.into().encode(self.0); + /// Define a result type. + pub fn result(self, ok: Option, err: Option) { + self.0.push(0x6A); + ok.encode(self.0); + err.encode(self.0); } } @@ -634,13 +676,15 @@ impl ComponentDefinedTypeEncoder<'_> { /// let mut types = ComponentTypeSection::new(); /// /// // Define a function type of `[string, string] -> string`. -/// types.function( -/// [ -/// (Some("a"), PrimitiveValType::String), -/// (Some("b"), PrimitiveValType::String) -/// ], -/// PrimitiveValType::String -/// ); +/// types +/// .function() +/// .params( +/// [ +/// ("a", PrimitiveValType::String), +/// ("b", PrimitiveValType::String) +/// ] +/// ) +/// .result(PrimitiveValType::String); /// /// let mut component = Component::new(); /// component.section(&types); @@ -691,18 +735,8 @@ impl ComponentTypeSection { } /// Define a function type in this type section. - pub fn function<'a, P, T>( - &mut self, - params: P, - result: impl Into, - ) -> &mut Self - where - P: IntoIterator, T)>, - P::IntoIter: ExactSizeIterator, - T: Into, - { - self.ty().function(params, result); - self + pub fn function(&mut self) -> ComponentFuncTypeEncoder<'_> { + self.ty().function() } /// Add a component defined type to this type section. diff --git a/crates/wasm-encoder/src/lib.rs b/crates/wasm-encoder/src/lib.rs index d8840f7934..c84e20f81d 100644 --- a/crates/wasm-encoder/src/lib.rs +++ b/crates/wasm-encoder/src/lib.rs @@ -144,6 +144,21 @@ impl Encode for i64 { } } +impl Encode for Option +where + T: Encode, +{ + fn encode(&self, sink: &mut Vec) { + match self { + Some(v) => { + sink.push(0x01); + v.encode(sink); + } + None => sink.push(0x00), + } + } +} + fn encoding_size(n: u32) -> usize { let mut buf = [0u8; 5]; leb128::write::unsigned(&mut &mut buf[..], n.into()).unwrap() diff --git a/crates/wasm-smith/src/component.rs b/crates/wasm-smith/src/component.rs index ea3186ed03..0cf39d27f9 100644 --- a/crates/wasm-smith/src/component.rs +++ b/crates/wasm-smith/src/component.rs @@ -1219,8 +1219,44 @@ impl ComponentBuilder { u: &mut Unstructured, type_fuel: &mut u32, ) -> Result> { - let mut params = vec![]; - let mut param_names = HashSet::new(); + let mut params = Vec::new(); + let mut results = Vec::new(); + let mut names = HashSet::new(); + + fn push( + b: &ComponentBuilder, + u: &mut Unstructured, + type_fuel: &mut u32, + names: &mut HashSet, + items: &mut Vec<(Option, ComponentValType)>, + ) -> Result { + *type_fuel = type_fuel.saturating_sub(1); + if *type_fuel == 0 { + return Ok(false); + } + + // If the collection is empty (i.e. first push), then arbitrarily give it a name. + // Otherwise, all of the items must be named. + let name = if items.is_empty() { + // Most of the time we should have named parameters/results. + u.ratio::(99, 100)? + .then(|| crate::unique_non_empty_string(100, names, u)) + .transpose()? + } else { + Some(crate::unique_non_empty_string(100, names, u)?) + }; + + let ty = b.arbitrary_component_val_type(u)?; + + items.push((name, ty)); + + // There can be only one unnamed parameter/result. + if items.len() == 1 && items[0].0.is_none() { + return Ok(false); + } + + Ok(true) + } // Note: parameters are currently limited to a maximum of 16 // because any additional parameters will require indirect access @@ -1232,18 +1268,19 @@ impl ComponentBuilder { // we should increase this maximum to test indirect parameter // passing. arbitrary_loop(u, 0, 16, |u| { - *type_fuel = type_fuel.saturating_sub(1); - if *type_fuel == 0 { - return Ok(false); - } - - params.push(self.arbitrary_optional_named_type(u, &mut param_names)?); - Ok(true) + push(self, u, type_fuel, &mut names, &mut params) })?; - let result = self.arbitrary_component_val_type(u)?; + names.clear(); - Ok(Rc::new(FuncType { params, result })) + // Likewise, the limit for results is 1 before the memory option is + // required. When the memory option is implemented, this restriction + // should be relaxed. + arbitrary_loop(u, 0, 1, |u| { + push(self, u, type_fuel, &mut names, &mut results) + })?; + + Ok(Rc::new(FuncType { params, results })) } fn arbitrary_component_val_type(&self, u: &mut Unstructured) -> Result { @@ -1266,49 +1303,24 @@ impl ComponentBuilder { } fn arbitrary_primitive_val_type(&self, u: &mut Unstructured) -> Result { - match u.int_in_range(0..=13)? { - 0 => Ok(PrimitiveValType::Unit), - 1 => Ok(PrimitiveValType::Bool), - 2 => Ok(PrimitiveValType::S8), - 3 => Ok(PrimitiveValType::U8), - 4 => Ok(PrimitiveValType::S16), - 5 => Ok(PrimitiveValType::U16), - 6 => Ok(PrimitiveValType::S32), - 7 => Ok(PrimitiveValType::U32), - 8 => Ok(PrimitiveValType::S64), - 9 => Ok(PrimitiveValType::U64), - 10 => Ok(PrimitiveValType::Float32), - 11 => Ok(PrimitiveValType::Float64), - 12 => Ok(PrimitiveValType::Char), - 13 => Ok(PrimitiveValType::String), + match u.int_in_range(0..=12)? { + 0 => Ok(PrimitiveValType::Bool), + 1 => Ok(PrimitiveValType::S8), + 2 => Ok(PrimitiveValType::U8), + 3 => Ok(PrimitiveValType::S16), + 4 => Ok(PrimitiveValType::U16), + 5 => Ok(PrimitiveValType::S32), + 6 => Ok(PrimitiveValType::U32), + 7 => Ok(PrimitiveValType::S64), + 8 => Ok(PrimitiveValType::U64), + 9 => Ok(PrimitiveValType::Float32), + 10 => Ok(PrimitiveValType::Float64), + 11 => Ok(PrimitiveValType::Char), + 12 => Ok(PrimitiveValType::String), _ => unreachable!(), } } - fn arbitrary_named_type( - &self, - u: &mut Unstructured, - names: &mut HashSet, - ) -> Result { - let name = crate::unique_non_empty_string(100, names, u)?; - let ty = self.arbitrary_component_val_type(u)?; - Ok(NamedType { name, ty }) - } - - fn arbitrary_optional_named_type( - &self, - u: &mut Unstructured, - names: &mut HashSet, - ) -> Result { - let name = if u.arbitrary()? { - Some(crate::unique_non_empty_string(100, names, u)?) - } else { - None - }; - let ty = self.arbitrary_component_val_type(u)?; - Ok(OptionalNamedType { name, ty }) - } - fn arbitrary_record_type( &self, u: &mut Unstructured, @@ -1322,7 +1334,10 @@ impl ComponentBuilder { return Ok(false); } - fields.push(self.arbitrary_named_type(u, &mut field_names)?); + let name = crate::unique_non_empty_string(100, &mut field_names, u)?; + let ty = self.arbitrary_component_val_type(u)?; + + fields.push((name, ty)); Ok(true) })?; Ok(RecordType { fields }) @@ -1341,14 +1356,21 @@ impl ComponentBuilder { return Ok(false); } - let default = if !cases.is_empty() && u.arbitrary()? { + let name = crate::unique_non_empty_string(100, &mut case_names, u)?; + + let ty = u + .arbitrary::()? + .then(|| self.arbitrary_component_val_type(u)) + .transpose()?; + + let refines = if !cases.is_empty() && u.arbitrary()? { let max_cases = u32::try_from(cases.len() - 1).unwrap(); Some(u.int_in_range(0..=max_cases)?) } else { None }; - cases.push((self.arbitrary_named_type(u, &mut case_names)?, default)); + cases.push((name, ty, refines)); Ok(true) })?; @@ -1425,10 +1447,16 @@ impl ComponentBuilder { }) } - fn arbitrary_expected_type(&self, u: &mut Unstructured) -> Result { - Ok(ExpectedType { - ok_ty: self.arbitrary_component_val_type(u)?, - err_ty: self.arbitrary_component_val_type(u)?, + fn arbitrary_result_type(&self, u: &mut Unstructured) -> Result { + Ok(ResultType { + ok_ty: u + .arbitrary::()? + .then(|| self.arbitrary_component_val_type(u)) + .transpose()?, + err_ty: u + .arbitrary::()? + .then(|| self.arbitrary_component_val_type(u)) + .transpose()?, }) } @@ -1453,7 +1481,7 @@ impl ComponentBuilder { 6 => Ok(DefinedType::Enum(self.arbitrary_enum_type(u, type_fuel)?)), 7 => Ok(DefinedType::Union(self.arbitrary_union_type(u, type_fuel)?)), 8 => Ok(DefinedType::Option(self.arbitrary_option_type(u)?)), - 9 => Ok(DefinedType::Expected(self.arbitrary_expected_type(u)?)), + 9 => Ok(DefinedType::Result(self.arbitrary_result_type(u)?)), _ => unreachable!(), } } @@ -1745,7 +1773,6 @@ impl ComponentBuilder { fn canonical_abi_for(func_ty: &FuncType) -> Rc { let to_core_ty = |ty| match ty { ComponentValType::Primitive(prim_ty) => match prim_ty { - PrimitiveValType::Unit => None, PrimitiveValType::Char | PrimitiveValType::Bool | PrimitiveValType::S8 @@ -1753,10 +1780,10 @@ fn canonical_abi_for(func_ty: &FuncType) -> Rc { | PrimitiveValType::S16 | PrimitiveValType::U16 | PrimitiveValType::S32 - | PrimitiveValType::U32 => Some(ValType::I32), - PrimitiveValType::S64 | PrimitiveValType::U64 => Some(ValType::I64), - PrimitiveValType::Float32 => Some(ValType::F32), - PrimitiveValType::Float64 => Some(ValType::F64), + | PrimitiveValType::U32 => ValType::I32, + PrimitiveValType::S64 | PrimitiveValType::U64 => ValType::I64, + PrimitiveValType::Float32 => ValType::F32, + PrimitiveValType::Float64 => ValType::F64, PrimitiveValType::String => { unimplemented!("non-scalar types are not supported yet") } @@ -1768,9 +1795,13 @@ fn canonical_abi_for(func_ty: &FuncType) -> Rc { params: func_ty .params .iter() - .flat_map(|ty| to_core_ty(ty.ty)) + .map(|(_, ty)| to_core_ty(*ty)) + .collect(), + results: func_ty + .results + .iter() + .map(|(_, ty)| to_core_ty(*ty)) .collect(), - results: to_core_ty(func_ty.result).into_iter().collect(), }) } @@ -1804,46 +1835,36 @@ fn inverse_scalar_canonical_abi_for( } }; - let mut param_names = HashSet::default(); + let mut names = HashSet::default(); let mut params = vec![]; - if u.ratio::(1, 25)? { - params.push(OptionalNamedType { - name: if u.arbitrary()? { - Some(crate::unique_non_empty_string(100, &mut param_names, u)?) + + for core_ty in &core_func_ty.params { + params.push(( + if core_func_ty.params.len() > 1 || u.arbitrary()? { + Some(crate::unique_non_empty_string(100, &mut names, u)?) } else { None }, - ty: ComponentValType::Primitive(PrimitiveValType::Unit), - }); + from_core_ty(u, *core_ty)?, + )); } - for core_ty in &core_func_ty.params { - params.push(OptionalNamedType { - name: if u.arbitrary()? { - Some(crate::unique_non_empty_string(100, &mut param_names, u)?) + + names.clear(); + + let results = match core_func_ty.results.len() { + 0 => Vec::new(), + 1 => vec![( + if u.arbitrary()? { + Some(crate::unique_non_empty_string(100, &mut names, u)?) } else { None }, - ty: from_core_ty(u, *core_ty)?, - }); - if u.ratio::(1, 25)? { - params.push(OptionalNamedType { - name: if u.arbitrary()? { - Some(crate::unique_non_empty_string(100, &mut param_names, u)?) - } else { - None - }, - ty: ComponentValType::Primitive(PrimitiveValType::Unit), - }); - } - } - - let result = match core_func_ty.results.len() { - 0 => ComponentValType::Primitive(PrimitiveValType::Unit), - 1 => from_core_ty(u, core_func_ty.results[0])?, + from_core_ty(u, core_func_ty.results[0])?, + )], _ => unimplemented!("non-scalar types are not supported yet"), }; - Ok(FuncType { params, result }) + Ok(FuncType { params, results }) } #[derive(Debug)] @@ -2014,33 +2035,42 @@ enum InstanceTypeDef { #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct FuncType { - params: Vec, - result: ComponentValType, + params: Vec<(Option, ComponentValType)>, + results: Vec<(Option, ComponentValType)>, } impl FuncType { - fn is_scalar(&self) -> bool { - self.params.iter().all(|p| p.is_scalar()) && is_scalar(&self.result) + fn unnamed_param_ty(&self) -> Option { + if self.params.len() == 1 { + let (name, ty) = &self.params[0]; + if name.is_none() { + return Some(*ty); + } + } + None } -} -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -struct OptionalNamedType { - name: Option, - ty: ComponentValType, -} + fn unnamed_result_ty(&self) -> Option { + if self.results.len() == 1 { + let (name, ty) = &self.results[0]; + if name.is_none() { + return Some(*ty); + } + } + None + } -impl OptionalNamedType { fn is_scalar(&self) -> bool { - is_scalar(&self.ty) + self.params.iter().all(|(_, ty)| is_scalar(ty)) + && self.results.len() == 1 + && is_scalar(&self.results[0].1) } } fn is_scalar(ty: &ComponentValType) -> bool { match ty { ComponentValType::Primitive(prim) => match prim { - PrimitiveValType::Unit - | PrimitiveValType::Bool + PrimitiveValType::Bool | PrimitiveValType::S8 | PrimitiveValType::U8 | PrimitiveValType::S16 @@ -2058,12 +2088,6 @@ fn is_scalar(ty: &ComponentValType) -> bool { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -struct NamedType { - name: String, - ty: ComponentValType, -} - #[derive(Clone, Debug, PartialEq, Eq, Hash)] enum DefinedType { Primitive(PrimitiveValType), @@ -2075,17 +2099,17 @@ enum DefinedType { Enum(EnumType), Union(UnionType), Option(OptionType), - Expected(ExpectedType), + Result(ResultType), } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct RecordType { - fields: Vec, + fields: Vec<(String, ComponentValType)>, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct VariantType { - cases: Vec<(NamedType, Option)>, + cases: Vec<(String, Option, Option)>, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -2119,9 +2143,9 @@ struct OptionType { } #[derive(Clone, Debug, PartialEq, Eq, Hash)] -struct ExpectedType { - ok_ty: ComponentValType, - err_ty: ComponentValType, +struct ResultType { + ok_ty: Option, + err_ty: Option, } #[derive(Debug)] diff --git a/crates/wasm-smith/src/component/encode.rs b/crates/wasm-smith/src/component/encode.rs index 320101f008..e8f2b36f44 100644 --- a/crates/wasm-smith/src/component/encode.rs +++ b/crates/wasm-smith/src/component/encode.rs @@ -163,10 +163,29 @@ impl Type { ty.encode(enc.defined_type()); } Self::Func(func_ty) => { - enc.function( - func_ty.params.iter().map(translate_optional_named_type), - func_ty.result, - ); + let mut f = enc.function(); + + if let Some(ty) = func_ty.unnamed_param_ty() { + f.param(ty); + } else { + f.params( + func_ty + .params + .iter() + .map(|(name, ty)| (name.as_deref().unwrap(), *ty)), + ); + } + + if let Some(ty) = func_ty.unnamed_result_ty() { + f.result(ty); + } else { + f.results( + func_ty + .results + .iter() + .map(|(name, ty)| (name.as_deref().unwrap(), *ty)), + ); + } } Self::Component(comp_ty) => { let mut enc_comp_ty = wasm_encoder::ComponentType::new(); @@ -244,13 +263,13 @@ impl DefinedType { match self { Self::Primitive(ty) => enc.primitive(*ty), Self::Record(ty) => { - enc.record(ty.fields.iter().map(translate_named_type)); + enc.record(ty.fields.iter().map(|(name, ty)| (name.as_str(), *ty))); } Self::Variant(ty) => { enc.variant( ty.cases .iter() - .map(|(ty, refines)| (ty.name.as_str(), ty.ty, *refines)), + .map(|(name, ty, refines)| (name.as_str(), *ty, *refines)), ); } Self::List(ty) => { @@ -271,21 +290,13 @@ impl DefinedType { Self::Option(ty) => { enc.option(ty.inner_ty); } - Self::Expected(ty) => { - enc.expected(ty.ok_ty, ty.err_ty); + Self::Result(ty) => { + enc.result(ty.ok_ty, ty.err_ty); } } } } -fn translate_named_type(ty: &NamedType) -> (&str, ComponentValType) { - (&ty.name, ty.ty) -} - -fn translate_optional_named_type(ty: &OptionalNamedType) -> (Option<&str>, ComponentValType) { - (ty.name.as_deref(), ty.ty) -} - fn translate_canon_opt(options: &[CanonOpt]) -> Vec { options .iter() diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 71ddde6d6b..81b1476ec5 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -309,22 +309,12 @@ impl<'a> BinaryReader<'a> { pub(crate) fn read_component_type(&mut self) -> Result> { Ok(match self.read_u8()? { - 0x40 => { - let params_size = - self.read_size(MAX_WASM_FUNCTION_PARAMS, "function parameters")?; - let params = (0..params_size) - .map(|_| { - Ok(( - self.read_optional_string()?, - self.read_component_val_type()?, - )) - }) - .collect::>()?; - ComponentType::Func(ComponentFuncType { - params, - result: self.read_component_val_type()?, - }) - } + 0x40 => ComponentType::Func(ComponentFuncType { + params: self + .read_type_vec(MAX_WASM_FUNCTION_PARAMS, "component function parameters")?, + results: self + .read_type_vec(MAX_WASM_FUNCTION_RETURNS, "component function results")?, + }), 0x41 => { let size = self.read_size(MAX_WASM_COMPONENT_TYPE_DECLS, "component type declaration")?; @@ -353,6 +343,21 @@ impl<'a> BinaryReader<'a> { }) } + pub(crate) fn read_type_vec(&mut self, max: usize, desc: &str) -> Result> { + Ok(match self.read_u8()? { + 0x00 => TypeVec::Unnamed(self.read_component_val_type()?), + 0x01 => { + let size = self.read_size(max, desc)?; + TypeVec::Named( + (0..size) + .map(|_| Ok((self.read_string()?, self.read_component_val_type()?))) + .collect::>()?, + ) + } + x => return self.invalid_leading_byte(x, desc), + }) + } + pub(crate) fn read_module_type_decl(&mut self) -> Result> { Ok(match self.read_u8()? { 0x00 => ModuleTypeDeclaration::Import(self.read_import()?), @@ -402,20 +407,19 @@ impl<'a> BinaryReader<'a> { fn primitive_val_type_from_byte(byte: u8) -> Option { Some(match byte { - 0x7f => PrimitiveValType::Unit, - 0x7e => PrimitiveValType::Bool, - 0x7d => PrimitiveValType::S8, - 0x7c => PrimitiveValType::U8, - 0x7b => PrimitiveValType::S16, - 0x7a => PrimitiveValType::U16, - 0x79 => PrimitiveValType::S32, - 0x78 => PrimitiveValType::U32, - 0x77 => PrimitiveValType::S64, - 0x76 => PrimitiveValType::U64, - 0x75 => PrimitiveValType::Float32, - 0x74 => PrimitiveValType::Float64, - 0x73 => PrimitiveValType::Char, - 0x72 => PrimitiveValType::String, + 0x7f => PrimitiveValType::Bool, + 0x7e => PrimitiveValType::S8, + 0x7d => PrimitiveValType::U8, + 0x7c => PrimitiveValType::S16, + 0x7b => PrimitiveValType::U16, + 0x7a => PrimitiveValType::S32, + 0x79 => PrimitiveValType::U32, + 0x78 => PrimitiveValType::S64, + 0x77 => PrimitiveValType::U64, + 0x76 => PrimitiveValType::Float32, + 0x75 => PrimitiveValType::Float64, + 0x74 => PrimitiveValType::Char, + 0x73 => PrimitiveValType::String, _ => return None, }) } @@ -423,11 +427,11 @@ impl<'a> BinaryReader<'a> { fn read_variant_case(&mut self) -> Result> { Ok(VariantCase { name: self.read_string()?, - ty: self.read_component_val_type()?, + ty: self.read_optional_val_type()?, refines: match self.read_u8()? { 0x0 => None, 0x1 => Some(self.read_var_u32()?), - x => return self.invalid_leading_byte(x, "variant case default"), + x => return self.invalid_leading_byte(x, "variant case refines"), }, }) } @@ -443,7 +447,7 @@ impl<'a> BinaryReader<'a> { fn read_component_defined_type(&mut self, byte: u8) -> Result> { Ok(match byte { - 0x71 => { + 0x72 => { let size = self.read_size(MAX_WASM_RECORD_FIELDS, "record field")?; ComponentDefinedType::Record( (0..size) @@ -451,7 +455,7 @@ impl<'a> BinaryReader<'a> { .collect::>()?, ) } - 0x70 => { + 0x71 => { let size = self.read_size(MAX_WASM_VARIANT_CASES, "variant cases")?; ComponentDefinedType::Variant( (0..size) @@ -459,8 +463,8 @@ impl<'a> BinaryReader<'a> { .collect::>()?, ) } - 0x6f => ComponentDefinedType::List(self.read_component_val_type()?), - 0x6e => { + 0x70 => ComponentDefinedType::List(self.read_component_val_type()?), + 0x6f => { let size = self.read_size(MAX_WASM_TUPLE_TYPES, "tuple types")?; ComponentDefinedType::Tuple( (0..size) @@ -468,7 +472,7 @@ impl<'a> BinaryReader<'a> { .collect::>()?, ) } - 0x6d => { + 0x6e => { let size = self.read_size(MAX_WASM_FLAG_NAMES, "flag names")?; ComponentDefinedType::Flags( (0..size) @@ -476,7 +480,7 @@ impl<'a> BinaryReader<'a> { .collect::>()?, ) } - 0x6c => { + 0x6d => { let size = self.read_size(MAX_WASM_ENUM_CASES, "enum cases")?; ComponentDefinedType::Enum( (0..size) @@ -484,7 +488,7 @@ impl<'a> BinaryReader<'a> { .collect::>()?, ) } - 0x6b => { + 0x6c => { let size = self.read_size(MAX_WASM_UNION_TYPES, "union types")?; ComponentDefinedType::Union( (0..size) @@ -492,10 +496,10 @@ impl<'a> BinaryReader<'a> { .collect::>()?, ) } - 0x6a => ComponentDefinedType::Option(self.read_component_val_type()?), - 0x69 => ComponentDefinedType::Expected { - ok: self.read_component_val_type()?, - error: self.read_component_val_type()?, + 0x6b => ComponentDefinedType::Option(self.read_component_val_type()?), + 0x6a => ComponentDefinedType::Result { + ok: self.read_optional_val_type()?, + err: self.read_optional_val_type()?, }, x => return self.invalid_leading_byte(x, "component defined type"), }) @@ -1261,14 +1265,11 @@ impl<'a> BinaryReader<'a> { }) } - fn read_optional_string(&mut self) -> Result> { + fn read_optional_val_type(&mut self) -> Result> { match self.read_u8()? { 0x0 => Ok(None), - 0x1 => Ok(Some(self.read_string()?)), - _ => Err(BinaryReaderError::new( - "invalid optional string encoding", - self.original_position() - 1, - )), + 0x1 => Ok(Some(self.read_component_val_type()?)), + x => self.invalid_leading_byte(x, "optional component value type"), } } diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs index 4a148029b1..bd49aecf8d 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -295,7 +295,7 @@ impl Parser { Parser { state: State::Header, offset, - max_size: u64::max_value(), + max_size: u64::MAX, // Assume the encoding is a module until we know otherwise encoding: Encoding::Module, } diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index 40ce2937d6..b2ea1d7cc6 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -131,8 +131,6 @@ pub enum ComponentValType { /// Represents a primitive value type. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PrimitiveValType { - /// The type is the unit type. - Unit, /// The type is a boolean. Bool, /// The type is a signed 8-bit integer. @@ -173,8 +171,7 @@ impl PrimitiveValType { a == b || matches!( (a, b), - (_, Self::Unit) - | (Self::S8, Self::S16) + (Self::S8, Self::S16) | (Self::S8, Self::S32) | (Self::S8, Self::S64) | (Self::U8, Self::U16) @@ -195,13 +192,6 @@ impl PrimitiveValType { | (Self::Float32, Self::Float64) ) } - - pub(crate) fn type_size(&self) -> usize { - match self { - Self::Unit => 0, - _ => 1, - } - } } /// Represents a type in a WebAssembly component. @@ -255,13 +245,66 @@ pub enum InstanceTypeDeclaration<'a> { }, } +/// Represents the vector of types in a component function's +/// parameters or results. +#[derive(Debug, Clone)] +pub enum TypeVec<'a> { + /// The type vector contains a single, unnamed type. + Unnamed(ComponentValType), + /// The type vector contains zero or more named types. + Named(Box<[(&'a str, ComponentValType)]>), +} + +impl TypeVec<'_> { + /// Gets the type vector's length. + pub fn len(&self) -> usize { + match self { + Self::Unnamed(_) => 1, + Self::Named(vec) => vec.len(), + } + } + + /// Determines if the type vector is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Iterates over the types in the type vector. + pub fn iter(&self) -> impl Iterator, &ComponentValType)> { + enum Either { + Left(L), + Right(R), + } + + impl Iterator for Either + where + L: Iterator, + R: Iterator, + { + type Item = L::Item; + + fn next(&mut self) -> Option { + match self { + Either::Left(l) => l.next(), + Either::Right(r) => r.next(), + } + } + } + + match self { + Self::Unnamed(ty) => Either::Left(std::iter::once(ty).map(|ty| (None, ty))), + Self::Named(vec) => Either::Right(vec.iter().map(|(n, ty)| (Some(*n), ty))), + } + } +} + /// Represents a type of a function in a WebAssembly component. #[derive(Debug, Clone)] pub struct ComponentFuncType<'a> { - /// The function parameter types. - pub params: Box<[(Option<&'a str>, ComponentValType)]>, - /// The function result type. - pub result: ComponentValType, + /// The function parameters. + pub params: TypeVec<'a>, + /// The function results. + pub results: TypeVec<'a>, } /// Represents a case in a variant type. @@ -270,7 +313,7 @@ pub struct VariantCase<'a> { /// The name of the variant case. pub name: &'a str, /// The value type of the variant case. - pub ty: ComponentValType, + pub ty: Option, /// The index of the variant case that is refined by this one. pub refines: Option, } @@ -296,12 +339,12 @@ pub enum ComponentDefinedType<'a> { Union(Box<[ComponentValType]>), /// The type is an option of the given value type. Option(ComponentValType), - /// The type is an expected type. - Expected { + /// The type is a result type. + Result { /// The type returned for success. - ok: ComponentValType, + ok: Option, /// The type returned for failure. - error: ComponentValType, + err: Option, }, } @@ -335,7 +378,7 @@ impl<'a> ComponentTypeSectionReader<'a> { /// # Examples /// ``` /// use wasmparser::ComponentTypeSectionReader; - /// let data: &[u8] = &[0x01, 0x40, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x72, 0x72]; + /// let data: &[u8] = &[0x01, 0x40, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x73, 0x00, 0x73]; /// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap(); /// for _ in 0..reader.get_count() { /// let ty = reader.read().expect("type"); @@ -382,7 +425,7 @@ impl<'a> IntoIterator for ComponentTypeSectionReader<'a> { /// # Examples /// ``` /// use wasmparser::ComponentTypeSectionReader; - /// let data: &[u8] = &[0x01, 0x40, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x72, 0x72]; + /// let data: &[u8] = &[0x01, 0x40, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x73, 0x00, 0x73]; /// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap(); /// for ty in reader { /// println!("Type {:?}", ty.expect("type")); diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 1dfd00a84b..d670600d9b 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -16,11 +16,11 @@ use crate::{ UnionType, VariantType, }, BinaryReaderError, CanonicalOption, ComponentExternalKind, ComponentOuterAliasKind, - ComponentTypeRef, ExternalKind, FuncType, GlobalType, InstantiationArgKind, MemoryType, - PrimitiveValType, Result, TableType, TypeBounds, ValType, WasmFeatures, + ComponentTypeRef, ExternalKind, FuncType, GlobalType, InstantiationArgKind, MemoryType, Result, + TableType, TypeBounds, ValType, WasmFeatures, }; use indexmap::{IndexMap, IndexSet}; -use std::mem; +use std::{collections::HashSet, mem}; pub(crate) struct ComponentState { // Core index spaces @@ -480,11 +480,8 @@ impl ComponentState { } } - match ft.result { - ComponentValType::Primitive(PrimitiveValType::Unit) => {} - ty => { - self.values.push((ty, false)); - } + for (_, ty) in ft.results.iter() { + self.values.push((*ty, false)); } self.has_start = true; @@ -902,12 +899,17 @@ impl ComponentState { ) -> Result { let mut type_size = 1; + let mut set = HashSet::with_capacity(std::cmp::max(ty.params.len(), ty.results.len())); + let params = ty .params .iter() .map(|(name, ty)| { if let Some(name) = name { Self::check_name(name, "function parameter", offset)?; + if !set.insert(name) { + return Err(BinaryReaderError::new("duplicate parameter name", offset)); + } } let ty = self.create_component_val_type(*ty, types, offset)?; type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; @@ -915,13 +917,28 @@ impl ComponentState { }) .collect::>()?; - let result = self.create_component_val_type(ty.result, types, offset)?; - type_size = combine_type_sizes(type_size, result.type_size(), offset)?; + set.clear(); + + let results = ty + .results + .iter() + .map(|(name, ty)| { + if let Some(name) = name { + Self::check_name(name, "function result", offset)?; + if !set.insert(name) { + return Err(BinaryReaderError::new("duplicate result name", offset)); + } + } + let ty = self.create_component_val_type(*ty, types, offset)?; + type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; + Ok((name.map(ToOwned::to_owned), ty)) + }) + .collect::>()?; Ok(ComponentFuncType { type_size, params, - result, + results, }) } @@ -1657,12 +1674,14 @@ impl ComponentState { crate::ComponentDefinedType::Option(ty) => Ok(ComponentDefinedType::Option( self.create_component_val_type(ty, types, offset)?, )), - crate::ComponentDefinedType::Expected { ok, error } => { - Ok(ComponentDefinedType::Expected( - self.create_component_val_type(ok, types, offset)?, - self.create_component_val_type(error, types, offset)?, - )) - } + crate::ComponentDefinedType::Result { ok, err } => Ok(ComponentDefinedType::Result { + ok: ok + .map(|ty| self.create_component_val_type(ty, types, offset)) + .transpose()?, + err: err + .map(|ty| self.create_component_val_type(ty, types, offset)) + .transpose()?, + }), } } @@ -1710,6 +1729,13 @@ impl ComponentState { )); } + if cases.len() > u32::MAX as usize { + return Err(BinaryReaderError::new( + "variant type cannot be represented with a 32-bit discriminant value", + offset, + )); + } + for (i, case) in cases.iter().enumerate() { Self::check_name(case.name, "variant case", offset)?; if let Some(refines) = case.refines { @@ -1720,8 +1746,13 @@ impl ComponentState { )); } } - let ty = self.create_component_val_type(case.ty, types, offset)?; - type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; + let ty = case + .ty + .map(|ty| self.create_component_val_type(ty, types, offset)) + .transpose()?; + + type_size = + combine_type_sizes(type_size, ty.map(|ty| ty.type_size()).unwrap_or(1), offset)?; if case_map .insert( @@ -1782,7 +1813,7 @@ impl ComponentState { } fn create_enum_type(&self, cases: &[&str], offset: usize) -> Result { - if cases.len() > u32::max_value() as usize { + if cases.len() > u32::MAX as usize { return Err(BinaryReaderError::new( "enumeration type cannot be represented with a 32-bit discriminant value", offset, diff --git a/crates/wasmparser/src/validator/types.rs b/crates/wasmparser/src/validator/types.rs index d3aa981a38..3b60b5d19e 100644 --- a/crates/wasmparser/src/validator/types.rs +++ b/crates/wasmparser/src/validator/types.rs @@ -114,7 +114,6 @@ impl Default for LoweringInfo { fn push_primitive_wasm_types(ty: &PrimitiveValType, lowered_types: &mut LoweredTypes) -> bool { match ty { - PrimitiveValType::Unit => true, PrimitiveValType::Bool | PrimitiveValType::S8 | PrimitiveValType::U8 @@ -322,7 +321,7 @@ impl ComponentValType { pub(crate) fn type_size(&self) -> usize { match self { - Self::Primitive(ty) => ty.type_size(), + Self::Primitive(_) => 1, Self::Type(id) => id.type_size, } } @@ -681,7 +680,7 @@ impl ComponentInstanceType { } } - /// Determines if this component instance type is a subtype of the given one. + /// Determines if component instance type `a` is a subtype of `b`. pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { Self::internal_is_subtype_of(a, at.list, b, bt.list) } @@ -708,47 +707,65 @@ pub struct ComponentFuncType { pub(crate) type_size: usize, /// The function parameters. pub params: Box<[(Option, ComponentValType)]>, - /// The function's result type. - pub result: ComponentValType, + /// The function's results. + pub results: Box<[(Option, ComponentValType)]>, } impl ComponentFuncType { - /// Determines if this component function type is a subtype of the given one. + /// Determines if component function type `a` is a subtype of `b`. pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { Self::internal_is_subtype_of(a, at.list, b, bt.list) } pub(crate) fn internal_is_subtype_of(a: &Self, at: &TypeList, b: &Self, bt: &TypeList) -> bool { // Subtyping rules: - // https://github.com/WebAssembly/component-model/blob/17f94ed1270a98218e0e796ca1dad1feb7e5c507/design/mvp/Subtyping.md + // https://github.com/WebAssembly/component-model/blob/main/design/mvp/Subtyping.md - // Covariant on return type - if !ComponentValType::internal_is_subtype_of(&a.result, at, &b.result, bt) { + // The subtype cannot have more parameters than the supertype + if b.params.len() < a.params.len() { return false; } - // The supertype cannot have fewer parameters than the subtype. - if b.params.len() < a.params.len() { + // The supertype cannot have more results than the subtype + if a.results.len() < b.results.len() { return false; } - // All overlapping parameters must have the same name and are contravariant subtypes for ((an, a), (bn, b)) in a.params.iter().zip(b.params.iter()) { + // All overlapping parameters must have the same name if an != bn { return false; } + // Contravariant on parameters if !ComponentValType::internal_is_subtype_of(b, bt, a, at) { return false; } } // All remaining parameters in the supertype must be optional - // All superfluous parameters in the subtype are ignored - b.params + if !b + .params .iter() .skip(a.params.len()) .all(|(_, b)| b.is_optional(bt)) + { + return false; + } + + for ((an, a), (bn, b)) in a.results.iter().zip(b.results.iter()) { + // All overlapping results must have the same name + if an != bn { + return false; + } + + // Covariant on results + if !ComponentValType::internal_is_subtype_of(a, at, b, bt) { + return false; + } + } + + true } /// Lowers the component function type to core parameter and result types for the @@ -759,8 +776,8 @@ impl ComponentFuncType { for (_, ty) in self.params.iter() { // When `import` is false, it means we're lifting a core function, // check if the parameters needs realloc - if !import { - info.requires_realloc = info.requires_realloc || ty.requires_realloc(types); + if !import && !info.requires_realloc { + info.requires_realloc = ty.requires_realloc(types); } if !ty.push_wasm_types(types, &mut info.params) { @@ -779,23 +796,26 @@ impl ComponentFuncType { } } - // When `import` is true, it means we're lowering a component function, - // check if the result needs realloc - if import { - info.requires_realloc = info.requires_realloc || self.result.requires_realloc(types); - } + for (_, ty) in self.results.iter() { + // When `import` is true, it means we're lowering a component function, + // check if the result needs realloc + if import && !info.requires_realloc { + info.requires_realloc = ty.requires_realloc(types); + } - if !self.result.push_wasm_types(types, &mut info.results) { - // Too many results to return directly, either a retptr parameter will be used (import) - // or a single pointer will be returned (export) - info.results.clear(); - if import { - info.params.max = MAX_LOWERED_TYPES; - assert!(info.params.push(ValType::I32)); - } else { - assert!(info.results.push(ValType::I32)); + if !ty.push_wasm_types(types, &mut info.results) { + // Too many results to return directly, either a retptr parameter will be used (import) + // or a single pointer will be returned (export) + info.results.clear(); + if import { + info.params.max = MAX_LOWERED_TYPES; + assert!(info.params.push(ValType::I32)); + } else { + assert!(info.results.push(ValType::I32)); + } + info.requires_memory = true; + break; } - info.requires_memory = true; } // Memory is always required when realloc is required @@ -809,7 +829,7 @@ impl ComponentFuncType { #[derive(Debug, Clone)] pub struct VariantCase { /// The variant case type. - pub ty: ComponentValType, + pub ty: Option, /// The name of the variant case refined by this one. pub refines: Option, } @@ -871,8 +891,13 @@ pub enum ComponentDefinedType { Union(UnionType), /// The type is an `option`. Option(ComponentValType), - /// The type is an `expected`. - Expected(ComponentValType, ComponentValType), + /// The type is a `result`. + Result { + /// The `ok` type. + ok: Option, + /// The `error` type. + err: Option, + }, } impl ComponentDefinedType { @@ -880,26 +905,31 @@ impl ComponentDefinedType { match self { Self::Primitive(ty) => ty.requires_realloc(), Self::Record(r) => r.fields.values().any(|ty| ty.requires_realloc(types)), - Self::Variant(v) => v.cases.values().any(|case| case.ty.requires_realloc(types)), + Self::Variant(v) => v.cases.values().any(|case| { + case.ty + .map(|ty| ty.requires_realloc(types)) + .unwrap_or(false) + }), Self::List(_) => true, Self::Tuple(t) => t.types.iter().any(|ty| ty.requires_realloc(types)), Self::Union(u) => u.types.iter().any(|ty| ty.requires_realloc(types)), Self::Flags(_) | Self::Enum(_) => false, Self::Option(ty) => ty.requires_realloc(types), - Self::Expected(ok, error) => { - ok.requires_realloc(types) || error.requires_realloc(types) + Self::Result { ok, err } => { + ok.map(|ty| ty.requires_realloc(types)).unwrap_or(false) + || err.map(|ty| ty.requires_realloc(types)).unwrap_or(false) } } } - /// Determines if this component defined type is a subtype of the given one. + /// Determines if component defined type `a` is a subtype of `b`. pub fn is_subtype_of(a: &Self, at: TypesRef, b: &Self, bt: TypesRef) -> bool { Self::internal_is_subtype_of(a, at.list, b, bt.list) } pub(crate) fn internal_is_subtype_of(a: &Self, at: &TypeList, b: &Self, bt: &TypeList) -> bool { // Subtyping rules according to - // https://github.com/WebAssembly/component-model/blob/17f94ed1270a98218e0e796ca1dad1feb7e5c507/design/mvp/Subtyping.md + // https://github.com/WebAssembly/component-model/blob/main/design/mvp/Subtyping.md match (a, b) { (Self::Primitive(a), Self::Primitive(b)) => PrimitiveValType::is_subtype_of(*a, *b), (Self::Record(a), Self::Record(b)) => { @@ -924,12 +954,12 @@ impl ComponentDefinedType { for (name, a) in a.cases.iter() { if let Some(b) = b.cases.get(name) { // Covariant subtype on the case type - if !ComponentValType::internal_is_subtype_of(&a.ty, at, &b.ty, bt) { + if !Self::is_optional_subtype_of(a.ty, at, b.ty, bt) { return false; } } else if let Some(refines) = &a.refines { if !b.cases.contains_key(refines) { - // The refined value is not in the supertype + // The refinement case is not in the supertype return false; } } else { @@ -962,9 +992,9 @@ impl ComponentDefinedType { .all(|(a, b)| ComponentValType::internal_is_subtype_of(a, at, b, bt)) } (Self::Flags(a), Self::Flags(b)) | (Self::Enum(a), Self::Enum(b)) => a.is_subset(b), - (Self::Expected(ao, ae), Self::Expected(bo, be)) => { - ComponentValType::internal_is_subtype_of(ao, at, bo, bt) - && ComponentValType::internal_is_subtype_of(ae, at, be, bt) + (Self::Result { ok: ao, err: ae }, Self::Result { ok: bo, err: be }) => { + Self::is_optional_subtype_of(*ao, at, *bo, bt) + && Self::is_optional_subtype_of(*ae, at, *be, bt) } _ => false, } @@ -972,17 +1002,31 @@ impl ComponentDefinedType { pub(crate) fn type_size(&self) -> usize { match self { - Self::Primitive(ty) => ty.type_size(), + Self::Primitive(_) => 1, Self::Flags(_) | Self::Enum(_) => 1, Self::Record(r) => r.type_size, Self::Variant(v) => v.type_size, Self::Tuple(t) => t.type_size, Self::Union(u) => u.type_size, Self::List(ty) | Self::Option(ty) => ty.type_size(), - Self::Expected(ok, error) => ok.type_size() + error.type_size(), + Self::Result { ok, err } => { + ok.map(|ty| ty.type_size()).unwrap_or(1) + err.map(|ty| ty.type_size()).unwrap_or(1) + } } } + fn is_optional_subtype_of( + a: Option, + at: &TypeList, + b: Option, + bt: &TypeList, + ) -> bool { + match (a, b) { + (None, None) | (Some(_), None) => true, + (None, Some(_)) => false, + (Some(a), Some(b)) => ComponentValType::internal_is_subtype_of(&a, at, &b, bt), + } + } fn push_wasm_types(&self, types: &TypeList, lowered_types: &mut LoweredTypes) -> bool { match self { Self::Primitive(ty) => push_primitive_wasm_types(ty, lowered_types), @@ -991,7 +1035,7 @@ impl ComponentDefinedType { .iter() .all(|(_, ty)| ty.push_wasm_types(types, lowered_types)), Self::Variant(v) => Self::push_variant_wasm_types( - v.cases.iter().map(|(_, case)| &case.ty), + v.cases.iter().filter_map(|(_, case)| case.ty.as_ref()), types, lowered_types, ), @@ -1008,24 +1052,19 @@ impl ComponentDefinedType { Self::Option(ty) => { Self::push_variant_wasm_types([ty].into_iter(), types, lowered_types) } - Self::Expected(ok, error) => { - Self::push_variant_wasm_types([ok, error].into_iter(), types, lowered_types) + Self::Result { ok, err } => { + Self::push_variant_wasm_types(ok.iter().chain(err.iter()), types, lowered_types) } } } fn push_variant_wasm_types<'a>( - cases: impl ExactSizeIterator, + cases: impl Iterator, types: &TypeList, lowered_types: &mut LoweredTypes, ) -> bool { - let pushed = if cases.len() <= u32::max_value() as usize { - lowered_types.push(ValType::I32) - } else { - lowered_types.push(ValType::I64) - }; - - if !pushed { + // Push the discriminant + if !lowered_types.push(ValType::I32) { return false; } diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index eee8d1781f..f00184669a 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -2115,7 +2115,6 @@ impl Printer { fn print_primitive_val_type(&mut self, ty: &PrimitiveValType) { match ty { - PrimitiveValType::Unit => self.result.push_str("unit"), PrimitiveValType::Bool => self.result.push_str("bool"), PrimitiveValType::S8 => self.result.push_str("s8"), PrimitiveValType::U8 => self.result.push_str("u8"), @@ -2156,8 +2155,11 @@ impl Printer { self.result.push(' '); self.start_group("case "); self.print_str(case.name)?; - self.result.push(' '); - self.print_component_val_type(state, &case.ty)?; + + if let Some(ty) = case.ty { + self.result.push(' '); + self.print_component_val_type(state, &ty)?; + } if let Some(refines) = case.refines { self.result.push(' '); @@ -2211,17 +2213,28 @@ impl Printer { Ok(()) } - fn print_expected_type( + fn print_result_type( &mut self, state: &State, - ok: &ComponentValType, - error: &ComponentValType, + ok: Option, + err: Option, ) -> Result<()> { - self.start_group("expected "); - self.print_component_val_type(state, ok)?; - self.result.push(' '); - self.print_component_val_type(state, error)?; + self.start_group("result"); + + if let Some(ok) = ok { + self.result.push(' '); + self.print_component_val_type(state, &ok)?; + } + + if let Some(err) = err { + self.result.push(' '); + self.start_group("error "); + self.print_component_val_type(state, &err)?; + self.end_group(); + } + self.end_group(); + Ok(()) } @@ -2240,9 +2253,7 @@ impl Printer { self.print_tuple_or_union_type("union", state, tys)? } ComponentDefinedType::Option(ty) => self.print_option_type(state, ty)?, - ComponentDefinedType::Expected { ok, error } => { - self.print_expected_type(state, ok, error)? - } + ComponentDefinedType::Result { ok, err } => self.print_result_type(state, *ok, *err)?, } Ok(()) @@ -2482,14 +2493,15 @@ impl Printer { self.end_group() } - if !matches!( - ty.result, - ComponentValType::Primitive(PrimitiveValType::Unit) - ) { + for (name, ty) in ty.results.iter() { self.result.push(' '); self.start_group("result "); - self.print_component_val_type(state, &ty.result)?; - self.end_group(); + if let Some(name) = name { + self.print_str(name)?; + self.result.push(' '); + } + self.print_component_val_type(state, ty)?; + self.end_group() } self.end_group(); @@ -2913,6 +2925,10 @@ impl Printer { self.end_group(); } + // TODO: print results; there's no easy way to do so with the current + // binary component encoding. + // See: https://github.com/WebAssembly/component-model/issues/84 + self.end_group(); // start Ok(()) @@ -2976,7 +2992,7 @@ impl Printer { Ok(()) } - fn print_aliases(&mut self, states: &mut Vec, parser: AliasSectionReader) -> Result<()> { + fn print_aliases(&mut self, states: &mut [State], parser: AliasSectionReader) -> Result<()> { for alias in parser { self.newline(); self.print_alias(states, alias?, true)?; diff --git a/crates/wast/src/component/alias.rs b/crates/wast/src/component/alias.rs index 0282a4bb01..f862ddae41 100644 --- a/crates/wast/src/component/alias.rs +++ b/crates/wast/src/component/alias.rs @@ -58,7 +58,7 @@ impl<'a> CoreAlias<'a> { impl<'a> Parse<'a> for CoreAlias<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; - parser.parse::()?.0; + parser.parse::()?; let mut l = parser.lookahead1(); diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index e15f449608..668b750686 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -78,7 +78,18 @@ fn encode_type(encoder: ComponentTypeEncoder, ty: &TypeDef) { encode_defined_type(encoder.defined_type(), t); } TypeDef::Func(f) => { - encoder.function(f.params.iter().map(|p| (p.name, &p.ty)), &f.result); + let mut encoder = encoder.function(); + if f.params.len() == 1 && f.params[0].name.is_none() { + encoder.param(&f.params[0].ty); + } else { + encoder.params(f.params.iter().map(|p| (p.name.unwrap_or(""), &p.ty))); + } + + if f.results.len() == 1 && f.results[0].name.is_none() { + encoder.result(&f.results[0].ty); + } else { + encoder.results(f.results.iter().map(|r| (r.name.unwrap_or(""), &r.ty))); + } } TypeDef::Component(c) => { encoder.component(&c.into()); @@ -96,11 +107,13 @@ fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefin encoder.record(r.fields.iter().map(|f| (f.name, &f.ty))); } ComponentDefinedType::Variant(v) => { - encoder.variant( - v.cases - .iter() - .map(|c| (c.name, &c.ty, c.refines.as_ref().map(Into::into))), - ); + encoder.variant(v.cases.iter().map(|c| { + ( + c.name, + c.ty.as_ref().map(Into::into), + c.refines.as_ref().map(Into::into), + ) + })); } ComponentDefinedType::List(l) => { encoder.list(l.element.as_ref()); @@ -118,8 +131,11 @@ fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefin ComponentDefinedType::Option(o) => { encoder.option(o.element.as_ref()); } - ComponentDefinedType::Expected(e) => { - encoder.expected(e.ok.as_ref(), e.err.as_ref()); + ComponentDefinedType::Result(e) => { + encoder.result( + e.ok.as_deref().map(Into::into), + e.err.as_deref().map(Into::into), + ); } } } @@ -590,7 +606,6 @@ impl From<&ComponentValType<'_>> for wasm_encoder::ComponentValType { impl From for wasm_encoder::PrimitiveValType { fn from(p: PrimitiveValType) -> Self { match p { - PrimitiveValType::Unit => Self::Unit, PrimitiveValType::Bool => Self::Bool, PrimitiveValType::S8 => Self::S8, PrimitiveValType::U8 => Self::U8, diff --git a/crates/wast/src/component/expand.rs b/crates/wast/src/component/expand.rs index 8e1a8b1b2d..5293fde111 100644 --- a/crates/wast/src/component/expand.rs +++ b/crates/wast/src/component/expand.rs @@ -356,7 +356,10 @@ impl<'a> Expander<'a> { for param in ty.params.iter_mut() { self.expand_component_val_ty(&mut param.ty); } - self.expand_component_val_ty(&mut ty.result); + + for result in ty.results.iter_mut() { + self.expand_component_val_ty(&mut result.ty); + } } fn expand_module_ty(&mut self, ty: &mut ModuleType<'a>) { @@ -485,7 +488,9 @@ impl<'a> Expander<'a> { } ComponentDefinedType::Variant(v) => { for case in v.cases.iter_mut() { - self.expand_component_val_ty(&mut case.ty); + if let Some(ty) = &mut case.ty { + self.expand_component_val_ty(ty); + } } } ComponentDefinedType::List(t) => { @@ -504,9 +509,14 @@ impl<'a> Expander<'a> { ComponentDefinedType::Option(t) => { self.expand_component_val_ty(&mut t.element); } - ComponentDefinedType::Expected(e) => { - self.expand_component_val_ty(&mut e.ok); - self.expand_component_val_ty(&mut e.err); + ComponentDefinedType::Result(r) => { + if let Some(ty) = &mut r.ok { + self.expand_component_val_ty(ty); + } + + if let Some(ty) = &mut r.err { + self.expand_component_val_ty(ty); + } } } } @@ -811,7 +821,5 @@ impl<'a> TypeKey<'a> for Todo { None } - fn insert(&self, cx: &mut Expander<'a>, index: Index<'a>) { - drop((cx, index)); - } + fn insert(&self, _cx: &mut Expander<'a>, _index: Index<'a>) {} } diff --git a/crates/wast/src/component/func.rs b/crates/wast/src/component/func.rs index 0ed28d6cbb..c265b3cbb4 100644 --- a/crates/wast/src/component/func.rs +++ b/crates/wast/src/component/func.rs @@ -354,7 +354,7 @@ impl<'a> Parse<'a> for CanonOpt<'a> { } } -fn parse_trailing_item_ref<'a, T>(kind: T, parser: Parser<'a>) -> Result> { +fn parse_trailing_item_ref(kind: T, parser: Parser) -> Result> { Ok(CoreItemRef { kind, idx: parser.parse()?, diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index cfcb82ae90..6cfc622bee 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -430,7 +430,10 @@ impl<'a> Resolver<'a> { let mut ns = Namespace::default(); for case in v.cases.iter_mut() { let index = ns.register(case.id, "variant case")?; - self.component_val_type(&mut case.ty)?; + + if let Some(ty) = &mut case.ty { + self.component_val_type(ty)?; + } if let Some(refines) = &mut case.refines { if let Refinement::Index(span, idx) = refines { @@ -463,9 +466,14 @@ impl<'a> Resolver<'a> { ComponentDefinedType::Option(o) => { self.component_val_type(&mut *o.element)?; } - ComponentDefinedType::Expected(r) => { - self.component_val_type(&mut *r.ok)?; - self.component_val_type(&mut *r.err)?; + ComponentDefinedType::Result(r) => { + if let Some(ty) = &mut r.ok { + self.component_val_type(ty)?; + } + + if let Some(ty) = &mut r.err { + self.component_val_type(ty)?; + } } } Ok(()) @@ -500,7 +508,10 @@ impl<'a> Resolver<'a> { for param in f.params.iter_mut() { self.component_val_type(&mut param.ty)?; } - self.component_val_type(&mut f.result)?; + + for result in f.results.iter_mut() { + self.component_val_type(&mut result.ty)?; + } } TypeDef::Component(c) => { self.stack.push(ComponentState::new(field.id)); diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index 50eaf9a6c6..1024cb0445 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -2,6 +2,7 @@ use crate::component::*; use crate::core; use crate::kw; use crate::parser::Lookahead1; +use crate::parser::Peek; use crate::parser::{Parse, Parser, Result}; use crate::token::Index; use crate::token::LParen; @@ -204,7 +205,6 @@ impl<'a> Parse<'a> for TypeDef<'a> { #[allow(missing_docs)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PrimitiveValType { - Unit, Bool, S8, U8, @@ -223,10 +223,7 @@ pub enum PrimitiveValType { impl<'a> Parse<'a> for PrimitiveValType { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { - parser.parse::()?; - Ok(Self::Unit) - } else if l.peek::() { + if l.peek::() { parser.parse::()?; Ok(Self::Bool) } else if l.peek::() { @@ -271,6 +268,31 @@ impl<'a> Parse<'a> for PrimitiveValType { } } +impl Peek for PrimitiveValType { + fn peek(cursor: crate::parser::Cursor<'_>) -> bool { + matches!( + cursor.keyword(), + Some(("bool", _)) + | Some(("s8", _)) + | Some(("u8", _)) + | Some(("s16", _)) + | Some(("u16", _)) + | Some(("s32", _)) + | Some(("u32", _)) + | Some(("s64", _)) + | Some(("u64", _)) + | Some(("float32", _)) + | Some(("float64", _)) + | Some(("char", _)) + | Some(("string", _)) + ) + } + + fn display() -> &'static str { + "primitive value type" + } +} + /// A component value type. #[allow(missing_docs)] #[derive(Debug)] @@ -291,6 +313,16 @@ impl<'a> Parse<'a> for ComponentValType<'a> { } } +impl Peek for ComponentValType<'_> { + fn peek(cursor: crate::parser::Cursor<'_>) -> bool { + Index::peek(cursor) || ComponentDefinedType::peek(cursor) + } + + fn display() -> &'static str { + "component value type" + } +} + /// An inline-only component value type. /// /// This variation does not parse type indexes. @@ -326,7 +358,7 @@ pub enum ComponentDefinedType<'a> { Enum(Enum<'a>), Union(Union<'a>), Option(OptionType<'a>), - Expected(Expected<'a>), + Result(ResultType<'a>), } impl<'a> ComponentDefinedType<'a> { @@ -348,8 +380,8 @@ impl<'a> ComponentDefinedType<'a> { Ok(Self::Union(parser.parse()?)) } else if l.peek::() { Ok(Self::Option(parser.parse()?)) - } else if l.peek::() { - Ok(Self::Expected(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Result(parser.parse()?)) } else { Err(l.error()) } @@ -358,7 +390,35 @@ impl<'a> ComponentDefinedType<'a> { impl Default for ComponentDefinedType<'_> { fn default() -> Self { - Self::Primitive(PrimitiveValType::Unit) + Self::Primitive(PrimitiveValType::Bool) + } +} + +impl Peek for ComponentDefinedType<'_> { + fn peek(cursor: crate::parser::Cursor<'_>) -> bool { + if PrimitiveValType::peek(cursor) { + return true; + } + + match cursor.lparen() { + Some(cursor) => matches!( + cursor.keyword(), + Some(("record", _)) + | Some(("variant", _)) + | Some(("list", _)) + | Some(("tuple", _)) + | Some(("flags", _)) + | Some(("enum", _)) + | Some(("union", _)) + | Some(("option", _)) + | Some(("result", _)) + ), + None => false, + } + } + + fn display() -> &'static str { + "component defined type" } } @@ -427,8 +487,8 @@ pub struct VariantCase<'a> { pub id: Option>, /// The name of the case. pub name: &'a str, - /// The type of the case. - pub ty: ComponentValType<'a>, + /// The optional type of the case. + pub ty: Option>, /// The optional refinement. pub refines: Option>, } @@ -578,23 +638,32 @@ impl<'a> Parse<'a> for OptionType<'a> { } } -/// An expected type. +/// A result type. #[derive(Debug)] -pub struct Expected<'a> { +pub struct ResultType<'a> { /// The type on success. - pub ok: Box>, + pub ok: Option>>, /// The type on failure. - pub err: Box>, + pub err: Option>>, } -impl<'a> Parse<'a> for Expected<'a> { +impl<'a> Parse<'a> for ResultType<'a> { fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let ok = parser.parse()?; - let err = parser.parse()?; + parser.parse::()?; + + let ok: Option = parser.parse()?; + let err: Option = if parser.peek::() { + Some(parser.parens(|parser| { + parser.parse::()?; + parser.parse() + })?) + } else { + None + }; + Ok(Self { - ok: Box::new(ok), - err: Box::new(err), + ok: ok.map(Box::new), + err: err.map(Box::new), }) } } @@ -605,31 +674,26 @@ pub struct ComponentFunctionType<'a> { /// The parameters of a function, optionally each having an identifier for /// name resolution and a name for the custom `name` section. pub params: Box<[ComponentFunctionParam<'a>]>, - /// The result type of a function. - pub result: ComponentValType<'a>, + /// The result of a function, optionally each having an identifier for + /// name resolution and a name for the custom `name` section. + pub results: Box<[ComponentFunctionResult<'a>]>, } impl<'a> Parse<'a> for ComponentFunctionType<'a> { fn parse(parser: Parser<'a>) -> Result { - let mut params = Vec::new(); + let mut params: Vec = Vec::new(); while parser.peek2::() { params.push(parser.parens(|p| p.parse())?); } - let result = if parser.peek2::() { - // Parse a `(result ...)`. - parser.parens(|parser| { - parser.parse::()?; - parser.parse() - })? - } else { - // If the result is omitted, use `unit`. - ComponentValType::Inline(ComponentDefinedType::Primitive(PrimitiveValType::Unit)) - }; + let mut results: Vec = Vec::new(); + while parser.peek2::() { + results.push(parser.parens(|p| p.parse())?); + } Ok(Self { params: params.into(), - result, + results: results.into(), }) } } @@ -653,6 +717,25 @@ impl<'a> Parse<'a> for ComponentFunctionParam<'a> { } } +/// A result of a [`ComponentFunctionType`]. +#[derive(Debug)] +pub struct ComponentFunctionResult<'a> { + /// An optionally-specified name of this result + pub name: Option<&'a str>, + /// The type of the result. + pub ty: ComponentValType<'a>, +} + +impl<'a> Parse<'a> for ComponentFunctionResult<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + Ok(Self { + name: parser.parse()?, + ty: parser.parse()?, + }) + } +} + /// The type of an exported item from an component or instance type. #[derive(Debug)] pub struct ComponentExportType<'a> { diff --git a/crates/wast/src/component/wast.rs b/crates/wast/src/component/wast.rs index 8875dca342..f6bd890e78 100644 --- a/crates/wast/src/component/wast.rs +++ b/crates/wast/src/component/wast.rs @@ -140,7 +140,7 @@ impl Peek for WastVal<'_> { Some((kw, _)) => kw, None => return false, }; - CASES.iter().find(|(name, _)| *name == kw).is_some() + CASES.iter().any(|(name, _)| *name == kw) } fn display() -> &'static str { diff --git a/crates/wast/src/core/binary.rs b/crates/wast/src/core/binary.rs index d334add45f..917dcb9e7a 100644 --- a/crates/wast/src/core/binary.rs +++ b/crates/wast/src/core/binary.rs @@ -823,7 +823,7 @@ fn find_names<'a>( names.push((Name::Type, &ty.id, &ty.name, field)); } continue; - }, + } ModuleField::Elem(e) => (Name::Elem, &e.id, &e.name), ModuleField::Data(d) => (Name::Data, &d.id, &d.name), ModuleField::Func(f) => (Name::Func, &f.id, &f.name), diff --git a/crates/wast/src/core/resolve/names.rs b/crates/wast/src/core/resolve/names.rs index 700738b39a..e65b72a778 100644 --- a/crates/wast/src/core/resolve/names.rs +++ b/crates/wast/src/core/resolve/names.rs @@ -95,12 +95,12 @@ impl<'a> Resolver<'a> { ModuleField::Type(i) => { return self.register_type(i); - }, + } ModuleField::Rec(i) => { for ty in &i.types { self.register_type(ty)?; } - return Ok(()) + return Ok(()); } ModuleField::Elem(e) => self.elems.register(e.id, "elem")?, ModuleField::Data(d) => self.datas.register(d.id, "data")?, @@ -606,8 +606,8 @@ impl<'a, 'b> ExprResolver<'a, 'b> { self.resolver.resolve(&mut i.r#type, Ns::Type)?; } - BrOnFunc(l) | BrOnData(l) | BrOnI31(l) | BrOnArray(l) | - BrOnNonFunc(l) | BrOnNonData(l) | BrOnNonI31(l) | BrOnNonArray(l) => { + BrOnFunc(l) | BrOnData(l) | BrOnI31(l) | BrOnArray(l) | BrOnNonFunc(l) + | BrOnNonData(l) | BrOnNonI31(l) | BrOnNonArray(l) => { self.resolve_label(l)?; } @@ -619,16 +619,8 @@ impl<'a, 'b> ExprResolver<'a, 'b> { } } - RefTest(i) - | RefCast(i) - | StructNew(i) - | StructNewDefault(i) - | ArrayNew(i) - | ArrayNewDefault(i) - | ArrayGet(i) - | ArrayGetS(i) - | ArrayGetU(i) - | ArraySet(i) + RefTest(i) | RefCast(i) | StructNew(i) | StructNewDefault(i) | ArrayNew(i) + | ArrayNewDefault(i) | ArrayGet(i) | ArrayGetS(i) | ArrayGetU(i) | ArraySet(i) | ArrayLen(i) => { self.resolver.resolve(i, Ns::Type)?; } diff --git a/crates/wast/src/core/types.rs b/crates/wast/src/core/types.rs index 470937752c..f3870f5b6a 100644 --- a/crates/wast/src/core/types.rs +++ b/crates/wast/src/core/types.rs @@ -691,8 +691,7 @@ impl<'a> Type<'a> { impl<'a> Peek for Type<'a> { fn peek(cursor: Cursor<'_>) -> bool { - kw::r#type::peek(cursor) || - kw::sub::peek(cursor) + kw::r#type::peek(cursor) || kw::sub::peek(cursor) } fn display() -> &'static str { "type" @@ -708,9 +707,7 @@ impl<'a> Parse<'a> for Type<'a> { } else { None }; - return parser.parens(|parser| { - Type::parse_inner(parser, parent) - }); + return parser.parens(|parser| Type::parse_inner(parser, parent)); } Type::parse_inner(parser, None) } @@ -730,14 +727,9 @@ impl<'a> Parse<'a> for Rec<'a> { let span = parser.parse::()?.0; let mut types = Vec::new(); while parser.peek2::>() { - types.push(parser.parens(|p| { - p.parse() - })?); + types.push(parser.parens(|p| p.parse())?); } - Ok(Rec { - span, - types - }) + Ok(Rec { span, types }) } } diff --git a/crates/wast/src/lib.rs b/crates/wast/src/lib.rs index cc18652412..3d301cca56 100644 --- a/crates/wast/src/lib.rs +++ b/crates/wast/src/lib.rs @@ -485,13 +485,12 @@ pub mod kw { custom_keyword!(float32); custom_keyword!(float64); custom_keyword!(variant); - custom_keyword!(unit); custom_keyword!(flags); custom_keyword!(option); custom_keyword!(tuple); custom_keyword!(list); + custom_keyword!(error); custom_keyword!(union); - custom_keyword!(expected); custom_keyword!(canon); custom_keyword!(lift); custom_keyword!(lower); diff --git a/tests/dump/alias.wat.dump b/tests/dump/alias.wat.dump index 3998b7328c..2347259d9a 100644 --- a/tests/dump/alias.wat.dump +++ b/tests/dump/alias.wat.dump @@ -1,57 +1,58 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 08 19 | component type section + 0x8 | 08 1b | component type section 0xa | 01 | 1 count - 0xb | 42 04 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "f1", ty: Func(0) }, Type(Func(ComponentFuncType { params: [(None, Primitive(String))], result: Primitive(Unit) })), Export { name: "f2", ty: Func(1) }]) - | 00 7f 04 02 - | 66 31 01 00 - | 01 40 01 00 - | 72 7f 04 02 - | 66 32 01 01 - 0x23 | 0b 05 | component import section - 0x25 | 01 | 1 count - 0x26 | 01 69 05 00 | [instance 0] ComponentImport { name: "i", ty: Instance(0) } - 0x2a | 07 13 | component alias section - 0x2c | 03 | 3 count - 0x2d | 01 00 00 02 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "f1" } + 0xb | 42 04 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "f1", ty: Func(0) }, Type(Func(ComponentFuncType { params: Unnamed(Primitive(String)), results: Named([]) })), Export { name: "f2", ty: Func(1) }]) + | 01 00 01 00 + | 04 02 66 31 + | 01 00 01 40 + | 00 73 01 00 + | 04 02 66 32 + | 01 01 + 0x25 | 0b 05 | component import section + 0x27 | 01 | 1 count + 0x28 | 01 69 05 00 | [instance 0] ComponentImport { name: "i", ty: Instance(0) } + 0x2c | 07 13 | component alias section + 0x2e | 03 | 3 count + 0x2f | 01 00 00 02 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "f1" } | 66 31 - 0x33 | 01 00 00 02 | alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "f2" } + 0x35 | 01 00 00 02 | alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "f2" } | 66 32 - 0x39 | 01 00 00 02 | alias [func 2] InstanceExport { kind: Func, instance_index: 0, name: "f1" } + 0x3b | 01 00 00 02 | alias [func 2] InstanceExport { kind: Func, instance_index: 0, name: "f1" } | 66 31 - 0x3f | 09 05 | canonical function section - 0x41 | 01 | 1 count - 0x42 | 01 00 02 00 | [core func 0] Lower { func_index: 2, options: [] } - 0x46 | 01 2b | [core module 0] inline size - 0x48 | 00 61 73 6d | version 1 (Module) + 0x41 | 09 05 | canonical function section + 0x43 | 01 | 1 count + 0x44 | 01 00 02 00 | [core func 0] Lower { func_index: 2, options: [] } + 0x48 | 01 2b | [core module 0] inline size + 0x4a | 00 61 73 6d | version 1 (Module) | 01 00 00 00 - 0x50 | 01 04 | type section - 0x52 | 01 | 1 count - 0x53 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x56 | 03 02 | func section - 0x58 | 01 | 1 count - 0x59 | 00 | [func 0] type 0 - 0x5a | 07 06 | export section - 0x5c | 01 | 1 count - 0x5d | 02 66 33 00 | export Export { name: "f3", kind: Func, index: 0 } + 0x52 | 01 04 | type section + 0x54 | 01 | 1 count + 0x55 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) + 0x58 | 03 02 | func section + 0x5a | 01 | 1 count + 0x5b | 00 | [func 0] type 0 + 0x5c | 07 06 | export section + 0x5e | 01 | 1 count + 0x5f | 02 66 33 00 | export Export { name: "f3", kind: Func, index: 0 } | 00 - 0x62 | 0a 04 | code section - 0x64 | 01 | 1 count + 0x64 | 0a 04 | code section + 0x66 | 01 | 1 count ============== func 0 ==================== - 0x65 | 02 | size of function - 0x66 | 00 | 0 local blocks - 0x67 | 0b | End - 0x68 | 00 09 | custom section - 0x6a | 04 6e 61 6d | name: "name" + 0x67 | 02 | size of function + 0x68 | 00 | 0 local blocks + 0x69 | 0b | End + 0x6a | 00 09 | custom section + 0x6c | 04 6e 61 6d | name: "name" | 65 - 0x6f | 00 02 | module name - 0x71 | 01 6d | "m" - 0x73 | 02 04 | core instance section - 0x75 | 01 | 1 count - 0x76 | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } - 0x79 | 03 0d | core alias section - 0x7b | 02 | 2 count - 0x7c | 00 00 00 02 | core alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "f3" } + 0x71 | 00 02 | module name + 0x73 | 01 6d | "m" + 0x75 | 02 04 | core instance section + 0x77 | 01 | 1 count + 0x78 | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } + 0x7b | 03 0d | core alias section + 0x7d | 02 | 2 count + 0x7e | 00 00 00 02 | core alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "f3" } | 66 33 - 0x82 | 00 00 00 02 | core alias [func 2] InstanceExport { kind: Func, instance_index: 0, name: "f3" } + 0x84 | 00 00 00 02 | core alias [func 2] InstanceExport { kind: Func, instance_index: 0, name: "f3" } | 66 33 diff --git a/tests/dump/alias2.wat.dump b/tests/dump/alias2.wat.dump index c0347983a3..a2312c8841 100644 --- a/tests/dump/alias2.wat.dump +++ b/tests/dump/alias2.wat.dump @@ -1,179 +1,180 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 08 2a | component type section + 0x8 | 08 2c | component type section 0xa | 01 | 1 count - 0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: "1", ty: Module(0) }, Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "2", ty: Func(0) }, Export { name: "3", ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: "4", ty: Instance(1) }, Type(Component([])), Export { name: "5", ty: Component(2) }]) + 0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: "1", ty: Module(0) }, Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "2", ty: Func(0) }, Export { name: "3", ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: "4", ty: Instance(1) }, Type(Component([])), Export { name: "5", ty: Component(2) }]) | 00 04 01 31 | 00 11 00 01 - | 40 00 7f 04 - | 01 32 01 00 - | 04 01 33 02 - | 72 01 42 00 - | 04 01 34 05 - | 01 01 41 00 - | 04 01 35 04 - | 02 - 0x34 | 0b 04 | component import section - 0x36 | 01 | 1 count - 0x37 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } - 0x3a | 05 3e | [component 0] inline size - 0x3c | 00 61 73 6d | version 65546 (Component) + | 40 01 00 01 + | 00 04 01 32 + | 01 00 04 01 + | 33 02 73 01 + | 42 00 04 01 + | 34 05 01 01 + | 41 00 04 01 + | 35 04 02 + 0x36 | 0b 04 | component import section + 0x38 | 01 | 1 count + 0x39 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } + 0x3c | 05 40 | [component 0] inline size + 0x3e | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x44 | 04 03 | core type section - 0x46 | 01 | 1 count - 0x47 | 50 00 | [core type 0] Module([]) - 0x49 | 0b 06 | component import section - 0x4b | 01 | 1 count - 0x4c | 01 31 00 11 | [module 0] ComponentImport { name: "1", ty: Module(0) } + 0x46 | 04 03 | core type section + 0x48 | 01 | 1 count + 0x49 | 50 00 | [core type 0] Module([]) + 0x4b | 0b 06 | component import section + 0x4d | 01 | 1 count + 0x4e | 01 31 00 11 | [module 0] ComponentImport { name: "1", ty: Module(0) } + | 00 + 0x53 | 08 06 | component type section + 0x55 | 01 | 1 count + 0x56 | 40 01 00 01 | [type 0] Func(ComponentFuncType { params: Named([]), results: Named([]) }) | 00 - 0x51 | 08 04 | component type section - 0x53 | 01 | 1 count - 0x54 | 40 00 7f | [type 0] Func(ComponentFuncType { params: [], result: Primitive(Unit) }) - 0x57 | 0b 09 | component import section - 0x59 | 02 | 2 count - 0x5a | 01 32 01 00 | [func 0] ComponentImport { name: "2", ty: Func(0) } - 0x5e | 01 33 02 72 | [value 0] ComponentImport { name: "3", ty: Value(Primitive(String)) } - 0x62 | 08 03 | component type section - 0x64 | 01 | 1 count - 0x65 | 42 00 | [type 1] Instance([]) - 0x67 | 0b 05 | component import section - 0x69 | 01 | 1 count - 0x6a | 01 34 05 01 | [instance 0] ComponentImport { name: "4", ty: Instance(1) } - 0x6e | 08 03 | component type section - 0x70 | 01 | 1 count - 0x71 | 41 00 | [type 2] Component([]) - 0x73 | 0b 05 | component import section - 0x75 | 01 | 1 count - 0x76 | 01 35 04 02 | [component 0] ComponentImport { name: "5", ty: Component(2) } - 0x7a | 07 1b | component alias section - 0x7c | 05 | 5 count - 0x7d | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "1" } + 0x5b | 0b 09 | component import section + 0x5d | 02 | 2 count + 0x5e | 01 32 01 00 | [func 0] ComponentImport { name: "2", ty: Func(0) } + 0x62 | 01 33 02 73 | [value 0] ComponentImport { name: "3", ty: Value(Primitive(String)) } + 0x66 | 08 03 | component type section + 0x68 | 01 | 1 count + 0x69 | 42 00 | [type 1] Instance([]) + 0x6b | 0b 05 | component import section + 0x6d | 01 | 1 count + 0x6e | 01 34 05 01 | [instance 0] ComponentImport { name: "4", ty: Instance(1) } + 0x72 | 08 03 | component type section + 0x74 | 01 | 1 count + 0x75 | 41 00 | [type 2] Component([]) + 0x77 | 0b 05 | component import section + 0x79 | 01 | 1 count + 0x7a | 01 35 04 02 | [component 0] ComponentImport { name: "5", ty: Component(2) } + 0x7e | 07 1b | component alias section + 0x80 | 05 | 5 count + 0x81 | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "1" } | 01 31 - 0x83 | 01 00 00 01 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "2" } + 0x87 | 01 00 00 01 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "2" } | 32 - 0x88 | 02 00 00 01 | alias [value 0] InstanceExport { kind: Value, instance_index: 0, name: "4" } + 0x8c | 02 00 00 01 | alias [value 0] InstanceExport { kind: Value, instance_index: 0, name: "4" } | 34 - 0x8d | 05 00 00 01 | alias [instance 1] InstanceExport { kind: Instance, instance_index: 0, name: "3" } + 0x91 | 05 00 00 01 | alias [instance 1] InstanceExport { kind: Instance, instance_index: 0, name: "3" } | 33 - 0x92 | 04 00 00 01 | alias [component 1] InstanceExport { kind: Component, instance_index: 0, name: "5" } + 0x96 | 04 00 00 01 | alias [component 1] InstanceExport { kind: Component, instance_index: 0, name: "5" } | 35 - 0x97 | 06 19 | component instance section - 0x99 | 01 | 1 count - 0x9a | 00 00 05 01 | [instance 2] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "1", kind: Module, index: 0 }, ComponentInstantiationArg { name: "2", kind: Func, index: 0 }, ComponentInstantiationArg { name: "3", kind: Value, index: 0 }, ComponentInstantiationArg { name: "4", kind: Instance, index: 1 }, ComponentInstantiationArg { name: "5", kind: Component, index: 1 }] } + 0x9b | 06 19 | component instance section + 0x9d | 01 | 1 count + 0x9e | 00 00 05 01 | [instance 2] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "1", kind: Module, index: 0 }, ComponentInstantiationArg { name: "2", kind: Func, index: 0 }, ComponentInstantiationArg { name: "3", kind: Value, index: 0 }, ComponentInstantiationArg { name: "4", kind: Instance, index: 1 }, ComponentInstantiationArg { name: "5", kind: Component, index: 1 }] } | 31 00 11 00 | 01 32 01 00 | 01 33 02 00 | 01 34 05 01 | 01 35 04 01 - 0xb2 | 05 15 | [component 2] inline size - 0xb4 | 00 61 73 6d | version 65546 (Component) + 0xb6 | 05 15 | [component 2] inline size + 0xb8 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0xbc | 07 05 | component alias section - 0xbe | 01 | 1 count - 0xbf | 03 01 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } - 0xc3 | 0b 04 | component import section - 0xc5 | 01 | 1 count - 0xc6 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } - 0xc9 | 07 1b | component alias section - 0xcb | 05 | 5 count - 0xcc | 00 11 00 00 | alias [module 1] InstanceExport { kind: Module, instance_index: 0, name: "1" } + 0xc0 | 07 05 | component alias section + 0xc2 | 01 | 1 count + 0xc3 | 03 01 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } + 0xc7 | 0b 04 | component import section + 0xc9 | 01 | 1 count + 0xca | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } + 0xcd | 07 1b | component alias section + 0xcf | 05 | 5 count + 0xd0 | 00 11 00 00 | alias [module 1] InstanceExport { kind: Module, instance_index: 0, name: "1" } | 01 31 - 0xd2 | 01 00 00 01 | alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "2" } + 0xd6 | 01 00 00 01 | alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "2" } | 32 - 0xd7 | 02 00 00 01 | alias [value 1] InstanceExport { kind: Value, instance_index: 0, name: "3" } + 0xdb | 02 00 00 01 | alias [value 1] InstanceExport { kind: Value, instance_index: 0, name: "3" } | 33 - 0xdc | 05 00 00 01 | alias [instance 3] InstanceExport { kind: Instance, instance_index: 0, name: "4" } + 0xe0 | 05 00 00 01 | alias [instance 3] InstanceExport { kind: Instance, instance_index: 0, name: "4" } | 34 - 0xe1 | 04 00 00 01 | alias [component 3] InstanceExport { kind: Component, instance_index: 0, name: "5" } + 0xe5 | 04 00 00 01 | alias [component 3] InstanceExport { kind: Component, instance_index: 0, name: "5" } | 35 - 0xe6 | 06 1e | component instance section - 0xe8 | 02 | 2 count - 0xe9 | 01 05 01 31 | [instance 4] FromExports([ComponentExport { name: "1", kind: Module, index: 1 }, ComponentExport { name: "2", kind: Func, index: 1 }, ComponentExport { name: "3", kind: Value, index: 1 }, ComponentExport { name: "4", kind: Instance, index: 3 }, ComponentExport { name: "5", kind: Component, index: 3 }]) + 0xea | 06 1e | component instance section + 0xec | 02 | 2 count + 0xed | 01 05 01 31 | [instance 4] FromExports([ComponentExport { name: "1", kind: Module, index: 1 }, ComponentExport { name: "2", kind: Func, index: 1 }, ComponentExport { name: "3", kind: Value, index: 1 }, ComponentExport { name: "4", kind: Instance, index: 3 }, ComponentExport { name: "5", kind: Component, index: 3 }]) | 00 11 01 01 | 32 01 01 01 | 33 02 01 01 | 34 05 03 01 | 35 04 03 - 0x100 | 00 02 01 00 | [instance 5] Instantiate { component_index: 2, args: [ComponentInstantiationArg { name: "", kind: Instance, index: 4 }] } + 0x104 | 00 02 01 00 | [instance 5] Instantiate { component_index: 2, args: [ComponentInstantiationArg { name: "", kind: Instance, index: 4 }] } | 05 04 - 0x106 | 01 48 | [core module 2] inline size - 0x108 | 00 61 73 6d | version 1 (Module) + 0x10a | 01 48 | [core module 2] inline size + 0x10c | 00 61 73 6d | version 1 (Module) | 01 00 00 00 - 0x110 | 01 04 | type section - 0x112 | 01 | 1 count - 0x113 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x116 | 03 02 | func section - 0x118 | 01 | 1 count - 0x119 | 00 | [func 0] type 0 - 0x11a | 04 04 | table section + 0x114 | 01 04 | type section + 0x116 | 01 | 1 count + 0x117 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) + 0x11a | 03 02 | func section 0x11c | 01 | 1 count - 0x11d | 70 00 01 | [table 0] TableType { element_type: FuncRef, initial: 1, maximum: None } - 0x120 | 05 03 | memory section - 0x122 | 01 | 1 count - 0x123 | 00 01 | [memory 0] MemoryType { memory64: false, shared: false, initial: 1, maximum: None } - 0x125 | 06 04 | global section - 0x127 | 01 | 1 count - 0x128 | 7f 00 | [global 0] GlobalType { content_type: I32, mutable: false } - 0x12a | 0b | End - 0x12b | 07 11 | export section - 0x12d | 04 | 4 count - 0x12e | 01 31 00 00 | export Export { name: "1", kind: Func, index: 0 } - 0x132 | 01 32 02 00 | export Export { name: "2", kind: Memory, index: 0 } - 0x136 | 01 33 03 00 | export Export { name: "3", kind: Global, index: 0 } - 0x13a | 01 34 01 00 | export Export { name: "4", kind: Table, index: 0 } - 0x13e | 0a 04 | code section - 0x140 | 01 | 1 count + 0x11d | 00 | [func 0] type 0 + 0x11e | 04 04 | table section + 0x120 | 01 | 1 count + 0x121 | 70 00 01 | [table 0] TableType { element_type: FuncRef, initial: 1, maximum: None } + 0x124 | 05 03 | memory section + 0x126 | 01 | 1 count + 0x127 | 00 01 | [memory 0] MemoryType { memory64: false, shared: false, initial: 1, maximum: None } + 0x129 | 06 04 | global section + 0x12b | 01 | 1 count + 0x12c | 7f 00 | [global 0] GlobalType { content_type: I32, mutable: false } + 0x12e | 0b | End + 0x12f | 07 11 | export section + 0x131 | 04 | 4 count + 0x132 | 01 31 00 00 | export Export { name: "1", kind: Func, index: 0 } + 0x136 | 01 32 02 00 | export Export { name: "2", kind: Memory, index: 0 } + 0x13a | 01 33 03 00 | export Export { name: "3", kind: Global, index: 0 } + 0x13e | 01 34 01 00 | export Export { name: "4", kind: Table, index: 0 } + 0x142 | 0a 04 | code section + 0x144 | 01 | 1 count ============== func 0 ==================== - 0x141 | 02 | size of function - 0x142 | 00 | 0 local blocks - 0x143 | 0b | End - 0x144 | 00 0a | custom section - 0x146 | 04 6e 61 6d | name: "name" + 0x145 | 02 | size of function + 0x146 | 00 | 0 local blocks + 0x147 | 0b | End + 0x148 | 00 0a | custom section + 0x14a | 04 6e 61 6d | name: "name" | 65 - 0x14b | 00 03 | module name - 0x14d | 02 6d 31 | "m1" - 0x150 | 01 35 | [core module 3] inline size - 0x152 | 00 61 73 6d | version 1 (Module) + 0x14f | 00 03 | module name + 0x151 | 02 6d 31 | "m1" + 0x154 | 01 35 | [core module 3] inline size + 0x156 | 00 61 73 6d | version 1 (Module) | 01 00 00 00 - 0x15a | 01 04 | type section - 0x15c | 01 | 1 count - 0x15d | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x160 | 02 19 | import section - 0x162 | 04 | 4 count - 0x163 | 00 01 31 00 | import [func 0] Import { module: "", name: "1", ty: Func(0) } + 0x15e | 01 04 | type section + 0x160 | 01 | 1 count + 0x161 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) + 0x164 | 02 19 | import section + 0x166 | 04 | 4 count + 0x167 | 00 01 31 00 | import [func 0] Import { module: "", name: "1", ty: Func(0) } | 00 - 0x168 | 00 01 32 02 | import [memory 0] Import { module: "", name: "2", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) } + 0x16c | 00 01 32 02 | import [memory 0] Import { module: "", name: "2", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) } | 00 01 - 0x16e | 00 01 33 03 | import [global 0] Import { module: "", name: "3", ty: Global(GlobalType { content_type: I32, mutable: false }) } + 0x172 | 00 01 33 03 | import [global 0] Import { module: "", name: "3", ty: Global(GlobalType { content_type: I32, mutable: false }) } | 7f 00 - 0x174 | 00 01 34 01 | import [table 0] Import { module: "", name: "4", ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) } + 0x178 | 00 01 34 01 | import [table 0] Import { module: "", name: "4", ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) } | 70 00 01 - 0x17b | 00 0a | custom section - 0x17d | 04 6e 61 6d | name: "name" + 0x17f | 00 0a | custom section + 0x181 | 04 6e 61 6d | name: "name" | 65 - 0x182 | 00 03 | module name - 0x184 | 02 6d 32 | "m2" - 0x187 | 02 0a | core instance section - 0x189 | 02 | 2 count - 0x18a | 00 02 00 | [core instance 0] Instantiate { module_index: 2, args: [] } - 0x18d | 00 03 01 00 | [core instance 1] Instantiate { module_index: 3, args: [InstantiationArg { name: "", kind: Instance, index: 0 }] } + 0x186 | 00 03 | module name + 0x188 | 02 6d 32 | "m2" + 0x18b | 02 0a | core instance section + 0x18d | 02 | 2 count + 0x18e | 00 02 00 | [core instance 0] Instantiate { module_index: 2, args: [] } + 0x191 | 00 03 01 00 | [core instance 1] Instantiate { module_index: 3, args: [InstantiationArg { name: "", kind: Instance, index: 0 }] } | 12 00 - 0x193 | 03 15 | core alias section - 0x195 | 04 | 4 count - 0x196 | 00 00 00 01 | core alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "1" } + 0x197 | 03 15 | core alias section + 0x199 | 04 | 4 count + 0x19a | 00 00 00 01 | core alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "1" } | 31 - 0x19b | 02 00 00 01 | core alias [memory 0] InstanceExport { kind: Memory, instance_index: 0, name: "2" } + 0x19f | 02 00 00 01 | core alias [memory 0] InstanceExport { kind: Memory, instance_index: 0, name: "2" } | 32 - 0x1a0 | 03 00 00 01 | core alias [global 0] InstanceExport { kind: Global, instance_index: 0, name: "3" } + 0x1a4 | 03 00 00 01 | core alias [global 0] InstanceExport { kind: Global, instance_index: 0, name: "3" } | 33 - 0x1a5 | 01 00 00 01 | core alias [table 0] InstanceExport { kind: Table, instance_index: 0, name: "4" } + 0x1a9 | 01 00 00 01 | core alias [table 0] InstanceExport { kind: Table, instance_index: 0, name: "4" } | 34 - 0x1aa | 02 19 | core instance section - 0x1ac | 02 | 2 count - 0x1ad | 01 04 01 31 | [core instance 2] FromExports([Export { name: "1", kind: Func, index: 0 }, Export { name: "2", kind: Memory, index: 0 }, Export { name: "3", kind: Global, index: 0 }, Export { name: "4", kind: Table, index: 0 }]) + 0x1ae | 02 19 | core instance section + 0x1b0 | 02 | 2 count + 0x1b1 | 01 04 01 31 | [core instance 2] FromExports([Export { name: "1", kind: Func, index: 0 }, Export { name: "2", kind: Memory, index: 0 }, Export { name: "3", kind: Global, index: 0 }, Export { name: "4", kind: Table, index: 0 }]) | 00 00 01 32 | 02 00 01 33 | 03 00 01 34 | 01 00 - 0x1bf | 00 03 01 00 | [core instance 3] Instantiate { module_index: 3, args: [InstantiationArg { name: "", kind: Instance, index: 2 }] } + 0x1c3 | 00 03 01 00 | [core instance 3] Instantiate { module_index: 3, args: [InstantiationArg { name: "", kind: Instance, index: 2 }] } | 12 02 diff --git a/tests/dump/bundled.wat.dump b/tests/dump/bundled.wat.dump index a3ae5f6d61..19689d94d7 100644 --- a/tests/dump/bundled.wat.dump +++ b/tests/dump/bundled.wat.dump @@ -2,13 +2,13 @@ | 0a 00 01 00 0x8 | 08 26 | component type section 0xa | 01 | 1 count - 0xb | 42 06 01 6f | [type 0] Instance([Type(Defined(List(Primitive(U8)))), Type(Func(ComponentFuncType { params: [(None, Primitive(U32))], result: Type(0) })), Export { name: "read", ty: Func(1) }, Type(Defined(List(Primitive(U8)))), Type(Func(ComponentFuncType { params: [(None, Type(2))], result: Primitive(U32) })), Export { name: "write", ty: Func(3) }]) - | 7c 01 40 01 - | 00 78 00 04 + 0xb | 42 06 01 70 | [type 0] Instance([Type(Defined(List(Primitive(U8)))), Type(Func(ComponentFuncType { params: Unnamed(Primitive(U32)), results: Unnamed(Type(0)) })), Export { name: "read", ty: Func(1) }, Type(Defined(List(Primitive(U8)))), Type(Func(ComponentFuncType { params: Unnamed(Type(2)), results: Unnamed(Primitive(U32)) })), Export { name: "write", ty: Func(3) }]) + | 7d 01 40 00 + | 79 00 00 04 | 04 72 65 61 | 64 01 01 01 - | 6f 7c 01 40 - | 01 00 02 78 + | 70 7d 01 40 + | 00 02 00 79 | 04 05 77 72 | 69 74 65 01 | 03 @@ -168,24 +168,25 @@ | 77 61 73 69 | 5f 66 69 6c | 65 12 02 - 0x1a3 | 08 04 | component type section + 0x1a3 | 08 06 | component type section 0x1a5 | 01 | 1 count - 0x1a6 | 40 00 7f | [type 1] Func(ComponentFuncType { params: [], result: Primitive(Unit) }) - 0x1a9 | 03 1b | core alias section - 0x1ab | 03 | 3 count - 0x1ac | 00 00 03 04 | core alias [func 2] InstanceExport { kind: Func, instance_index: 3, name: "play" } + 0x1a6 | 40 01 00 01 | [type 1] Func(ComponentFuncType { params: Named([]), results: Named([]) }) + | 00 + 0x1ab | 03 1b | core alias section + 0x1ad | 03 | 3 count + 0x1ae | 00 00 03 04 | core alias [func 2] InstanceExport { kind: Func, instance_index: 3, name: "play" } | 70 6c 61 79 - 0x1b4 | 02 00 00 03 | core alias [memory 1] InstanceExport { kind: Memory, instance_index: 0, name: "mem" } + 0x1b6 | 02 00 00 03 | core alias [memory 1] InstanceExport { kind: Memory, instance_index: 0, name: "mem" } | 6d 65 6d - 0x1bb | 00 00 00 07 | core alias [func 3] InstanceExport { kind: Func, instance_index: 0, name: "realloc" } + 0x1bd | 00 00 00 07 | core alias [func 3] InstanceExport { kind: Func, instance_index: 0, name: "realloc" } | 72 65 61 6c | 6c 6f 63 - 0x1c6 | 09 0a | canonical function section - 0x1c8 | 01 | 1 count - 0x1c9 | 00 00 02 02 | [func 1] Lift { core_func_index: 2, type_index: 1, options: [Memory(1), Realloc(3)] } + 0x1c8 | 09 0a | canonical function section + 0x1ca | 01 | 1 count + 0x1cb | 00 00 02 02 | [func 1] Lift { core_func_index: 2, type_index: 1, options: [Memory(1), Realloc(3)] } | 03 01 04 03 | 01 - 0x1d2 | 0c 08 | component export section - 0x1d4 | 01 | 1 count - 0x1d5 | 04 77 6f 72 | export ComponentExport { name: "work", kind: Func, index: 1 } + 0x1d4 | 0c 08 | component export section + 0x1d6 | 01 | 1 count + 0x1d7 | 04 77 6f 72 | export ComponentExport { name: "work", kind: Func, index: 1 } | 6b 01 01 diff --git a/tests/dump/component-inline-type.wat.dump b/tests/dump/component-inline-type.wat.dump index f2d6ee74c8..43ae33546d 100644 --- a/tests/dump/component-inline-type.wat.dump +++ b/tests/dump/component-inline-type.wat.dump @@ -18,9 +18,10 @@ 0x24 | 0b 04 | component import section 0x26 | 01 | 1 count 0x27 | 00 05 01 | [instance 0] ComponentImport { name: "", ty: Instance(1) } - 0x2a | 08 04 | component type section + 0x2a | 08 06 | component type section 0x2c | 01 | 1 count - 0x2d | 40 00 7f | [type 2] Func(ComponentFuncType { params: [], result: Primitive(Unit) }) - 0x30 | 0b 04 | component import section - 0x32 | 01 | 1 count - 0x33 | 00 01 02 | [func 0] ComponentImport { name: "", ty: Func(2) } + 0x2d | 40 01 00 01 | [type 2] Func(ComponentFuncType { params: Named([]), results: Named([]) }) + | 00 + 0x32 | 0b 04 | component import section + 0x34 | 01 | 1 count + 0x35 | 00 01 02 | [func 0] ComponentImport { name: "", ty: Func(2) } diff --git a/tests/dump/component-instance-type.wat.dump b/tests/dump/component-instance-type.wat.dump index 0cc0bab9b4..4bc19b8715 100644 --- a/tests/dump/component-instance-type.wat.dump +++ b/tests/dump/component-instance-type.wat.dump @@ -1,11 +1,12 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 08 23 | component type section + 0x8 | 08 27 | component type section 0xa | 01 | 1 count - 0xb | 42 03 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Type(Component([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Alias(Outer { kind: Type, count: 1, index: 0 }), Import(ComponentImport { name: "1", ty: Func(0) }), Export { name: "1", ty: Func(1) }])), Export { name: "c5", ty: Component(1) }]) - | 00 7f 01 41 - | 04 01 40 00 - | 7f 02 03 01 + 0xb | 42 03 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Type(Component([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Alias(Outer { kind: Type, count: 1, index: 0 }), Import(ComponentImport { name: "1", ty: Func(0) }), Export { name: "1", ty: Func(1) }])), Export { name: "c5", ty: Component(1) }]) + | 01 00 01 00 + | 01 41 04 01 + | 40 01 00 01 + | 00 02 03 01 | 01 00 03 01 | 31 01 00 04 | 01 31 01 01 diff --git a/tests/dump/component-linking.wat.dump b/tests/dump/component-linking.wat.dump index 52fc4a9ff9..6031bb77f2 100644 --- a/tests/dump/component-linking.wat.dump +++ b/tests/dump/component-linking.wat.dump @@ -1,65 +1,66 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 08 2a | component type section + 0x8 | 08 2c | component type section 0xa | 01 | 1 count - 0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: "1", ty: Module(0) }, Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "2", ty: Func(0) }, Export { name: "3", ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: "4", ty: Instance(1) }, Type(Component([])), Export { name: "5", ty: Component(2) }]) + 0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: "1", ty: Module(0) }, Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "2", ty: Func(0) }, Export { name: "3", ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: "4", ty: Instance(1) }, Type(Component([])), Export { name: "5", ty: Component(2) }]) | 00 04 01 31 | 00 11 00 01 - | 40 00 7f 04 - | 01 32 01 00 - | 04 01 33 02 - | 72 01 42 00 - | 04 01 34 05 - | 01 01 41 00 - | 04 01 35 04 - | 02 - 0x34 | 0b 04 | component import section - 0x36 | 01 | 1 count - 0x37 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } - 0x3a | 05 3e | [component 0] inline size - 0x3c | 00 61 73 6d | version 65546 (Component) + | 40 01 00 01 + | 00 04 01 32 + | 01 00 04 01 + | 33 02 73 01 + | 42 00 04 01 + | 34 05 01 01 + | 41 00 04 01 + | 35 04 02 + 0x36 | 0b 04 | component import section + 0x38 | 01 | 1 count + 0x39 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } + 0x3c | 05 40 | [component 0] inline size + 0x3e | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x44 | 04 03 | core type section - 0x46 | 01 | 1 count - 0x47 | 50 00 | [core type 0] Module([]) - 0x49 | 0b 06 | component import section - 0x4b | 01 | 1 count - 0x4c | 01 31 00 11 | [module 0] ComponentImport { name: "1", ty: Module(0) } + 0x46 | 04 03 | core type section + 0x48 | 01 | 1 count + 0x49 | 50 00 | [core type 0] Module([]) + 0x4b | 0b 06 | component import section + 0x4d | 01 | 1 count + 0x4e | 01 31 00 11 | [module 0] ComponentImport { name: "1", ty: Module(0) } + | 00 + 0x53 | 08 06 | component type section + 0x55 | 01 | 1 count + 0x56 | 40 01 00 01 | [type 0] Func(ComponentFuncType { params: Named([]), results: Named([]) }) | 00 - 0x51 | 08 04 | component type section - 0x53 | 01 | 1 count - 0x54 | 40 00 7f | [type 0] Func(ComponentFuncType { params: [], result: Primitive(Unit) }) - 0x57 | 0b 09 | component import section - 0x59 | 02 | 2 count - 0x5a | 01 32 01 00 | [func 0] ComponentImport { name: "2", ty: Func(0) } - 0x5e | 01 33 02 72 | [value 0] ComponentImport { name: "3", ty: Value(Primitive(String)) } - 0x62 | 08 03 | component type section - 0x64 | 01 | 1 count - 0x65 | 42 00 | [type 1] Instance([]) - 0x67 | 0b 05 | component import section - 0x69 | 01 | 1 count - 0x6a | 01 34 05 01 | [instance 0] ComponentImport { name: "4", ty: Instance(1) } - 0x6e | 08 03 | component type section - 0x70 | 01 | 1 count - 0x71 | 41 00 | [type 2] Component([]) - 0x73 | 0b 05 | component import section - 0x75 | 01 | 1 count - 0x76 | 01 35 04 02 | [component 0] ComponentImport { name: "5", ty: Component(2) } - 0x7a | 07 1b | component alias section - 0x7c | 05 | 5 count - 0x7d | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "1" } + 0x5b | 0b 09 | component import section + 0x5d | 02 | 2 count + 0x5e | 01 32 01 00 | [func 0] ComponentImport { name: "2", ty: Func(0) } + 0x62 | 01 33 02 73 | [value 0] ComponentImport { name: "3", ty: Value(Primitive(String)) } + 0x66 | 08 03 | component type section + 0x68 | 01 | 1 count + 0x69 | 42 00 | [type 1] Instance([]) + 0x6b | 0b 05 | component import section + 0x6d | 01 | 1 count + 0x6e | 01 34 05 01 | [instance 0] ComponentImport { name: "4", ty: Instance(1) } + 0x72 | 08 03 | component type section + 0x74 | 01 | 1 count + 0x75 | 41 00 | [type 2] Component([]) + 0x77 | 0b 05 | component import section + 0x79 | 01 | 1 count + 0x7a | 01 35 04 02 | [component 0] ComponentImport { name: "5", ty: Component(2) } + 0x7e | 07 1b | component alias section + 0x80 | 05 | 5 count + 0x81 | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "1" } | 01 31 - 0x83 | 01 00 00 01 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "2" } + 0x87 | 01 00 00 01 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "2" } | 32 - 0x88 | 02 00 00 01 | alias [value 0] InstanceExport { kind: Value, instance_index: 0, name: "4" } + 0x8c | 02 00 00 01 | alias [value 0] InstanceExport { kind: Value, instance_index: 0, name: "4" } | 34 - 0x8d | 05 00 00 01 | alias [instance 1] InstanceExport { kind: Instance, instance_index: 0, name: "3" } + 0x91 | 05 00 00 01 | alias [instance 1] InstanceExport { kind: Instance, instance_index: 0, name: "3" } | 33 - 0x92 | 04 00 00 01 | alias [component 1] InstanceExport { kind: Component, instance_index: 0, name: "5" } + 0x96 | 04 00 00 01 | alias [component 1] InstanceExport { kind: Component, instance_index: 0, name: "5" } | 35 - 0x97 | 06 19 | component instance section - 0x99 | 01 | 1 count - 0x9a | 00 00 05 01 | [instance 2] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "1", kind: Module, index: 0 }, ComponentInstantiationArg { name: "2", kind: Func, index: 0 }, ComponentInstantiationArg { name: "3", kind: Value, index: 0 }, ComponentInstantiationArg { name: "4", kind: Instance, index: 1 }, ComponentInstantiationArg { name: "5", kind: Component, index: 1 }] } + 0x9b | 06 19 | component instance section + 0x9d | 01 | 1 count + 0x9e | 00 00 05 01 | [instance 2] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "1", kind: Module, index: 0 }, ComponentInstantiationArg { name: "2", kind: Func, index: 0 }, ComponentInstantiationArg { name: "3", kind: Value, index: 0 }, ComponentInstantiationArg { name: "4", kind: Instance, index: 1 }, ComponentInstantiationArg { name: "5", kind: Component, index: 1 }] } | 31 00 11 00 | 01 32 01 00 | 01 33 02 00 diff --git a/tests/dump/component-outer-alias.wat.dump b/tests/dump/component-outer-alias.wat.dump index 451fd0b9d3..a8e28ce1e6 100644 --- a/tests/dump/component-outer-alias.wat.dump +++ b/tests/dump/component-outer-alias.wat.dump @@ -1,40 +1,46 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 08 0d | component type section + 0x8 | 08 0f | component type section 0xa | 02 | 2 count - 0xb | 72 | [type 0] Defined(Primitive(String)) - 0xc | 41 02 02 03 | [type 1] Component([Alias(Outer { kind: Type, count: 1, index: 0 }), Type(Func(ComponentFuncType { params: [], result: Type(0) }))]) + 0xb | 73 | [type 0] Defined(Primitive(String)) + 0xc | 41 02 02 03 | [type 1] Component([Alias(Outer { kind: Type, count: 1, index: 0 }), Type(Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }))]) | 01 01 00 01 - | 40 00 00 - 0x17 | 05 15 | [component 0] inline size - 0x19 | 00 61 73 6d | version 65546 (Component) + | 40 01 00 00 + | 00 + 0x19 | 05 17 | [component 0] inline size + 0x1b | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x21 | 07 05 | component alias section - 0x23 | 01 | 1 count - 0x24 | 03 01 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } - 0x28 | 08 04 | component type section - 0x2a | 01 | 1 count - 0x2b | 40 00 00 | [type 1] Func(ComponentFuncType { params: [], result: Type(0) }) - 0x2e | 05 18 | [component 1] inline size - 0x30 | 00 61 73 6d | version 65546 (Component) + 0x23 | 07 05 | component alias section + 0x25 | 01 | 1 count + 0x26 | 03 01 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } + 0x2a | 08 06 | component type section + 0x2c | 01 | 1 count + 0x2d | 40 01 00 00 | [type 1] Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }) + | 00 + 0x32 | 05 1c | [component 1] inline size + 0x34 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x38 | 07 05 | component alias section - 0x3a | 01 | 1 count - 0x3b | 03 01 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } - 0x3f | 08 07 | component type section - 0x41 | 02 | 2 count - 0x42 | 40 00 00 | [type 1] Func(ComponentFuncType { params: [], result: Type(0) }) - 0x45 | 40 00 00 | [type 2] Func(ComponentFuncType { params: [], result: Type(0) }) - 0x48 | 08 02 | component type section - 0x4a | 01 | 1 count - 0x4b | 7c | [type 2] Defined(Primitive(U8)) - 0x4c | 05 18 | [component 2] inline size - 0x4e | 00 61 73 6d | version 65546 (Component) + 0x3c | 07 05 | component alias section + 0x3e | 01 | 1 count + 0x3f | 03 01 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } + 0x43 | 08 0b | component type section + 0x45 | 02 | 2 count + 0x46 | 40 01 00 00 | [type 1] Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }) + | 00 + 0x4b | 40 01 00 00 | [type 2] Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }) + | 00 + 0x50 | 08 02 | component type section + 0x52 | 01 | 1 count + 0x53 | 7d | [type 2] Defined(Primitive(U8)) + 0x54 | 05 1c | [component 2] inline size + 0x56 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x56 | 07 05 | component alias section - 0x58 | 01 | 1 count - 0x59 | 03 01 01 02 | alias [type 0] Outer { kind: Type, count: 1, index: 2 } - 0x5d | 08 07 | component type section - 0x5f | 02 | 2 count - 0x60 | 40 00 00 | [type 1] Func(ComponentFuncType { params: [], result: Type(0) }) - 0x63 | 40 00 00 | [type 2] Func(ComponentFuncType { params: [], result: Type(0) }) + 0x5e | 07 05 | component alias section + 0x60 | 01 | 1 count + 0x61 | 03 01 01 02 | alias [type 0] Outer { kind: Type, count: 1, index: 2 } + 0x65 | 08 0b | component type section + 0x67 | 02 | 2 count + 0x68 | 40 01 00 00 | [type 1] Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }) + | 00 + 0x6d | 40 01 00 00 | [type 2] Func(ComponentFuncType { params: Named([]), results: Unnamed(Type(0)) }) + | 00 diff --git a/tests/dump/instance-expand.wat.dump b/tests/dump/instance-expand.wat.dump index 185864fd1a..6065d09f20 100644 --- a/tests/dump/instance-expand.wat.dump +++ b/tests/dump/instance-expand.wat.dump @@ -1,10 +1,10 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 08 0b | component type section + 0x8 | 08 0d | component type section 0xa | 01 | 1 count - 0xb | 42 02 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "", ty: Func(0) }]) - | 00 7f 04 00 - | 01 00 - 0x15 | 0b 04 | component import section - 0x17 | 01 | 1 count - 0x18 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } + 0xb | 42 02 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "", ty: Func(0) }]) + | 01 00 01 00 + | 04 00 01 00 + 0x17 | 0b 04 | component import section + 0x19 | 01 | 1 count + 0x1a | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } diff --git a/tests/dump/instance-type.wat.dump b/tests/dump/instance-type.wat.dump index b028e2d256..82b121c746 100644 --- a/tests/dump/instance-type.wat.dump +++ b/tests/dump/instance-type.wat.dump @@ -1,10 +1,10 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 08 14 | component type section + 0x8 | 08 16 | component type section 0xa | 02 | 2 count - 0xb | 42 02 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "", ty: Func(0) }]) - | 00 7f 04 00 - | 01 00 - 0x15 | 42 02 01 42 | [type 1] Instance([Type(Instance([])), Export { name: "", ty: Instance(0) }]) + 0xb | 42 02 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "", ty: Func(0) }]) + | 01 00 01 00 + | 04 00 01 00 + 0x17 | 42 02 01 42 | [type 1] Instance([Type(Instance([])), Export { name: "", ty: Instance(0) }]) | 00 04 00 05 | 00 diff --git a/tests/dump/instantiate.wat.dump b/tests/dump/instantiate.wat.dump index 068f3012d5..ed6823f7c6 100644 --- a/tests/dump/instantiate.wat.dump +++ b/tests/dump/instantiate.wat.dump @@ -6,13 +6,14 @@ 0xd | 0b 05 | component import section 0xf | 01 | 1 count 0x10 | 01 61 04 00 | [component 0] ComponentImport { name: "a", ty: Component(0) } - 0x14 | 08 04 | component type section + 0x14 | 08 06 | component type section 0x16 | 01 | 1 count - 0x17 | 40 00 7f | [type 1] Func(ComponentFuncType { params: [], result: Primitive(Unit) }) - 0x1a | 0b 05 | component import section - 0x1c | 01 | 1 count - 0x1d | 01 66 01 01 | [func 0] ComponentImport { name: "f", ty: Func(1) } - 0x21 | 06 08 | component instance section - 0x23 | 01 | 1 count - 0x24 | 00 00 01 01 | [instance 0] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "a", kind: Func, index: 0 }] } + 0x17 | 40 01 00 01 | [type 1] Func(ComponentFuncType { params: Named([]), results: Named([]) }) + | 00 + 0x1c | 0b 05 | component import section + 0x1e | 01 | 1 count + 0x1f | 01 66 01 01 | [func 0] ComponentImport { name: "f", ty: Func(1) } + 0x23 | 06 08 | component instance section + 0x25 | 01 | 1 count + 0x26 | 00 00 01 01 | [instance 0] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "a", kind: Func, index: 0 }] } | 61 01 00 diff --git a/tests/dump/instantiate2.wat.dump b/tests/dump/instantiate2.wat.dump index 56d3e6ffbf..539ab29699 100644 --- a/tests/dump/instantiate2.wat.dump +++ b/tests/dump/instantiate2.wat.dump @@ -1,13 +1,13 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 08 0b | component type section + 0x8 | 08 0d | component type section 0xa | 01 | 1 count - 0xb | 41 02 01 40 | [type 0] Component([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Import(ComponentImport { name: "", ty: Func(0) })]) - | 00 7f 03 00 - | 01 00 - 0x15 | 0b 04 | component import section - 0x17 | 01 | 1 count - 0x18 | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } - 0x1b | 06 04 | component instance section - 0x1d | 01 | 1 count - 0x1e | 00 00 00 | [instance 0] Instantiate { component_index: 0, args: [] } + 0xb | 41 02 01 40 | [type 0] Component([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Import(ComponentImport { name: "", ty: Func(0) })]) + | 01 00 01 00 + | 03 00 01 00 + 0x17 | 0b 04 | component import section + 0x19 | 01 | 1 count + 0x1a | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } + 0x1d | 06 04 | component instance section + 0x1f | 01 | 1 count + 0x20 | 00 00 00 | [instance 0] Instantiate { component_index: 0, args: [] } diff --git a/tests/dump/nested-component.wat.dump b/tests/dump/nested-component.wat.dump index fea5779333..1699c142e7 100644 --- a/tests/dump/nested-component.wat.dump +++ b/tests/dump/nested-component.wat.dump @@ -21,7 +21,7 @@ 0x3b | 05 08 | [component 0] inline size 0x3d | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x45 | 05 4e | [component 5] inline size + 0x45 | 05 50 | [component 5] inline size 0x47 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 0x4f | 01 13 | [core module 0] inline size @@ -34,8 +34,8 @@ 0x62 | 01 6d | "m" 0x64 | 08 06 | component type section 0x66 | 01 | 1 count - 0x67 | 40 01 00 72 | [type 0] Func(ComponentFuncType { params: [(None, Primitive(String))], result: Primitive(Unit) }) - | 7f + 0x67 | 40 00 73 01 | [type 0] Func(ComponentFuncType { params: Unnamed(Primitive(String)), results: Named([]) }) + | 00 0x6c | 0b 04 | component import section 0x6e | 01 | 1 count 0x6f | 00 01 00 | [func 0] ComponentImport { name: "", ty: Func(0) } @@ -43,17 +43,18 @@ 0x74 | 01 | 1 count 0x75 | 01 61 00 11 | export ComponentExport { name: "a", kind: Module, index: 0 } | 00 - 0x7a | 08 0c | component type section + 0x7a | 08 0e | component type section 0x7c | 01 | 1 count - 0x7d | 42 02 01 40 | [type 1] Instance([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "b", ty: Func(0) }]) - | 00 7f 04 01 - | 62 01 00 - 0x88 | 0b 04 | component import section - 0x8a | 01 | 1 count - 0x8b | 00 05 01 | [instance 0] ComponentImport { name: "", ty: Instance(1) } - 0x8e | 0c 05 | component export section - 0x90 | 01 | 1 count - 0x91 | 01 62 05 00 | export ComponentExport { name: "b", kind: Instance, index: 0 } - 0x95 | 0c 05 | component export section - 0x97 | 01 | 1 count - 0x98 | 01 78 04 03 | export ComponentExport { name: "x", kind: Component, index: 3 } + 0x7d | 42 02 01 40 | [type 1] Instance([Type(Func(ComponentFuncType { params: Named([]), results: Named([]) })), Export { name: "b", ty: Func(0) }]) + | 01 00 01 00 + | 04 01 62 01 + | 00 + 0x8a | 0b 04 | component import section + 0x8c | 01 | 1 count + 0x8d | 00 05 01 | [instance 0] ComponentImport { name: "", ty: Instance(1) } + 0x90 | 0c 05 | component export section + 0x92 | 01 | 1 count + 0x93 | 01 62 05 00 | export ComponentExport { name: "b", kind: Instance, index: 0 } + 0x97 | 0c 05 | component export section + 0x99 | 01 | 1 count + 0x9a | 01 78 04 03 | export ComponentExport { name: "x", kind: Component, index: 3 } diff --git a/tests/local/component-model/definedtypes.wast b/tests/local/component-model/definedtypes.wast index 0ce5bb2d13..0f6e1f3984 100644 --- a/tests/local/component-model/definedtypes.wast +++ b/tests/local/component-model/definedtypes.wast @@ -1,5 +1,4 @@ (component $C - (type $A0 unit) (type $A1 bool) (type $A2 u8) (type $A3 s8) @@ -15,20 +14,19 @@ (type $A13 string) (type $A14a (record)) - (type $A14b (record (field "x" unit))) - (type $A14c (record (field "x" $A0))) + (type $A14b (record (field "x" (tuple)))) + (type $A14c (record (field "x" $A1))) - (type $A15a (variant (case "x" unit))) + (type $A15a (variant (case "x"))) (type $A15b (variant (case "x" $A1))) - (type $A15c (variant (case $x "x" unit) (case $y "y" string (refines $x)) (case "z" string (refines $y)))) - (type $A15d (variant (case "x" unit) (case "y" string (refines 0)) (case "z" string (refines 1)))) + (type $A15c (variant (case $x "x") (case $y "y" string (refines $x)) (case "z" string (refines $y)))) + (type $A15d (variant (case "x") (case "y" string (refines 0)) (case "z" string (refines 1)))) - (type $A16a (list unit)) + (type $A16a (list (tuple))) (type $A16b (list $A3)) (type $A17a (tuple)) - (type $A17b (tuple unit)) - (type $A17c (tuple $A4)) + (type $A17b (tuple $A4)) (type $A18a (flags)) (type $A18b (flags "x")) @@ -37,16 +35,15 @@ (type $A19b (enum "x")) (type $A20a (union)) - (type $A20b (union unit)) - (type $A20c (union $A5)) + (type $A20b (union $A5)) - (type $A21a (option unit)) + (type $A21a (option (tuple))) (type $A21b (option $A6)) - (type $A22a (expected unit unit)) - (type $A22b (expected $A7 unit)) - (type $A22c (expected unit $A8)) - (type $A22d (expected $A9 $A10)) + (type $A22a (result)) + (type $A22b (result $A7)) + (type $A22c (result (error $A8))) + (type $A22d (result $A9 (error $A10))) ) (assert_invalid @@ -58,7 +55,7 @@ (assert_invalid (component - (type $t (variant (case "x" unit (refines $y)) (case $y "y" string))) + (type $t (variant (case "x" (refines $y)) (case $y "y" string))) ) "failed to find variant case named `$y`" ) @@ -132,7 +129,7 @@ (component (type (union 0))) "index out of bounds") (assert_invalid - (component (type (expected 0 1))) + (component (type (result 0 (error 1)))) "index out of bounds") (assert_invalid (component (type (tuple 0))) diff --git a/tests/local/component-model/func.wast b/tests/local/component-model/func.wast index a1924e7f36..c9c63c0e47 100644 --- a/tests/local/component-model/func.wast +++ b/tests/local/component-model/func.wast @@ -1,6 +1,43 @@ (component (import "" (func (param "foo" string))) - (import "a" (func (param "foo" string) (param s32) (param "bar" u32))) + (import "a" (func (param "foo" string) (param "bar" s32) (param "baz" u32))) + (import "b" (func (result "foo" (tuple)))) + (import "c" (func (result "foo" string) (result "bar" s32) (result "baz" u32))) +) + +(component + (import "" (func)) + (import "a" (func (param string))) + (import "b" (func (result u32))) + (import "c" (func (param bool) (result string))) +) + +(assert_invalid + (component + (import "a" (func (param "foo" string) (param s32) (param "bar" u32))) + ) + "function parameter name cannot be empty" +) + +(assert_invalid + (component + (import "a" (func (result "foo" string) (result s32) (result "bar" u32))) + ) + "function result name cannot be empty" +) + +(assert_invalid + (component + (type (func (param "foo" string) (param "foo" u32))) + ) + "duplicate parameter name" +) + +(assert_invalid + (component + (type (func (result "foo" string) (result "foo" u32))) + ) + "duplicate result name" ) (assert_invalid @@ -41,10 +78,10 @@ (component (type $big (func - (param u32) (param u32) (param u32) (param u32) (param u32) - (param u32) (param u32) (param u32) (param u32) (param u32) - (param u32) (param u32) (param u32) (param u32) (param u32) - (param u32) (param u32) (param u32) (param u32) (param u32) + (param "1" u32) (param "2" u32) (param "3" u32) (param "4" u32) (param "5" u32) + (param "6" u32) (param "7" u32) (param "8" u32) (param "9" u32) (param "10" u32) + (param "11" u32) (param "12" u32) (param "13" u32) (param "14" u32) (param "15" u32) + (param "16" u32) (param "17" u32) (param "18" u32) (param "19" u32) (param "20" u32) )) (component $c @@ -64,10 +101,10 @@ (core instance $m (instantiate $m)) (type $roundtrip (func - (param u32) (param u32) (param u32) (param u32) (param u32) - (param u32) (param u32) (param u32) (param u32) (param u32) - (param u32) (param u32) (param u32) (param u32) (param u32) - (param u32) (param u32) (param u32) (param u32) (param u32) + (param "1" u32) (param "2" u32) (param "3" u32) (param "4" u32) (param "5" u32) + (param "6" u32) (param "7" u32) (param "8" u32) (param "9" u32) (param "10" u32) + (param "11" u32) (param "12" u32) (param "13" u32) (param "14" u32) (param "15" u32) + (param "16" u32) (param "17" u32) (param "18" u32) (param "19" u32) (param "20" u32) )) (func $roundtrip (type $roundtrip) diff --git a/tests/local/component-model/start.wast b/tests/local/component-model/start.wast index c0307a6e9c..9cd6cb788a 100644 --- a/tests/local/component-model/start.wast +++ b/tests/local/component-model/start.wast @@ -16,7 +16,7 @@ (assert_invalid (component - (import "" (func $f (param string) (param string))) + (import "" (func $f (param "1" string) (param "2" string))) (import "v" (value $v string)) (start $f (value $v) (value $v) (result)) ) @@ -24,7 +24,7 @@ (assert_invalid (component - (import "" (func $f (param string) (param string))) + (import "" (func $f (param "x" string) (param "y" string))) (import "v" (value $v string)) (import "v2" (value $v2 u32)) (start $f (value $v) (value $v2) (result)) @@ -32,7 +32,7 @@ "type mismatch for component start function argument 1") (component - (import "" (func $f (param string) (param string))) + (import "" (func $f (param "z" string) (param "a" string))) (import "v" (value $v string)) (import "v2" (value $v2 string)) (start $f (value $v) (value $v2) (result)) diff --git a/tests/local/component-model/very-nested.wast b/tests/local/component-model/very-nested.wast index c008fb2925..f076780187 100644 --- a/tests/local/component-model/very-nested.wast +++ b/tests/local/component-model/very-nested.wast @@ -1837,16 +1837,16 @@ )) (type $f (func - (param $t4) - (param $t4) - (param $t4) - (param $t4) - (param $t4) - (param $t4) - (param $t4) - (param $t4) - (param $t4) - (param $t4) + (param "a" $t4) + (param "b" $t4) + (param "c" $t4) + (param "d" $t4) + (param "e" $t4) + (param "f" $t4) + (param "g" $t4) + (param "h" $t4) + (param "i" $t4) + (param "j" $t4) )) ) "effective type size exceeds the limit")