From a5eb177ef7abf1a0d3f6d8324864b65030a3e4c3 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 2 Feb 2025 16:51:37 +0100 Subject: [PATCH 01/25] support fixed length lists, part 1 --- crates/wasm-compose/src/encoding.rs | 2 +- crates/wasm-encoder/src/reencode/component.rs | 2 +- .../wasmparser/src/readers/component/types.rs | 4 +-- crates/wasmparser/src/validator/component.rs | 5 ++-- .../src/validator/component_types.rs | 27 ++++++++++++------- crates/wasmprinter/src/component.rs | 2 +- crates/wit-parser/src/abi.rs | 12 ++++++--- crates/wit-parser/src/ast.rs | 10 ++++++- crates/wit-parser/src/ast/resolve.rs | 8 +++--- crates/wit-parser/src/decoding.rs | 8 +++--- crates/wit-parser/src/lib.rs | 6 ++--- crates/wit-parser/src/live.rs | 2 +- crates/wit-parser/src/resolve.rs | 2 +- crates/wit-parser/src/sizealign.rs | 13 +++++++-- .../tests/ui/parse-fail/bad-list.wit | 3 +++ crates/wit-parser/tests/ui/types.wit | 2 ++ 16 files changed, 72 insertions(+), 36 deletions(-) diff --git a/crates/wasm-compose/src/encoding.rs b/crates/wasm-compose/src/encoding.rs index fe1622e742..84ce8eef42 100644 --- a/crates/wasm-compose/src/encoding.rs +++ b/crates/wasm-compose/src/encoding.rs @@ -648,7 +648,7 @@ impl<'a> TypeEncoder<'a> { } ComponentDefinedType::Record(r) => self.record(state, r), ComponentDefinedType::Variant(v) => self.variant(state, v), - ComponentDefinedType::List(ty) => self.list(state, *ty), + ComponentDefinedType::List(ty, ..) => self.list(state, *ty), ComponentDefinedType::Tuple(t) => self.tuple(state, t), ComponentDefinedType::Flags(names) => Self::flags(&mut state.cur.encodable, names), ComponentDefinedType::Enum(cases) => Self::enum_type(&mut state.cur.encodable, cases), diff --git a/crates/wasm-encoder/src/reencode/component.rs b/crates/wasm-encoder/src/reencode/component.rs index 33e7d81c5a..502bd537d6 100644 --- a/crates/wasm-encoder/src/reencode/component.rs +++ b/crates/wasm-encoder/src/reencode/component.rs @@ -764,7 +764,7 @@ pub mod component_utils { ) })); } - wasmparser::ComponentDefinedType::List(t) => { + wasmparser::ComponentDefinedType::List(t, ..) => { defined.list(reencoder.component_val_type(t)); } wasmparser::ComponentDefinedType::Tuple(t) => { diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index 0bdc1df956..5d23a63394 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -440,7 +440,7 @@ pub enum ComponentDefinedType<'a> { /// The type is a variant with the given cases. Variant(Box<[VariantCase<'a>]>), /// The type is a list of the given value type. - List(ComponentValType), + List(ComponentValType, Option), /// The type is a tuple of the given value types. Tuple(Box<[ComponentValType]>), /// The type is flags with the given names. @@ -479,7 +479,7 @@ impl<'a> ComponentDefinedType<'a> { .read_iter(MAX_WASM_VARIANT_CASES, "variant cases")? .collect::>()?, ), - 0x70 => ComponentDefinedType::List(reader.read()?), + 0x70 => ComponentDefinedType::List(reader.read()?, None), 0x6f => ComponentDefinedType::Tuple( reader .read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")? diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 75f997d171..05efce76bf 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -724,7 +724,7 @@ impl ComponentState { .map(|t| types.type_named_valtype(t, set)) .unwrap_or(true) } - ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { + ComponentDefinedType::List(ty, ..) | ComponentDefinedType::Option(ty) => { types.type_named_valtype(ty, set) } @@ -3436,8 +3436,9 @@ impl ComponentState { crate::ComponentDefinedType::Variant(cases) => { self.create_variant_type(cases.as_ref(), types, offset) } - crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List( + crate::ComponentDefinedType::List(ty, size) => Ok(ComponentDefinedType::List( self.create_component_val_type(ty, offset)?, + size, )), crate::ComponentDefinedType::Tuple(tys) => { self.create_tuple_type(tys.as_ref(), types, offset) diff --git a/crates/wasmparser/src/validator/component_types.rs b/crates/wasmparser/src/validator/component_types.rs index 271b850fc6..ad2a80ddc9 100644 --- a/crates/wasmparser/src/validator/component_types.rs +++ b/crates/wasmparser/src/validator/component_types.rs @@ -1083,7 +1083,7 @@ pub enum ComponentDefinedType { /// The type is a variant. Variant(VariantType), /// The type is a list. - List(ComponentValType), + List(ComponentValType, Option), /// The type is a tuple. Tuple(TupleType), /// The type is a set of flags. @@ -1124,7 +1124,7 @@ impl TypeData for ComponentDefinedType { Self::Record(r) => r.info, Self::Variant(v) => v.info, Self::Tuple(t) => t.info, - Self::List(ty) | Self::Option(ty) => ty.info(types), + Self::List(ty, ..) | Self::Option(ty) => ty.info(types), Self::Result { ok, err } => { let default = TypeInfo::new(); let mut info = ok.map(|ty| ty.type_info(types)).unwrap_or(default); @@ -1145,7 +1145,7 @@ impl ComponentDefinedType { .cases .values() .any(|case| case.ty.map(|ty| ty.contains_ptr(types)).unwrap_or(false)), - Self::List(_) => true, + Self::List(..) => true, Self::Tuple(t) => t.types.iter().any(|ty| ty.contains_ptr(types)), Self::Flags(_) | Self::Enum(_) @@ -1173,7 +1173,12 @@ impl ComponentDefinedType { types, lowered_types, ), - Self::List(_) => lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32), + Self::List(_, None) => { + lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32) + } + Self::List(ty, Some(length)) => { + (0..*length).all(|_n| ty.push_wasm_types(types, lowered_types)) + } Self::Tuple(t) => t .types .iter() @@ -1247,7 +1252,7 @@ impl ComponentDefinedType { ComponentDefinedType::Enum(_) => "enum", ComponentDefinedType::Flags(_) => "flags", ComponentDefinedType::Option(_) => "option", - ComponentDefinedType::List(_) => "list", + ComponentDefinedType::List(..) => "list", ComponentDefinedType::Result { .. } => "result", ComponentDefinedType::Own(_) => "own", ComponentDefinedType::Borrow(_) => "borrow", @@ -1985,7 +1990,7 @@ impl TypeAlloc { } } } - ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { + ComponentDefinedType::List(ty, ..) | ComponentDefinedType::Option(ty) => { self.free_variables_valtype(ty, set); } ComponentDefinedType::Result { ok, err } => { @@ -2127,7 +2132,7 @@ impl TypeAlloc { .map(|t| self.type_named_valtype(t, set)) .unwrap_or(true) } - ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { + ComponentDefinedType::List(ty, ..) | ComponentDefinedType::Option(ty) => { self.type_named_valtype(ty, set) } @@ -2314,7 +2319,7 @@ where } } } - ComponentDefinedType::List(ty) | ComponentDefinedType::Option(ty) => { + ComponentDefinedType::List(ty, ..) | ComponentDefinedType::Option(ty) => { any_changed |= self.remap_valtype(ty, map); } ComponentDefinedType::Result { ok, err } => { @@ -3201,8 +3206,10 @@ impl<'a> SubtypeCx<'a> { Ok(()) } (Variant(_), b) => bail!(offset, "expected {}, found variant", b.desc()), - (List(a), List(b)) | (Option(a), Option(b)) => self.component_val_type(a, b, offset), - (List(_), b) => bail!(offset, "expected {}, found list", b.desc()), + (List(a, ..), List(b, ..)) | (Option(a), Option(b)) => { + self.component_val_type(a, b, offset) + } + (List(_, ..), b) => bail!(offset, "expected {}, found list", b.desc()), (Option(_), b) => bail!(offset, "expected {}, found option", b.desc()), (Tuple(a), Tuple(b)) => { if a.types.len() != b.types.len() { diff --git a/crates/wasmprinter/src/component.rs b/crates/wasmprinter/src/component.rs index ee50cbaa21..cfe8921bf0 100644 --- a/crates/wasmprinter/src/component.rs +++ b/crates/wasmprinter/src/component.rs @@ -264,7 +264,7 @@ impl Printer<'_, '_> { ComponentDefinedType::Primitive(ty) => self.print_primitive_val_type(ty)?, ComponentDefinedType::Record(fields) => self.print_record_type(state, fields)?, ComponentDefinedType::Variant(cases) => self.print_variant_type(state, cases)?, - ComponentDefinedType::List(ty) => self.print_list_type(state, ty)?, + ComponentDefinedType::List(ty, _size) => self.print_list_type(state, ty)?, ComponentDefinedType::Tuple(tys) => self.print_tuple_type(state, tys)?, ComponentDefinedType::Flags(names) => self.print_flag_or_enum_type("flags", names)?, ComponentDefinedType::Enum(cases) => self.print_flag_or_enum_type("enum", cases)?, diff --git a/crates/wit-parser/src/abi.rs b/crates/wit-parser/src/abi.rs index 8b86fc8b32..89e7bb31ca 100644 --- a/crates/wit-parser/src/abi.rs +++ b/crates/wit-parser/src/abi.rs @@ -283,9 +283,15 @@ impl Resolve { } } - TypeDefKind::List(_) => { - result.push(WasmType::Pointer); - result.push(WasmType::Length); + TypeDefKind::List(ty, size) => { + if let Some(size) = size { + for _ in 0..*size { + self.push_flat(ty, result); + } + } else { + result.push(WasmType::Pointer); + result.push(WasmType::Length); + } } TypeDefKind::Variant(v) => { diff --git a/crates/wit-parser/src/ast.rs b/crates/wit-parser/src/ast.rs index 9608dbb705..16b153364c 100644 --- a/crates/wit-parser/src/ast.rs +++ b/crates/wit-parser/src/ast.rs @@ -903,6 +903,7 @@ struct Option_<'a> { struct List<'a> { span: Span, ty: Box>, + fixed_size: Option, } struct Future<'a> { @@ -1362,14 +1363,21 @@ impl<'a> Type<'a> { Some((span, Token::Bool)) => Ok(Type::Bool(span)), Some((span, Token::String_)) => Ok(Type::String(span)), - // list + // list or list Some((span, Token::List)) => { tokens.expect(Token::LessThan)?; let ty = Type::parse(tokens)?; + let size = if tokens.eat(Token::Comma)? { + tokens.expect(Token::Integer)?; + Some(1) + } else { + None + }; tokens.expect(Token::GreaterThan)?; Ok(Type::List(List { span, ty: Box::new(ty), + fixed_size: size, })) } diff --git a/crates/wit-parser/src/ast/resolve.rs b/crates/wit-parser/src/ast/resolve.rs index ee7777bbc0..b5c1798d6b 100644 --- a/crates/wit-parser/src/ast/resolve.rs +++ b/crates/wit-parser/src/ast/resolve.rs @@ -91,7 +91,7 @@ enum Key { Flags(Vec), Tuple(Vec), Enum(Vec), - List(Type), + List(Type, Option), Option(Type), Result(Option, Option), Future(Option), @@ -1172,7 +1172,7 @@ impl<'a> Resolver<'a> { } ast::Type::List(list) => { let ty = self.resolve_type(&list.ty, stability)?; - TypeDefKind::List(ty) + TypeDefKind::List(ty, list.fixed_size) } ast::Type::Handle(handle) => TypeDefKind::Handle(match handle { ast::Handle::Own { resource } => Handle::Own(self.validate_resource(resource)?), @@ -1351,7 +1351,7 @@ impl<'a> Resolver<'a> { find_in_type(types, Type::Id(*id)) } TypeDefKind::Tuple(t) => t.types.iter().find_map(|ty| find_in_type(types, *ty)), - TypeDefKind::List(ty) | TypeDefKind::Option(ty) => find_in_type(types, *ty), + TypeDefKind::List(ty, ..) | TypeDefKind::Option(ty) => find_in_type(types, *ty), TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => { ty.as_ref().and_then(|ty| find_in_type(types, *ty)) } @@ -1442,7 +1442,7 @@ impl<'a> Resolver<'a> { TypeDefKind::Enum(r) => { Key::Enum(r.cases.iter().map(|f| f.name.clone()).collect::>()) } - TypeDefKind::List(ty) => Key::List(*ty), + TypeDefKind::List(ty, size) => Key::List(*ty, *size), TypeDefKind::Option(t) => Key::Option(*t), TypeDefKind::Result(r) => Key::Result(r.ok, r.err), TypeDefKind::Future(ty) => Key::Future(*ty), diff --git a/crates/wit-parser/src/decoding.rs b/crates/wit-parser/src/decoding.rs index 26c7e93edd..7f0a7bdf0a 100644 --- a/crates/wit-parser/src/decoding.rs +++ b/crates/wit-parser/src/decoding.rs @@ -1253,7 +1253,7 @@ impl WitPackageDecoder<'_> { let kind = self.convert_defined(def)?; match &kind { TypeDefKind::Type(_) - | TypeDefKind::List(_) + | TypeDefKind::List(..) | TypeDefKind::Tuple(_) | TypeDefKind::Option(_) | TypeDefKind::Result(_) @@ -1289,7 +1289,7 @@ impl WitPackageDecoder<'_> { match ty { ComponentDefinedType::Primitive(t) => Ok(TypeDefKind::Type(self.convert_primitive(*t))), - ComponentDefinedType::List(t) => { + ComponentDefinedType::List(t, ..) => { let t = self.convert_valtype(t)?; Ok(TypeDefKind::List(t)) } @@ -1570,9 +1570,9 @@ impl Registrar<'_> { match def { ComponentDefinedType::Primitive(_) => Ok(()), - ComponentDefinedType::List(t) => { + ComponentDefinedType::List(t, ..) => { let ty = match &self.resolve.types[id].kind { - TypeDefKind::List(r) => r, + TypeDefKind::List(r, ..) => r, // Note that all cases below have this match and the general // idea is that once a type is named or otherwise identified // here there's no need to recurse. The purpose of this diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs index d8551db1d7..e0e51382b3 100644 --- a/crates/wit-parser/src/lib.rs +++ b/crates/wit-parser/src/lib.rs @@ -568,7 +568,7 @@ pub enum TypeDefKind { Enum(Enum), Option(Type), Result(Result_), - List(Type), + List(Type, Option), Future(Option), Stream(Option), Type(Type), @@ -596,7 +596,7 @@ impl TypeDefKind { TypeDefKind::Enum(_) => "enum", TypeDefKind::Option(_) => "option", TypeDefKind::Result(_) => "result", - TypeDefKind::List(_) => "list", + TypeDefKind::List(..) => "list", TypeDefKind::Future(_) => "future", TypeDefKind::Stream(_) => "stream", TypeDefKind::Type(_) => "type", @@ -1153,7 +1153,7 @@ fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec { + TypeDefKind::Option(ty) | TypeDefKind::List(ty, ..) | TypeDefKind::Type(ty) => { find_futures_and_streams(resolve, *ty, results); } TypeDefKind::Result(r) => { diff --git a/crates/wit-parser/src/live.rs b/crates/wit-parser/src/live.rs index 27a769b095..98003bfabd 100644 --- a/crates/wit-parser/src/live.rs +++ b/crates/wit-parser/src/live.rs @@ -131,7 +131,7 @@ pub trait TypeIdVisitor { fn visit_type_def(&mut self, resolve: &Resolve, ty: &TypeDef) { match &ty.kind { TypeDefKind::Type(t) - | TypeDefKind::List(t) + | TypeDefKind::List(t, ..) | TypeDefKind::Option(t) | TypeDefKind::Future(Some(t)) | TypeDefKind::Stream(Some(t)) => self.visit_type(resolve, t), diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs index 8950dcd163..a87bfcaee3 100644 --- a/crates/wit-parser/src/resolve.rs +++ b/crates/wit-parser/src/resolve.rs @@ -3135,7 +3135,7 @@ impl Remap { } } } - Option(t) | List(t) | Future(Some(t)) | Stream(Some(t)) => { + Option(t) | List(t, ..) | Future(Some(t)) | Stream(Some(t)) => { self.update_ty(resolve, t, span)? } Result(r) => { diff --git a/crates/wit-parser/src/sizealign.rs b/crates/wit-parser/src/sizealign.rs index 5e0f0e0ddb..268f93866b 100644 --- a/crates/wit-parser/src/sizealign.rs +++ b/crates/wit-parser/src/sizealign.rs @@ -260,8 +260,17 @@ impl SizeAlign { fn calculate(&self, ty: &TypeDef) -> ElementInfo { match &ty.kind { TypeDefKind::Type(t) => ElementInfo::new(self.size(t), self.align(t)), - TypeDefKind::List(_) => { - ElementInfo::new(ArchitectureSize::new(0, 2), Alignment::Pointer) + TypeDefKind::List(t, size) => { + if let Some(size) = size { + let field_align = self.align(t); + let field_size = self.size(t); + ElementInfo::new( + ArchitectureSize::new(field_size.bytes * size, field_size.pointers * size), + field_align, + ) + } else { + ElementInfo::new(ArchitectureSize::new(0, 2), Alignment::Pointer) + } } TypeDefKind::Record(r) => self.record(r.fields.iter().map(|f| &f.ty)), TypeDefKind::Tuple(t) => self.record(t.types.iter()), diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list.wit b/crates/wit-parser/tests/ui/parse-fail/bad-list.wit index e3aca6b984..95aec07e4d 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-list.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-list.wit @@ -2,6 +2,9 @@ interface foo { type x = list + type b = list type y = u32 } diff --git a/crates/wit-parser/tests/ui/types.wit b/crates/wit-parser/tests/ui/types.wit index d67939799d..5a644f305c 100644 --- a/crates/wit-parser/tests/ui/types.wit +++ b/crates/wit-parser/tests/ui/types.wit @@ -50,6 +50,8 @@ interface types { type t48 = stream; type t49 = future; type t50 = future; + type t51a = list; + type t51b = list, 2>; /// type order doesn't matter type foo = bar; From 6aeef59b1fa413c9c3af2737957d7ce588309457 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 2 Feb 2025 17:05:25 +0100 Subject: [PATCH 02/25] more fixed size --- crates/wasm-wave/src/value/wit.rs | 2 +- crates/wit-component/src/encoding.rs | 2 +- crates/wit-component/src/encoding/types.rs | 2 +- crates/wit-component/src/printing.rs | 7 +++++-- crates/wit-encoder/src/from_parser.rs | 8 ++++---- crates/wit-encoder/src/ty.rs | 14 +++++++++----- crates/wit-encoder/tests/type_defs.rs | 4 ++-- crates/wit-encoder/tests/world.rs | 2 +- crates/wit-parser/src/decoding.rs | 4 ++-- crates/wit-parser/src/resolve.rs | 5 +++-- crates/wit-parser/src/resolve/clone.rs | 2 +- 11 files changed, 30 insertions(+), 22 deletions(-) diff --git a/crates/wasm-wave/src/value/wit.rs b/crates/wasm-wave/src/value/wit.rs index 423090a622..62f17f3137 100644 --- a/crates/wasm-wave/src/value/wit.rs +++ b/crates/wasm-wave/src/value/wit.rs @@ -69,7 +69,7 @@ impl<'a> TypeResolver<'a> { TypeDefKind::Enum(enum_) => self.resolve_enum(enum_), TypeDefKind::Option(some_type) => self.resolve_option(some_type), TypeDefKind::Result(result) => self.resolve_result(result), - TypeDefKind::List(element_type) => self.resolve_list(element_type), + TypeDefKind::List(element_type, _size) => self.resolve_list(element_type), TypeDefKind::Type(Type::Bool) => Ok(value::Type::BOOL), TypeDefKind::Type(Type::U8) => Ok(value::Type::U8), TypeDefKind::Type(Type::U16) => Ok(value::Type::U16), diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 737c31df7f..8b92a49354 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -319,7 +319,7 @@ impl TypeContents { Self::for_optional_types(resolve, v.cases.iter().map(|c| c.ty.as_ref())) } TypeDefKind::Enum(_) => Self::empty(), - TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::LIST, + TypeDefKind::List(t, ..) => Self::for_type(resolve, t) | Self::LIST, TypeDefKind::Type(t) => Self::for_type(resolve, t), TypeDefKind::Future(_) => Self::empty(), TypeDefKind::Stream(_) => Self::empty(), diff --git a/crates/wit-component/src/encoding/types.rs b/crates/wit-component/src/encoding/types.rs index 59d4330f52..927b02b287 100644 --- a/crates/wit-component/src/encoding/types.rs +++ b/crates/wit-component/src/encoding/types.rs @@ -138,7 +138,7 @@ pub trait ValtypeEncoder<'a> { TypeDefKind::Option(t) => self.encode_option(resolve, t)?, TypeDefKind::Result(r) => self.encode_result(resolve, r)?, TypeDefKind::Enum(e) => self.encode_enum(e)?, - TypeDefKind::List(ty) => { + TypeDefKind::List(ty, ..) => { let ty = self.encode_valtype(resolve, ty)?; let (index, encoder) = self.defined_type(); encoder.list(ty); diff --git a/crates/wit-component/src/printing.rs b/crates/wit-component/src/printing.rs index 3292fd0550..e9b9595aad 100644 --- a/crates/wit-component/src/printing.rs +++ b/crates/wit-component/src/printing.rs @@ -567,10 +567,13 @@ impl WitPrinter { TypeDefKind::Variant(_) => { bail!("resolve has unnamed variant type") } - TypeDefKind::List(ty) => { + TypeDefKind::List(ty, size) => { self.output.ty("list", TypeKind::BuiltIn); self.output.generic_args_start(); self.print_type_name(resolve, ty)?; + if let Some(size) = size { + self.output.push_str(&format!(", {}", *size)); + } self.output.generic_args_end(); } TypeDefKind::Type(ty) => self.print_type_name(resolve, ty)?, @@ -744,7 +747,7 @@ impl WitPrinter { self.declare_result(resolve, ty.name.as_deref(), r)? } TypeDefKind::Enum(e) => self.declare_enum(ty.name.as_deref(), e)?, - TypeDefKind::List(inner) => { + TypeDefKind::List(inner, _size) => { self.declare_list(resolve, ty.name.as_deref(), inner)? } TypeDefKind::Type(inner) => match ty.name.as_deref() { diff --git a/crates/wit-encoder/src/from_parser.rs b/crates/wit-encoder/src/from_parser.rs index 0a107a6edc..b4a9a54b05 100644 --- a/crates/wit-encoder/src/from_parser.rs +++ b/crates/wit-encoder/src/from_parser.rs @@ -239,8 +239,8 @@ impl<'a> Converter<'a> { let output = Type::option(self.convert_type(ty)); TypeDefKind::Type(output) } - wit_parser::TypeDefKind::List(ty) => { - let output = Type::list(self.convert_type(ty)); + wit_parser::TypeDefKind::List(ty, size) => { + let output = Type::list(self.convert_type(ty), *size); TypeDefKind::Type(output) } wit_parser::TypeDefKind::Handle(handle) => { @@ -301,8 +301,8 @@ impl<'a> Converter<'a> { wit_parser::TypeDefKind::Result(result) => { Type::result(self.convert_result(result)) } - wit_parser::TypeDefKind::List(type_) => { - Type::list(self.convert_type(type_)) + wit_parser::TypeDefKind::List(type_, size) => { + Type::list(self.convert_type(type_), *size) } wit_parser::TypeDefKind::Handle(handle) => self.handle_to_type(handle), wit_parser::TypeDefKind::Future(type_) => { diff --git a/crates/wit-encoder/src/ty.rs b/crates/wit-encoder/src/ty.rs index 79006fd054..d7dc88c92b 100644 --- a/crates/wit-encoder/src/ty.rs +++ b/crates/wit-encoder/src/ty.rs @@ -25,7 +25,7 @@ pub enum Type { Borrow(Ident), Option(Box), Result(Box), - List(Box), + List(Box, Option), Tuple(Tuple), Future(Option>), Stream(Option>), @@ -55,8 +55,8 @@ impl Type { pub fn result_empty() -> Self { Type::Result(Box::new(Result_::empty())) } - pub fn list(type_: Type) -> Self { - Type::List(Box::new(type_)) + pub fn list(type_: Type, size: Option) -> Self { + Type::List(Box::new(type_), size) } pub fn tuple(types: impl IntoIterator) -> Self { Type::Tuple(Tuple { @@ -113,8 +113,12 @@ impl Display for Type { write!(f, "option<{type_}>") } Type::Result(result) => result.fmt(f), - Type::List(type_) => { - write!(f, "list<{type_}>") + Type::List(type_, size) => { + if let Some(size) = size { + write!(f, "list<{type_}, {size}>") + } else { + write!(f, "list<{type_}>") + } } Type::Tuple(tuple) => tuple.fmt(f), Type::Future(None) => { diff --git a/crates/wit-encoder/tests/type_defs.rs b/crates/wit-encoder/tests/type_defs.rs index 02d0147f5b..974d2f1a7f 100644 --- a/crates/wit-encoder/tests/type_defs.rs +++ b/crates/wit-encoder/tests/type_defs.rs @@ -139,7 +139,7 @@ fn types() { interface.type_def(TypeDef::type_("t10a", Type::F64)); interface.type_def(TypeDef::type_("t10b", Type::F64)); interface.type_def(TypeDef::type_("t11", Type::Char)); - interface.type_def(TypeDef::type_("t12", Type::list(Type::Char))); + interface.type_def(TypeDef::type_("t12", Type::list(Type::Char, None))); interface.type_def(TypeDef::type_("t13", Type::String)); interface.type_def(TypeDef::type_("t14", Type::option(Type::U32))); interface.type_def(TypeDef::type_( @@ -206,7 +206,7 @@ fn types() { interface.type_def(TypeDef::type_("t44", Type::String)); interface.type_def(TypeDef::type_( "t45", - Type::list(Type::list(Type::list(Type::named("t32")))), + Type::list(Type::list(Type::list(Type::named("t32"), None), None), None), )); interface.type_def(TypeDef::type_("t46", Type::named("t44"))); interface.type_def(TypeDef::type_("foo", Type::named("bar"))); diff --git a/crates/wit-encoder/tests/world.rs b/crates/wit-encoder/tests/world.rs index 192d5fe464..395cbb753b 100644 --- a/crates/wit-encoder/tests/world.rs +++ b/crates/wit-encoder/tests/world.rs @@ -40,7 +40,7 @@ fn worlds() { }); world.function_export({ let mut func = StandaloneFunc::new("scan", false); - func.set_result(Some(Type::list(Type::U8))); + func.set_result(Some(Type::list(Type::U8, None))); func.set_docs(Some("scan stuff")); func }); diff --git a/crates/wit-parser/src/decoding.rs b/crates/wit-parser/src/decoding.rs index 7f0a7bdf0a..8d4f20df9a 100644 --- a/crates/wit-parser/src/decoding.rs +++ b/crates/wit-parser/src/decoding.rs @@ -1289,9 +1289,9 @@ impl WitPackageDecoder<'_> { match ty { ComponentDefinedType::Primitive(t) => Ok(TypeDefKind::Type(self.convert_primitive(*t))), - ComponentDefinedType::List(t, ..) => { + ComponentDefinedType::List(t, size) => { let t = self.convert_valtype(t)?; - Ok(TypeDefKind::List(t)) + Ok(TypeDefKind::List(t, *size)) } ComponentDefinedType::Tuple(t) => { diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs index a87bfcaee3..62a48eaff2 100644 --- a/crates/wit-parser/src/resolve.rs +++ b/crates/wit-parser/src/resolve.rs @@ -566,7 +566,8 @@ package {name} is defined in two different locations:\n\ Type::Bool | Type::Char | Type::String | Type::ErrorContext => false, Type::Id(id) => match &self.types[*id].kind { - TypeDefKind::List(_) + TypeDefKind::List(t, Some(_)) => self.all_bits_valid(t), + TypeDefKind::List(_, None) | TypeDefKind::Variant(_) | TypeDefKind::Enum(_) | TypeDefKind::Option(_) @@ -3521,7 +3522,7 @@ impl Remap { TypeDefKind::Flags(_) => false, TypeDefKind::Tuple(t) => t.types.iter().any(|t| self.type_has_borrow(resolve, t)), TypeDefKind::Enum(_) => false, - TypeDefKind::List(ty) + TypeDefKind::List(ty, ..) | TypeDefKind::Future(Some(ty)) | TypeDefKind::Stream(Some(ty)) | TypeDefKind::Option(ty) => self.type_has_borrow(resolve, ty), diff --git a/crates/wit-parser/src/resolve/clone.rs b/crates/wit-parser/src/resolve/clone.rs index 5554826fa9..087fc6c4b4 100644 --- a/crates/wit-parser/src/resolve/clone.rs +++ b/crates/wit-parser/src/resolve/clone.rs @@ -109,7 +109,7 @@ impl<'a> Cloner<'a> { TypeDefKind::Handle(Handle::Own(ty) | Handle::Borrow(ty)) => { self.type_id(ty); } - TypeDefKind::Option(ty) | TypeDefKind::List(ty) => { + TypeDefKind::Option(ty) | TypeDefKind::List(ty, ..) => { self.ty(ty); } TypeDefKind::Tuple(list) => { From c14d32d9ff571fd90b4e03a1018237ff36c77bba Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 2 Feb 2025 17:46:09 +0100 Subject: [PATCH 03/25] fix tests for wit-parser --- crates/wit-parser/src/ast.rs | 12 +++- .../tests/ui/multi-package-deps.wit.json | 5 +- .../tests/ui/parse-fail/bad-list.wit | 3 - .../tests/ui/parse-fail/bad-list2.wit | 7 +++ .../tests/ui/parse-fail/bad-list2.wit.result | 5 ++ .../tests/ui/parse-fail/bad-list3.wit | 7 +++ .../tests/ui/parse-fail/bad-list3.wit.result | 5 ++ .../tests/ui/parse-fail/bad-list4.wit | 7 +++ .../tests/ui/parse-fail/bad-list4.wit.result | 5 ++ crates/wit-parser/tests/ui/random.wit.json | 5 +- .../wit-parser/tests/ui/shared-types.wit.json | 5 +- .../tests/ui/streams-and-futures.wit.json | 10 ++- crates/wit-parser/tests/ui/types.wit.json | 62 ++++++++++++++++--- .../tests/ui/world-top-level-funcs.wit.json | 10 ++- .../ui/world-top-level-resources.wit.json | 5 +- 15 files changed, 132 insertions(+), 21 deletions(-) create mode 100644 crates/wit-parser/tests/ui/parse-fail/bad-list2.wit create mode 100644 crates/wit-parser/tests/ui/parse-fail/bad-list2.wit.result create mode 100644 crates/wit-parser/tests/ui/parse-fail/bad-list3.wit create mode 100644 crates/wit-parser/tests/ui/parse-fail/bad-list3.wit.result create mode 100644 crates/wit-parser/tests/ui/parse-fail/bad-list4.wit create mode 100644 crates/wit-parser/tests/ui/parse-fail/bad-list4.wit.result diff --git a/crates/wit-parser/src/ast.rs b/crates/wit-parser/src/ast.rs index 16b153364c..2797324906 100644 --- a/crates/wit-parser/src/ast.rs +++ b/crates/wit-parser/src/ast.rs @@ -1363,13 +1363,19 @@ impl<'a> Type<'a> { Some((span, Token::Bool)) => Ok(Type::Bool(span)), Some((span, Token::String_)) => Ok(Type::String(span)), - // list or list + // list + // list Some((span, Token::List)) => { tokens.expect(Token::LessThan)?; let ty = Type::parse(tokens)?; let size = if tokens.eat(Token::Comma)? { - tokens.expect(Token::Integer)?; - Some(1) + let number = tokens.next()?; + if let Some((span, Token::Integer)) = number { + let size: usize = tokens.get_span(span).parse()?; + Some(size) + } else { + return Err(err_expected(tokens, "fixed size", number).into()); + } } else { None }; diff --git a/crates/wit-parser/tests/ui/multi-package-deps.wit.json b/crates/wit-parser/tests/ui/multi-package-deps.wit.json index 427c1bdf35..45989fb266 100644 --- a/crates/wit-parser/tests/ui/multi-package-deps.wit.json +++ b/crates/wit-parser/tests/ui/multi-package-deps.wit.json @@ -79,7 +79,10 @@ { "name": "l", "kind": { - "list": 3 + "list": [ + 3, + null + ] }, "owner": { "interface": 2 diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list.wit b/crates/wit-parser/tests/ui/parse-fail/bad-list.wit index 95aec07e4d..e3aca6b984 100644 --- a/crates/wit-parser/tests/ui/parse-fail/bad-list.wit +++ b/crates/wit-parser/tests/ui/parse-fail/bad-list.wit @@ -2,9 +2,6 @@ interface foo { type x = list - type b = list type y = u32 } diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list2.wit b/crates/wit-parser/tests/ui/parse-fail/bad-list2.wit new file mode 100644 index 0000000000..4313c54958 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-list2.wit @@ -0,0 +1,7 @@ +// parse-fail + +interface foo { + type z = list tests/ui/parse-fail/bad-list2.wit:6:3 + | + 6 | type y = u32 + | ^--- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit b/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit new file mode 100644 index 0000000000..1f0238ea03 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit @@ -0,0 +1,7 @@ +// parse-fail + +interface foo { + type a = list + + type y = u32 +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit.result new file mode 100644 index 0000000000..4f48238f89 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-list3.wit.result @@ -0,0 +1,5 @@ +expected fixed size, found '>' + --> tests/ui/parse-fail/bad-list3.wit:4:21 + | + 4 | type a = list + | ^ \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit b/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit new file mode 100644 index 0000000000..14fa344da0 --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit @@ -0,0 +1,7 @@ +// parse-fail + +interface foo { + type b = list + + type y = u32 +} diff --git a/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit.result b/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit.result new file mode 100644 index 0000000000..c2aae207fa --- /dev/null +++ b/crates/wit-parser/tests/ui/parse-fail/bad-list4.wit.result @@ -0,0 +1,5 @@ +expected fixed size, found keyword `u32` + --> tests/ui/parse-fail/bad-list4.wit:4:22 + | + 4 | type b = list + | ^-- \ No newline at end of file diff --git a/crates/wit-parser/tests/ui/random.wit.json b/crates/wit-parser/tests/ui/random.wit.json index dcf2178c1c..7c4f4b5267 100644 --- a/crates/wit-parser/tests/ui/random.wit.json +++ b/crates/wit-parser/tests/ui/random.wit.json @@ -39,7 +39,10 @@ { "name": null, "kind": { - "list": "u8" + "list": [ + "u8", + null + ] }, "owner": null } diff --git a/crates/wit-parser/tests/ui/shared-types.wit.json b/crates/wit-parser/tests/ui/shared-types.wit.json index 8f53710b99..06142a9d2c 100644 --- a/crates/wit-parser/tests/ui/shared-types.wit.json +++ b/crates/wit-parser/tests/ui/shared-types.wit.json @@ -51,7 +51,10 @@ { "name": null, "kind": { - "list": "u8" + "list": [ + "u8", + null + ] }, "owner": null }, diff --git a/crates/wit-parser/tests/ui/streams-and-futures.wit.json b/crates/wit-parser/tests/ui/streams-and-futures.wit.json index 8a0b295308..7e579e1634 100644 --- a/crates/wit-parser/tests/ui/streams-and-futures.wit.json +++ b/crates/wit-parser/tests/ui/streams-and-futures.wit.json @@ -72,7 +72,10 @@ { "name": null, "kind": { - "list": "u8" + "list": [ + "u8", + null + ] }, "owner": null }, @@ -171,7 +174,10 @@ { "name": null, "kind": { - "list": "string" + "list": [ + "string", + null + ] }, "owner": null }, diff --git a/crates/wit-parser/tests/ui/types.wit.json b/crates/wit-parser/tests/ui/types.wit.json index 1b5e70e51d..5825d842cb 100644 --- a/crates/wit-parser/tests/ui/types.wit.json +++ b/crates/wit-parser/tests/ui/types.wit.json @@ -53,8 +53,10 @@ "t48": 49, "t49": 50, "t50": 51, - "bar": 52, - "foo": 53 + "t51a": 52, + "t51b": 54, + "bar": 55, + "foo": 56 }, "functions": {}, "package": 0 @@ -181,7 +183,10 @@ { "name": "t12", "kind": { - "list": "char" + "list": [ + "char", + null + ] }, "owner": { "interface": 0 @@ -633,21 +638,30 @@ { "name": null, "kind": { - "list": 33 + "list": [ + 33, + null + ] }, "owner": null }, { "name": null, "kind": { - "list": 44 + "list": [ + 44, + null + ] }, "owner": null }, { "name": "t45", "kind": { - "list": 45 + "list": [ + 45, + null + ] }, "owner": { "interface": 0 @@ -698,6 +712,40 @@ "interface": 0 } }, + { + "name": "t51a", + "kind": { + "list": [ + "u32", + 4 + ] + }, + "owner": { + "interface": 0 + } + }, + { + "name": null, + "kind": { + "list": [ + "u32", + 4 + ] + }, + "owner": null + }, + { + "name": "t51b", + "kind": { + "list": [ + 53, + 2 + ] + }, + "owner": { + "interface": 0 + } + }, { "name": "bar", "kind": { @@ -710,7 +758,7 @@ { "name": "foo", "kind": { - "type": 52 + "type": 55 }, "owner": { "interface": 0 diff --git a/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json b/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json index df491f2349..b87e1c686d 100644 --- a/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json +++ b/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json @@ -48,7 +48,10 @@ { "name": null, "kind": { - "list": "u32" + "list": [ + "u32", + null + ] }, "owner": null }, @@ -62,7 +65,10 @@ { "name": null, "kind": { - "list": 1 + "list": [ + 1, + null + ] }, "owner": null } diff --git a/crates/wit-parser/tests/ui/world-top-level-resources.wit.json b/crates/wit-parser/tests/ui/world-top-level-resources.wit.json index 0babd96f9b..f59b8a7ea2 100644 --- a/crates/wit-parser/tests/ui/world-top-level-resources.wit.json +++ b/crates/wit-parser/tests/ui/world-top-level-resources.wit.json @@ -151,7 +151,10 @@ { "name": null, "kind": { - "list": "u32" + "list": [ + "u32", + null + ] }, "owner": null }, From ef4b5e58e4be522d8d71fa588db53f08df4c0b95 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 9 Feb 2025 15:41:23 +0100 Subject: [PATCH 04/25] re-implement as two separate types (outside of WIT) --- crates/wasm-compose/src/encoding.rs | 26 ++++++++++- crates/wasm-encoder/src/component/types.rs | 7 +++ crates/wasm-encoder/src/reencode/component.rs | 5 ++- crates/wasm-wave/src/value/ty.rs | 11 +++++ crates/wasm-wave/src/value/wit.rs | 10 ++++- crates/wasm-wave/src/wasm/ty.rs | 2 + crates/wasm-wave/src/writer.rs | 10 +++++ .../wasmparser/src/readers/component/types.rs | 6 ++- crates/wasmparser/src/validator/component.rs | 15 ++++--- .../src/validator/component_types.rs | 44 ++++++++++++------- crates/wasmprinter/src/component.rs | 18 +++++++- crates/wit-component/src/encoding.rs | 3 +- crates/wit-component/src/encoding/types.rs | 8 +++- crates/wit-component/src/printing.rs | 41 ++++++++++++++--- crates/wit-encoder/src/from_parser.rs | 15 +++++-- crates/wit-parser/src/abi.rs | 16 +++---- crates/wit-parser/src/ast/resolve.rs | 13 ++++-- crates/wit-parser/src/decoding.rs | 32 +++++++++++--- crates/wit-parser/src/lib.rs | 10 +++-- crates/wit-parser/src/live.rs | 3 +- crates/wit-parser/src/resolve.rs | 10 ++--- crates/wit-parser/src/resolve/clone.rs | 4 +- crates/wit-parser/src/sizealign.rs | 21 +++++---- 23 files changed, 253 insertions(+), 77 deletions(-) diff --git a/crates/wasm-compose/src/encoding.rs b/crates/wasm-compose/src/encoding.rs index 84ce8eef42..07bdba48d9 100644 --- a/crates/wasm-compose/src/encoding.rs +++ b/crates/wasm-compose/src/encoding.rs @@ -648,7 +648,10 @@ impl<'a> TypeEncoder<'a> { } ComponentDefinedType::Record(r) => self.record(state, r), ComponentDefinedType::Variant(v) => self.variant(state, v), - ComponentDefinedType::List(ty, ..) => self.list(state, *ty), + ComponentDefinedType::List(ty) => self.list(state, *ty), + ComponentDefinedType::FixedSizeList(ty, elements) => { + self.fixed_size_list(state, *ty, *elements) + } ComponentDefinedType::Tuple(t) => self.tuple(state, t), ComponentDefinedType::Flags(names) => Self::flags(&mut state.cur.encodable, names), ComponentDefinedType::Enum(cases) => Self::enum_type(&mut state.cur.encodable, cases), @@ -709,6 +712,23 @@ impl<'a> TypeEncoder<'a> { index } + fn fixed_size_list( + &self, + state: &mut TypeState<'a>, + ty: ct::ComponentValType, + elements: usize, + ) -> u32 { + let ty = self.component_val_type(state, ty); + let index = state.cur.encodable.type_count(); + state + .cur + .encodable + .ty() + .defined_type() + .fixed_size_list(ty, elements); + index + } + fn tuple(&self, state: &mut TypeState<'a>, tuple: &TupleType) -> u32 { let types = tuple .types @@ -1228,7 +1248,9 @@ impl DependencyRegistrar<'_, '_> { ComponentDefinedType::Primitive(_) | ComponentDefinedType::Enum(_) | ComponentDefinedType::Flags(_) => {} - ComponentDefinedType::List(t) | ComponentDefinedType::Option(t) => self.val_type(*t), + ComponentDefinedType::List(t) + | ComponentDefinedType::FixedSizeList(t, _) + | ComponentDefinedType::Option(t) => self.val_type(*t), ComponentDefinedType::Own(r) | ComponentDefinedType::Borrow(r) => { self.ty(ComponentAnyTypeId::Resource(*r)) } diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index e32c75c464..5edf85f224 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -593,6 +593,13 @@ impl ComponentDefinedTypeEncoder<'_> { ty.into().encode(self.0); } + /// Define a fixed size list type. + pub fn fixed_size_list(self, ty: impl Into, elements: usize) { + self.0.push(0x67); + ty.into().encode(self.0); + (elements as u32).encode(self.0); + } + /// Define a tuple type. pub fn tuple(self, types: I) where diff --git a/crates/wasm-encoder/src/reencode/component.rs b/crates/wasm-encoder/src/reencode/component.rs index 502bd537d6..faaa4fecdd 100644 --- a/crates/wasm-encoder/src/reencode/component.rs +++ b/crates/wasm-encoder/src/reencode/component.rs @@ -764,9 +764,12 @@ pub mod component_utils { ) })); } - wasmparser::ComponentDefinedType::List(t, ..) => { + wasmparser::ComponentDefinedType::List(t) => { defined.list(reencoder.component_val_type(t)); } + wasmparser::ComponentDefinedType::FixedSizeList(t, elements) => { + defined.fixed_size_list(reencoder.component_val_type(t), elements); + } wasmparser::ComponentDefinedType::Tuple(t) => { defined.tuple(t.iter().map(|t| reencoder.component_val_type(*t))); } diff --git a/crates/wasm-wave/src/value/ty.rs b/crates/wasm-wave/src/value/ty.rs index 8898892b4a..1f74d58f38 100644 --- a/crates/wasm-wave/src/value/ty.rs +++ b/crates/wasm-wave/src/value/ty.rs @@ -10,6 +10,7 @@ pub struct Type(pub(super) TypeEnum); pub(super) enum TypeEnum { Simple(SimpleType), List(Arc), + FixedSizeList(Arc, usize), Record(Arc), Tuple(Arc), Variant(Arc), @@ -55,6 +56,15 @@ impl Type { Self(TypeEnum::List(Arc::new(ListType { element }))) } + /// Returns a list type with the given element type. + pub fn fixed_size_list(element_type: impl Into, elements: usize) -> Self { + let element = element_type.into(); + Self(TypeEnum::FixedSizeList( + Arc::new(ListType { element }), + elements, + )) + } + /// Returns a record type with the given field types. Returns None if /// `fields` is empty. pub fn record>>( @@ -189,6 +199,7 @@ impl WasmType for Type { match self.0 { TypeEnum::Simple(simple) => simple.0, TypeEnum::List(_) => WasmTypeKind::List, + TypeEnum::FixedSizeList(_, _) => WasmTypeKind::FixedSizeList, TypeEnum::Record(_) => WasmTypeKind::Record, TypeEnum::Tuple(_) => WasmTypeKind::Tuple, TypeEnum::Variant(_) => WasmTypeKind::Variant, diff --git a/crates/wasm-wave/src/value/wit.rs b/crates/wasm-wave/src/value/wit.rs index 62f17f3137..1872b076f9 100644 --- a/crates/wasm-wave/src/value/wit.rs +++ b/crates/wasm-wave/src/value/wit.rs @@ -69,7 +69,10 @@ impl<'a> TypeResolver<'a> { TypeDefKind::Enum(enum_) => self.resolve_enum(enum_), TypeDefKind::Option(some_type) => self.resolve_option(some_type), TypeDefKind::Result(result) => self.resolve_result(result), - TypeDefKind::List(element_type, _size) => self.resolve_list(element_type), + TypeDefKind::List(element_type) => self.resolve_list(element_type), + TypeDefKind::FixedSizeList(element_type, elements) => { + self.resolve_fixed_size_list(element_type, *elements) + } TypeDefKind::Type(Type::Bool) => Ok(value::Type::BOOL), TypeDefKind::Type(Type::U8) => Ok(value::Type::U8), TypeDefKind::Type(Type::U16) => Ok(value::Type::U16), @@ -145,6 +148,11 @@ impl<'a> TypeResolver<'a> { let element_type = self.resolve_type(*element_type)?; Ok(value::Type::list(element_type)) } + + fn resolve_fixed_size_list(&self, element_type: &Type, elements: usize) -> ValueResult { + let element_type = self.resolve_type(*element_type)?; + Ok(value::Type::fixed_size_list(element_type, elements)) + } } #[cfg(test)] diff --git a/crates/wasm-wave/src/wasm/ty.rs b/crates/wasm-wave/src/wasm/ty.rs index e131759cfb..499647a072 100644 --- a/crates/wasm-wave/src/wasm/ty.rs +++ b/crates/wasm-wave/src/wasm/ty.rs @@ -20,6 +20,7 @@ pub enum WasmTypeKind { Char, String, List, + FixedSizeList, Record, Tuple, Variant, @@ -48,6 +49,7 @@ impl std::fmt::Display for WasmTypeKind { WasmTypeKind::Char => "char", WasmTypeKind::String => "string", WasmTypeKind::List => "list", + WasmTypeKind::FixedSizeList => "list<_,N>", WasmTypeKind::Record => "record", WasmTypeKind::Tuple => "tuple", WasmTypeKind::Variant => "variant", diff --git a/crates/wasm-wave/src/writer.rs b/crates/wasm-wave/src/writer.rs index eca4f37a14..4233f359ed 100644 --- a/crates/wasm-wave/src/writer.rs +++ b/crates/wasm-wave/src/writer.rs @@ -75,6 +75,16 @@ impl Writer { } self.write_str("]") } + WasmTypeKind::FixedSizeList => { + self.write_str("[")?; + for (idx, val) in val.unwrap_list().enumerate() { + if idx != 0 { + self.write_str(", ")?; + } + self.write_value(&*val)?; + } + self.write_str("]") + } WasmTypeKind::Record => { self.write_str("{")?; let mut first = true; diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index 5d23a63394..b27a881405 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -440,7 +440,9 @@ pub enum ComponentDefinedType<'a> { /// The type is a variant with the given cases. Variant(Box<[VariantCase<'a>]>), /// The type is a list of the given value type. - List(ComponentValType, Option), + List(ComponentValType), + /// The type is a fixed size list of the given value type. + FixedSizeList(ComponentValType, usize), /// The type is a tuple of the given value types. Tuple(Box<[ComponentValType]>), /// The type is flags with the given names. @@ -479,7 +481,7 @@ impl<'a> ComponentDefinedType<'a> { .read_iter(MAX_WASM_VARIANT_CASES, "variant cases")? .collect::>()?, ), - 0x70 => ComponentDefinedType::List(reader.read()?, None), + 0x70 => ComponentDefinedType::List(reader.read()?), 0x6f => ComponentDefinedType::Tuple( reader .read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")? diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 05efce76bf..a8b4031894 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -724,9 +724,9 @@ impl ComponentState { .map(|t| types.type_named_valtype(t, set)) .unwrap_or(true) } - ComponentDefinedType::List(ty, ..) | ComponentDefinedType::Option(ty) => { - types.type_named_valtype(ty, set) - } + ComponentDefinedType::List(ty) + | ComponentDefinedType::FixedSizeList(ty, _) + | ComponentDefinedType::Option(ty) => types.type_named_valtype(ty, set), // The resource referred to by own/borrow must be named. ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => { @@ -3436,10 +3436,15 @@ impl ComponentState { crate::ComponentDefinedType::Variant(cases) => { self.create_variant_type(cases.as_ref(), types, offset) } - crate::ComponentDefinedType::List(ty, size) => Ok(ComponentDefinedType::List( + crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List( self.create_component_val_type(ty, offset)?, - size, )), + crate::ComponentDefinedType::FixedSizeList(ty, elements) => { + Ok(ComponentDefinedType::FixedSizeList( + self.create_component_val_type(ty, offset)?, + elements, + )) + } crate::ComponentDefinedType::Tuple(tys) => { self.create_tuple_type(tys.as_ref(), types, offset) } diff --git a/crates/wasmparser/src/validator/component_types.rs b/crates/wasmparser/src/validator/component_types.rs index ad2a80ddc9..db440be9e6 100644 --- a/crates/wasmparser/src/validator/component_types.rs +++ b/crates/wasmparser/src/validator/component_types.rs @@ -1083,7 +1083,9 @@ pub enum ComponentDefinedType { /// The type is a variant. Variant(VariantType), /// The type is a list. - List(ComponentValType, Option), + List(ComponentValType), + /// The type is a fixed size list. + FixedSizeList(ComponentValType, usize), /// The type is a tuple. Tuple(TupleType), /// The type is a set of flags. @@ -1124,7 +1126,7 @@ impl TypeData for ComponentDefinedType { Self::Record(r) => r.info, Self::Variant(v) => v.info, Self::Tuple(t) => t.info, - Self::List(ty, ..) | Self::Option(ty) => ty.info(types), + Self::List(ty) | Self::FixedSizeList(ty, _) | Self::Option(ty) => ty.info(types), Self::Result { ok, err } => { let default = TypeInfo::new(); let mut info = ok.map(|ty| ty.type_info(types)).unwrap_or(default); @@ -1145,7 +1147,7 @@ impl ComponentDefinedType { .cases .values() .any(|case| case.ty.map(|ty| ty.contains_ptr(types)).unwrap_or(false)), - Self::List(..) => true, + Self::List(_) => true, Self::Tuple(t) => t.types.iter().any(|ty| ty.contains_ptr(types)), Self::Flags(_) | Self::Enum(_) @@ -1153,7 +1155,7 @@ impl ComponentDefinedType { | Self::Borrow(_) | Self::Future(_) | Self::Stream(_) => false, - Self::Option(ty) => ty.contains_ptr(types), + Self::Option(ty) | Self::FixedSizeList(ty, _) => ty.contains_ptr(types), Self::Result { ok, err } => { ok.map(|ty| ty.contains_ptr(types)).unwrap_or(false) || err.map(|ty| ty.contains_ptr(types)).unwrap_or(false) @@ -1173,10 +1175,8 @@ impl ComponentDefinedType { types, lowered_types, ), - Self::List(_, None) => { - lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32) - } - Self::List(ty, Some(length)) => { + Self::List(_) => lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32), + Self::FixedSizeList(ty, length) => { (0..*length).all(|_n| ty.push_wasm_types(types, lowered_types)) } Self::Tuple(t) => t @@ -1252,7 +1252,7 @@ impl ComponentDefinedType { ComponentDefinedType::Enum(_) => "enum", ComponentDefinedType::Flags(_) => "flags", ComponentDefinedType::Option(_) => "option", - ComponentDefinedType::List(..) => "list", + ComponentDefinedType::List(_) | ComponentDefinedType::FixedSizeList(_, _) => "list", ComponentDefinedType::Result { .. } => "result", ComponentDefinedType::Own(_) => "own", ComponentDefinedType::Borrow(_) => "borrow", @@ -1990,7 +1990,9 @@ impl TypeAlloc { } } } - ComponentDefinedType::List(ty, ..) | ComponentDefinedType::Option(ty) => { + ComponentDefinedType::List(ty) + | ComponentDefinedType::FixedSizeList(ty, _) + | ComponentDefinedType::Option(ty) => { self.free_variables_valtype(ty, set); } ComponentDefinedType::Result { ok, err } => { @@ -2132,9 +2134,9 @@ impl TypeAlloc { .map(|t| self.type_named_valtype(t, set)) .unwrap_or(true) } - ComponentDefinedType::List(ty, ..) | ComponentDefinedType::Option(ty) => { - self.type_named_valtype(ty, set) - } + ComponentDefinedType::List(ty) + | ComponentDefinedType::FixedSizeList(ty, _) + | ComponentDefinedType::Option(ty) => self.type_named_valtype(ty, set), // own/borrow themselves don't have to be named, but the resource // they refer to must be named. @@ -2319,7 +2321,9 @@ where } } } - ComponentDefinedType::List(ty, ..) | ComponentDefinedType::Option(ty) => { + ComponentDefinedType::List(ty) + | ComponentDefinedType::FixedSizeList(ty, _) + | ComponentDefinedType::Option(ty) => { any_changed |= self.remap_valtype(ty, map); } ComponentDefinedType::Result { ok, err } => { @@ -3206,10 +3210,16 @@ impl<'a> SubtypeCx<'a> { Ok(()) } (Variant(_), b) => bail!(offset, "expected {}, found variant", b.desc()), - (List(a, ..), List(b, ..)) | (Option(a), Option(b)) => { - self.component_val_type(a, b, offset) + (List(a), List(b)) | (Option(a), Option(b)) => self.component_val_type(a, b, offset), + (List(_), b) => bail!(offset, "expected {}, found list", b.desc()), + (FixedSizeList(a, asize), FixedSizeList(b, bsize)) => { + if asize != bsize { + bail!(offset, "expected fixed size {bsize}, found size {asize}") + } else { + self.component_val_type(a, b, offset) + } } - (List(_, ..), b) => bail!(offset, "expected {}, found list", b.desc()), + (FixedSizeList(_, _), b) => bail!(offset, "expected {}, found list", b.desc()), (Option(_), b) => bail!(offset, "expected {}, found option", b.desc()), (Tuple(a), Tuple(b)) => { if a.types.len() != b.types.len() { diff --git a/crates/wasmprinter/src/component.rs b/crates/wasmprinter/src/component.rs index cfe8921bf0..f747db242f 100644 --- a/crates/wasmprinter/src/component.rs +++ b/crates/wasmprinter/src/component.rs @@ -169,6 +169,19 @@ impl Printer<'_, '_> { Ok(()) } + pub(crate) fn print_fixed_size_list_type( + &mut self, + state: &State, + element_ty: &ComponentValType, + elements: usize, + ) -> Result<()> { + self.start_group("list ")?; + self.print_component_val_type(state, element_ty)?; + self.result.write_str(&format!(" {elements}"))?; + self.end_group()?; + Ok(()) + } + pub(crate) fn print_tuple_type( &mut self, state: &State, @@ -264,7 +277,10 @@ impl Printer<'_, '_> { ComponentDefinedType::Primitive(ty) => self.print_primitive_val_type(ty)?, ComponentDefinedType::Record(fields) => self.print_record_type(state, fields)?, ComponentDefinedType::Variant(cases) => self.print_variant_type(state, cases)?, - ComponentDefinedType::List(ty, _size) => self.print_list_type(state, ty)?, + ComponentDefinedType::List(ty) => self.print_list_type(state, ty)?, + ComponentDefinedType::FixedSizeList(ty, elements) => { + self.print_fixed_size_list_type(state, ty, *elements)? + } ComponentDefinedType::Tuple(tys) => self.print_tuple_type(state, tys)?, ComponentDefinedType::Flags(names) => self.print_flag_or_enum_type("flags", names)?, ComponentDefinedType::Enum(cases) => self.print_flag_or_enum_type("enum", cases)?, diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 8b92a49354..e85c950b39 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -319,7 +319,8 @@ impl TypeContents { Self::for_optional_types(resolve, v.cases.iter().map(|c| c.ty.as_ref())) } TypeDefKind::Enum(_) => Self::empty(), - TypeDefKind::List(t, ..) => Self::for_type(resolve, t) | Self::LIST, + TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::LIST, + TypeDefKind::FixedSizeList(t, _elements) => Self::for_type(resolve, t) | Self::LIST, TypeDefKind::Type(t) => Self::for_type(resolve, t), TypeDefKind::Future(_) => Self::empty(), TypeDefKind::Stream(_) => Self::empty(), diff --git a/crates/wit-component/src/encoding/types.rs b/crates/wit-component/src/encoding/types.rs index 927b02b287..7b354dc674 100644 --- a/crates/wit-component/src/encoding/types.rs +++ b/crates/wit-component/src/encoding/types.rs @@ -138,12 +138,18 @@ pub trait ValtypeEncoder<'a> { TypeDefKind::Option(t) => self.encode_option(resolve, t)?, TypeDefKind::Result(r) => self.encode_result(resolve, r)?, TypeDefKind::Enum(e) => self.encode_enum(e)?, - TypeDefKind::List(ty, ..) => { + TypeDefKind::List(ty) => { let ty = self.encode_valtype(resolve, ty)?; let (index, encoder) = self.defined_type(); encoder.list(ty); ComponentValType::Type(index) } + TypeDefKind::FixedSizeList(ty, elements) => { + let ty = self.encode_valtype(resolve, ty)?; + let (index, encoder) = self.defined_type(); + encoder.fixed_size_list(ty, *elements); + ComponentValType::Type(index) + } TypeDefKind::Type(ty) => self.encode_valtype(resolve, ty)?, TypeDefKind::Future(ty) => self.encode_future(resolve, ty)?, TypeDefKind::Stream(ty) => self.encode_stream(resolve, ty)?, diff --git a/crates/wit-component/src/printing.rs b/crates/wit-component/src/printing.rs index e9b9595aad..af13e68012 100644 --- a/crates/wit-component/src/printing.rs +++ b/crates/wit-component/src/printing.rs @@ -567,13 +567,17 @@ impl WitPrinter { TypeDefKind::Variant(_) => { bail!("resolve has unnamed variant type") } - TypeDefKind::List(ty, size) => { + TypeDefKind::List(ty) => { self.output.ty("list", TypeKind::BuiltIn); self.output.generic_args_start(); self.print_type_name(resolve, ty)?; - if let Some(size) = size { - self.output.push_str(&format!(", {}", *size)); - } + self.output.generic_args_end(); + } + TypeDefKind::FixedSizeList(ty, size) => { + self.output.ty("list", TypeKind::BuiltIn); + self.output.generic_args_start(); + self.print_type_name(resolve, ty)?; + self.output.push_str(&format!(", {}", *size)); self.output.generic_args_end(); } TypeDefKind::Type(ty) => self.print_type_name(resolve, ty)?, @@ -747,9 +751,12 @@ impl WitPrinter { self.declare_result(resolve, ty.name.as_deref(), r)? } TypeDefKind::Enum(e) => self.declare_enum(ty.name.as_deref(), e)?, - TypeDefKind::List(inner, _size) => { + TypeDefKind::List(inner) => { self.declare_list(resolve, ty.name.as_deref(), inner)? } + TypeDefKind::FixedSizeList(inner, size) => { + self.declare_fixed_size_list(resolve, ty.name.as_deref(), inner, *size)? + } TypeDefKind::Type(inner) => match ty.name.as_deref() { Some(name) => { self.output.keyword("type"); @@ -963,6 +970,30 @@ impl WitPrinter { Ok(()) } + fn declare_fixed_size_list( + &mut self, + resolve: &Resolve, + name: Option<&str>, + ty: &Type, + elements: usize, + ) -> Result<()> { + if let Some(name) = name { + self.output.keyword("type"); + self.output.str(" "); + self.print_name_type(name, TypeKind::List); + self.output.str(" = "); + self.output.ty("list", TypeKind::BuiltIn); + self.output.str("<"); + self.print_type_name(resolve, ty)?; + self.output.str(&format!(", {elements}")); + self.output.str(">"); + self.output.semicolon(); + return Ok(()); + } + + Ok(()) + } + fn declare_stream( &mut self, resolve: &Resolve, diff --git a/crates/wit-encoder/src/from_parser.rs b/crates/wit-encoder/src/from_parser.rs index b4a9a54b05..c275e8a587 100644 --- a/crates/wit-encoder/src/from_parser.rs +++ b/crates/wit-encoder/src/from_parser.rs @@ -239,8 +239,12 @@ impl<'a> Converter<'a> { let output = Type::option(self.convert_type(ty)); TypeDefKind::Type(output) } - wit_parser::TypeDefKind::List(ty, size) => { - let output = Type::list(self.convert_type(ty), *size); + wit_parser::TypeDefKind::List(ty) => { + let output = Type::list(self.convert_type(ty), None); + TypeDefKind::Type(output) + } + wit_parser::TypeDefKind::FixedSizeList(ty, size) => { + let output = Type::list(self.convert_type(ty), Some(*size)); TypeDefKind::Type(output) } wit_parser::TypeDefKind::Handle(handle) => { @@ -301,8 +305,11 @@ impl<'a> Converter<'a> { wit_parser::TypeDefKind::Result(result) => { Type::result(self.convert_result(result)) } - wit_parser::TypeDefKind::List(type_, size) => { - Type::list(self.convert_type(type_), *size) + wit_parser::TypeDefKind::List(type_) => { + Type::list(self.convert_type(type_), None) + } + wit_parser::TypeDefKind::FixedSizeList(type_, size) => { + Type::list(self.convert_type(type_), Some(*size)) } wit_parser::TypeDefKind::Handle(handle) => self.handle_to_type(handle), wit_parser::TypeDefKind::Future(type_) => { diff --git a/crates/wit-parser/src/abi.rs b/crates/wit-parser/src/abi.rs index 89e7bb31ca..9d26a81e56 100644 --- a/crates/wit-parser/src/abi.rs +++ b/crates/wit-parser/src/abi.rs @@ -283,14 +283,14 @@ impl Resolve { } } - TypeDefKind::List(ty, size) => { - if let Some(size) = size { - for _ in 0..*size { - self.push_flat(ty, result); - } - } else { - result.push(WasmType::Pointer); - result.push(WasmType::Length); + TypeDefKind::List(_) => { + result.push(WasmType::Pointer); + result.push(WasmType::Length); + } + + TypeDefKind::FixedSizeList(ty, size) => { + for _ in 0..*size { + self.push_flat(ty, result); } } diff --git a/crates/wit-parser/src/ast/resolve.rs b/crates/wit-parser/src/ast/resolve.rs index b5c1798d6b..18daefe623 100644 --- a/crates/wit-parser/src/ast/resolve.rs +++ b/crates/wit-parser/src/ast/resolve.rs @@ -1172,7 +1172,11 @@ impl<'a> Resolver<'a> { } ast::Type::List(list) => { let ty = self.resolve_type(&list.ty, stability)?; - TypeDefKind::List(ty, list.fixed_size) + if let Some(elements) = list.fixed_size { + TypeDefKind::FixedSizeList(ty, elements) + } else { + TypeDefKind::List(ty) + } } ast::Type::Handle(handle) => TypeDefKind::Handle(match handle { ast::Handle::Own { resource } => Handle::Own(self.validate_resource(resource)?), @@ -1351,7 +1355,9 @@ impl<'a> Resolver<'a> { find_in_type(types, Type::Id(*id)) } TypeDefKind::Tuple(t) => t.types.iter().find_map(|ty| find_in_type(types, *ty)), - TypeDefKind::List(ty, ..) | TypeDefKind::Option(ty) => find_in_type(types, *ty), + TypeDefKind::List(ty) + | TypeDefKind::FixedSizeList(ty, _) + | TypeDefKind::Option(ty) => find_in_type(types, *ty), TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => { ty.as_ref().and_then(|ty| find_in_type(types, *ty)) } @@ -1442,7 +1448,8 @@ impl<'a> Resolver<'a> { TypeDefKind::Enum(r) => { Key::Enum(r.cases.iter().map(|f| f.name.clone()).collect::>()) } - TypeDefKind::List(ty, size) => Key::List(*ty, *size), + TypeDefKind::List(ty) => Key::List(*ty, None), + TypeDefKind::FixedSizeList(ty, size) => Key::List(*ty, Some(*size)), TypeDefKind::Option(t) => Key::Option(*t), TypeDefKind::Result(r) => Key::Result(r.ok, r.err), TypeDefKind::Future(ty) => Key::Future(*ty), diff --git a/crates/wit-parser/src/decoding.rs b/crates/wit-parser/src/decoding.rs index 8d4f20df9a..cdd624559a 100644 --- a/crates/wit-parser/src/decoding.rs +++ b/crates/wit-parser/src/decoding.rs @@ -1253,7 +1253,8 @@ impl WitPackageDecoder<'_> { let kind = self.convert_defined(def)?; match &kind { TypeDefKind::Type(_) - | TypeDefKind::List(..) + | TypeDefKind::List(_) + | TypeDefKind::FixedSizeList(..) | TypeDefKind::Tuple(_) | TypeDefKind::Option(_) | TypeDefKind::Result(_) @@ -1289,9 +1290,14 @@ impl WitPackageDecoder<'_> { match ty { ComponentDefinedType::Primitive(t) => Ok(TypeDefKind::Type(self.convert_primitive(*t))), - ComponentDefinedType::List(t, size) => { + ComponentDefinedType::List(t) => { let t = self.convert_valtype(t)?; - Ok(TypeDefKind::List(t, *size)) + Ok(TypeDefKind::List(t)) + } + + ComponentDefinedType::FixedSizeList(t, size) => { + let t = self.convert_valtype(t)?; + Ok(TypeDefKind::FixedSizeList(t, *size)) } ComponentDefinedType::Tuple(t) => { @@ -1570,9 +1576,9 @@ impl Registrar<'_> { match def { ComponentDefinedType::Primitive(_) => Ok(()), - ComponentDefinedType::List(t, ..) => { + ComponentDefinedType::List(t) => { let ty = match &self.resolve.types[id].kind { - TypeDefKind::List(r, ..) => r, + TypeDefKind::List(r) => r, // Note that all cases below have this match and the general // idea is that once a type is named or otherwise identified // here there's no need to recurse. The purpose of this @@ -1586,6 +1592,22 @@ impl Registrar<'_> { self.valtype(t, ty) } + ComponentDefinedType::FixedSizeList(t, elements) => { + let ty = match &self.resolve.types[id].kind { + TypeDefKind::FixedSizeList(r, elements2) if elements2 == elements => r, + // Note that all cases below have this match and the general + // idea is that once a type is named or otherwise identified + // here there's no need to recurse. The purpose of this + // registrar is to build connections for anonymous types + // that don't otherwise have a name to ensure that they're + // decoded to reuse the same constructs consistently. For + // that reason once something is named we can bail out. + TypeDefKind::Type(Type::Id(_)) => return Ok(()), + _ => bail!("expected a fixed size {elements} list"), + }; + self.valtype(t, ty) + } + ComponentDefinedType::Tuple(t) => { let ty = match &self.resolve.types[id].kind { TypeDefKind::Tuple(r) => r, diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs index e0e51382b3..9c86cb7f67 100644 --- a/crates/wit-parser/src/lib.rs +++ b/crates/wit-parser/src/lib.rs @@ -568,7 +568,8 @@ pub enum TypeDefKind { Enum(Enum), Option(Type), Result(Result_), - List(Type, Option), + List(Type), + FixedSizeList(Type, usize), Future(Option), Stream(Option), Type(Type), @@ -596,7 +597,7 @@ impl TypeDefKind { TypeDefKind::Enum(_) => "enum", TypeDefKind::Option(_) => "option", TypeDefKind::Result(_) => "result", - TypeDefKind::List(..) => "list", + TypeDefKind::List(_) | TypeDefKind::FixedSizeList(..) => "list", TypeDefKind::Future(_) => "future", TypeDefKind::Stream(_) => "stream", TypeDefKind::Type(_) => "type", @@ -1153,7 +1154,10 @@ fn find_futures_and_streams(resolve: &Resolve, ty: Type, results: &mut Vec { + TypeDefKind::Option(ty) + | TypeDefKind::List(ty) + | TypeDefKind::FixedSizeList(ty, ..) + | TypeDefKind::Type(ty) => { find_futures_and_streams(resolve, *ty, results); } TypeDefKind::Result(r) => { diff --git a/crates/wit-parser/src/live.rs b/crates/wit-parser/src/live.rs index 98003bfabd..48637f5444 100644 --- a/crates/wit-parser/src/live.rs +++ b/crates/wit-parser/src/live.rs @@ -131,7 +131,8 @@ pub trait TypeIdVisitor { fn visit_type_def(&mut self, resolve: &Resolve, ty: &TypeDef) { match &ty.kind { TypeDefKind::Type(t) - | TypeDefKind::List(t, ..) + | TypeDefKind::List(t) + | TypeDefKind::FixedSizeList(t, ..) | TypeDefKind::Option(t) | TypeDefKind::Future(Some(t)) | TypeDefKind::Stream(Some(t)) => self.visit_type(resolve, t), diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs index 62a48eaff2..b258ccb9b4 100644 --- a/crates/wit-parser/src/resolve.rs +++ b/crates/wit-parser/src/resolve.rs @@ -566,15 +566,14 @@ package {name} is defined in two different locations:\n\ Type::Bool | Type::Char | Type::String | Type::ErrorContext => false, Type::Id(id) => match &self.types[*id].kind { - TypeDefKind::List(t, Some(_)) => self.all_bits_valid(t), - TypeDefKind::List(_, None) + TypeDefKind::List(_) | TypeDefKind::Variant(_) | TypeDefKind::Enum(_) | TypeDefKind::Option(_) | TypeDefKind::Result(_) | TypeDefKind::Future(_) | TypeDefKind::Stream(_) => false, - TypeDefKind::Type(t) => self.all_bits_valid(t), + TypeDefKind::Type(t) | TypeDefKind::FixedSizeList(t, ..) => self.all_bits_valid(t), TypeDefKind::Handle(h) => match h { crate::Handle::Own(_) => true, @@ -3136,7 +3135,7 @@ impl Remap { } } } - Option(t) | List(t, ..) | Future(Some(t)) | Stream(Some(t)) => { + Option(t) | List(t, ..) | FixedSizeList(t, ..) | Future(Some(t)) | Stream(Some(t)) => { self.update_ty(resolve, t, span)? } Result(r) => { @@ -3522,7 +3521,8 @@ impl Remap { TypeDefKind::Flags(_) => false, TypeDefKind::Tuple(t) => t.types.iter().any(|t| self.type_has_borrow(resolve, t)), TypeDefKind::Enum(_) => false, - TypeDefKind::List(ty, ..) + TypeDefKind::List(ty) + | TypeDefKind::FixedSizeList(ty, ..) | TypeDefKind::Future(Some(ty)) | TypeDefKind::Stream(Some(ty)) | TypeDefKind::Option(ty) => self.type_has_borrow(resolve, ty), diff --git a/crates/wit-parser/src/resolve/clone.rs b/crates/wit-parser/src/resolve/clone.rs index 087fc6c4b4..32bc5bc299 100644 --- a/crates/wit-parser/src/resolve/clone.rs +++ b/crates/wit-parser/src/resolve/clone.rs @@ -109,7 +109,9 @@ impl<'a> Cloner<'a> { TypeDefKind::Handle(Handle::Own(ty) | Handle::Borrow(ty)) => { self.type_id(ty); } - TypeDefKind::Option(ty) | TypeDefKind::List(ty, ..) => { + TypeDefKind::Option(ty) + | TypeDefKind::List(ty) + | TypeDefKind::FixedSizeList(ty, ..) => { self.ty(ty); } TypeDefKind::Tuple(list) => { diff --git a/crates/wit-parser/src/sizealign.rs b/crates/wit-parser/src/sizealign.rs index 268f93866b..2286f1beb7 100644 --- a/crates/wit-parser/src/sizealign.rs +++ b/crates/wit-parser/src/sizealign.rs @@ -260,17 +260,16 @@ impl SizeAlign { fn calculate(&self, ty: &TypeDef) -> ElementInfo { match &ty.kind { TypeDefKind::Type(t) => ElementInfo::new(self.size(t), self.align(t)), - TypeDefKind::List(t, size) => { - if let Some(size) = size { - let field_align = self.align(t); - let field_size = self.size(t); - ElementInfo::new( - ArchitectureSize::new(field_size.bytes * size, field_size.pointers * size), - field_align, - ) - } else { - ElementInfo::new(ArchitectureSize::new(0, 2), Alignment::Pointer) - } + TypeDefKind::FixedSizeList(t, size) => { + let field_align = self.align(t); + let field_size = self.size(t); + ElementInfo::new( + ArchitectureSize::new(field_size.bytes * size, field_size.pointers * size), + field_align, + ) + } + TypeDefKind::List(_) => { + ElementInfo::new(ArchitectureSize::new(0, 2), Alignment::Pointer) } TypeDefKind::Record(r) => self.record(r.fields.iter().map(|f| &f.ty)), TypeDefKind::Tuple(t) => self.record(t.types.iter()), From 5d2e4d8c3ec168d528e314626322a37805684b90 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 9 Feb 2025 17:59:05 +0100 Subject: [PATCH 05/25] adapt the tests for the new type --- .../tests/ui/multi-package-deps.wit.json | 5 +--- crates/wit-parser/tests/ui/random.wit.json | 5 +--- .../wit-parser/tests/ui/shared-types.wit.json | 5 +--- .../tests/ui/streams-and-futures.wit.json | 10 ++----- crates/wit-parser/tests/ui/types.wit.json | 26 +++++-------------- .../tests/ui/world-top-level-funcs.wit.json | 10 ++----- .../ui/world-top-level-resources.wit.json | 5 +--- 7 files changed, 15 insertions(+), 51 deletions(-) diff --git a/crates/wit-parser/tests/ui/multi-package-deps.wit.json b/crates/wit-parser/tests/ui/multi-package-deps.wit.json index 45989fb266..427c1bdf35 100644 --- a/crates/wit-parser/tests/ui/multi-package-deps.wit.json +++ b/crates/wit-parser/tests/ui/multi-package-deps.wit.json @@ -79,10 +79,7 @@ { "name": "l", "kind": { - "list": [ - 3, - null - ] + "list": 3 }, "owner": { "interface": 2 diff --git a/crates/wit-parser/tests/ui/random.wit.json b/crates/wit-parser/tests/ui/random.wit.json index 7c4f4b5267..dcf2178c1c 100644 --- a/crates/wit-parser/tests/ui/random.wit.json +++ b/crates/wit-parser/tests/ui/random.wit.json @@ -39,10 +39,7 @@ { "name": null, "kind": { - "list": [ - "u8", - null - ] + "list": "u8" }, "owner": null } diff --git a/crates/wit-parser/tests/ui/shared-types.wit.json b/crates/wit-parser/tests/ui/shared-types.wit.json index 06142a9d2c..8f53710b99 100644 --- a/crates/wit-parser/tests/ui/shared-types.wit.json +++ b/crates/wit-parser/tests/ui/shared-types.wit.json @@ -51,10 +51,7 @@ { "name": null, "kind": { - "list": [ - "u8", - null - ] + "list": "u8" }, "owner": null }, diff --git a/crates/wit-parser/tests/ui/streams-and-futures.wit.json b/crates/wit-parser/tests/ui/streams-and-futures.wit.json index 7e579e1634..8a0b295308 100644 --- a/crates/wit-parser/tests/ui/streams-and-futures.wit.json +++ b/crates/wit-parser/tests/ui/streams-and-futures.wit.json @@ -72,10 +72,7 @@ { "name": null, "kind": { - "list": [ - "u8", - null - ] + "list": "u8" }, "owner": null }, @@ -174,10 +171,7 @@ { "name": null, "kind": { - "list": [ - "string", - null - ] + "list": "string" }, "owner": null }, diff --git a/crates/wit-parser/tests/ui/types.wit.json b/crates/wit-parser/tests/ui/types.wit.json index 5825d842cb..a8dfbc8136 100644 --- a/crates/wit-parser/tests/ui/types.wit.json +++ b/crates/wit-parser/tests/ui/types.wit.json @@ -183,10 +183,7 @@ { "name": "t12", "kind": { - "list": [ - "char", - null - ] + "list": "char" }, "owner": { "interface": 0 @@ -638,30 +635,21 @@ { "name": null, "kind": { - "list": [ - 33, - null - ] + "list": 33 }, "owner": null }, { "name": null, "kind": { - "list": [ - 44, - null - ] + "list": 44 }, "owner": null }, { "name": "t45", "kind": { - "list": [ - 45, - null - ] + "list": 45 }, "owner": { "interface": 0 @@ -715,7 +703,7 @@ { "name": "t51a", "kind": { - "list": [ + "fixed-size-list": [ "u32", 4 ] @@ -727,7 +715,7 @@ { "name": null, "kind": { - "list": [ + "fixed-size-list": [ "u32", 4 ] @@ -737,7 +725,7 @@ { "name": "t51b", "kind": { - "list": [ + "fixed-size-list": [ 53, 2 ] diff --git a/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json b/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json index b87e1c686d..df491f2349 100644 --- a/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json +++ b/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json @@ -48,10 +48,7 @@ { "name": null, "kind": { - "list": [ - "u32", - null - ] + "list": "u32" }, "owner": null }, @@ -65,10 +62,7 @@ { "name": null, "kind": { - "list": [ - 1, - null - ] + "list": 1 }, "owner": null } diff --git a/crates/wit-parser/tests/ui/world-top-level-resources.wit.json b/crates/wit-parser/tests/ui/world-top-level-resources.wit.json index f59b8a7ea2..0babd96f9b 100644 --- a/crates/wit-parser/tests/ui/world-top-level-resources.wit.json +++ b/crates/wit-parser/tests/ui/world-top-level-resources.wit.json @@ -151,10 +151,7 @@ { "name": null, "kind": { - "list": [ - "u32", - null - ] + "list": "u32" }, "owner": null }, From bd6db9a3ea81f36c36b6b41a1b40f2ff3e5be1f1 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 9 Feb 2025 22:47:29 +0100 Subject: [PATCH 06/25] handle reading correctly --- crates/wasmparser/src/readers/component/types.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index b27a881405..5bbcfb0155 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -482,6 +482,7 @@ impl<'a> ComponentDefinedType<'a> { .collect::>()?, ), 0x70 => ComponentDefinedType::List(reader.read()?), + 0x67 => ComponentDefinedType::FixedSizeList(reader.read()?, reader.read_var_u32()? as usize), 0x6f => ComponentDefinedType::Tuple( reader .read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")? From 4b06d9dc5b8e0f047da8e972cc1dc7457a928b8e Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Mon, 10 Feb 2025 00:08:44 +0100 Subject: [PATCH 07/25] wat parsing --- crates/wasmparser/src/readers/component/types.rs | 4 +++- crates/wast/src/component/binary.rs | 6 +++++- crates/wast/src/component/types.rs | 11 ++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index 5bbcfb0155..8c4b4918d9 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -482,7 +482,9 @@ impl<'a> ComponentDefinedType<'a> { .collect::>()?, ), 0x70 => ComponentDefinedType::List(reader.read()?), - 0x67 => ComponentDefinedType::FixedSizeList(reader.read()?, reader.read_var_u32()? as usize), + 0x67 => { + ComponentDefinedType::FixedSizeList(reader.read()?, reader.read_var_u32()? as usize) + } 0x6f => ComponentDefinedType::Tuple( reader .read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")? diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index b981ee3969..6a2b0179b2 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -107,7 +107,11 @@ fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefin })); } ComponentDefinedType::List(l) => { - encoder.list(l.element.as_ref()); + if let Some(elements) = l.elements { + encoder.fixed_size_list(l.element.as_ref(), elements); + } else { + encoder.list(l.element.as_ref()); + } } ComponentDefinedType::Tuple(t) => { encoder.tuple(t.fields.iter()); diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index 648eb59df1..690d104622 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -584,13 +584,22 @@ impl<'a> Parse<'a> for Refinement<'a> { pub struct List<'a> { /// The element type of the array. pub element: Box>, + /// Optional fixed size + pub elements: Option, } impl<'a> Parse<'a> for List<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; + let tp = parser.parse()?; + let elements = if !parser.is_empty() { + Some(parser.parse::()? as usize) + } else { + None + }; Ok(Self { - element: Box::new(parser.parse()?), + element: Box::new(tp), + elements, }) } } From c7b697c58081acc866b1528c77fac51ca3b45f8d Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Mon, 10 Feb 2025 00:18:42 +0100 Subject: [PATCH 08/25] generate fixed size lists in wit-smith --- crates/wit-smith/src/generate.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/wit-smith/src/generate.rs b/crates/wit-smith/src/generate.rs index f4740a703b..cb309de80b 100644 --- a/crates/wit-smith/src/generate.rs +++ b/crates/wit-smith/src/generate.rs @@ -716,6 +716,7 @@ impl<'a> InterfaceGenerator<'a> { Option, Result, List, + FixedSizeList, Stream, Future, ErrorContext, @@ -797,6 +798,16 @@ impl<'a> InterfaceGenerator<'a> { self.gen_type(u, fuel, dst)?; dst.push_str(">"); } + Kind::FixedSizeList => { + *fuel = match fuel.checked_sub(1) { + Some(fuel) => fuel, + None => continue, + }; + let elements = u.int_in_range(1..=self.config.max_type_parts)?; + dst.push_str("list<"); + self.gen_type(u, fuel, dst)?; + dst.push_str(&format!(", {elements}>")); + } Kind::Result => { *fuel = match fuel.checked_sub(2) { Some(fuel) => fuel, From f1d6efe554b6363ee4d545acf2208e5d213c18a8 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Mon, 10 Feb 2025 00:24:53 +0100 Subject: [PATCH 09/25] proper rustfmt (whitespace change) --- crates/wast/src/component/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index 690d104622..c2c65598c6 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -594,8 +594,8 @@ impl<'a> Parse<'a> for List<'a> { let tp = parser.parse()?; let elements = if !parser.is_empty() { Some(parser.parse::()? as usize) - } else { - None + } else { + None }; Ok(Self { element: Box::new(tp), From b5f54ee7c79ac3fbc251a713635f9c2fdbe044dd Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Tue, 11 Feb 2025 13:22:32 +0100 Subject: [PATCH 10/25] implement Alex' suggetions, part one --- crates/wasm-compose/src/encoding.rs | 2 +- crates/wasm-encoder/src/component/types.rs | 4 ++-- crates/wasm-wave/src/value/ty.rs | 4 ++-- crates/wasm-wave/src/value/wit.rs | 2 +- crates/wasmparser/src/features.rs | 3 ++- crates/wasmparser/src/readers/component/types.rs | 8 +++----- crates/wasmparser/src/validator/component.rs | 6 ++++++ crates/wasmparser/src/validator/component_types.rs | 5 +++-- crates/wasmprinter/src/component.rs | 2 +- crates/wast/src/component/types.rs | 8 ++------ crates/wit-component/src/encoding.rs | 2 +- crates/wit-component/src/printing.rs | 2 +- crates/wit-encoder/src/ty.rs | 4 ++-- crates/wit-parser/src/ast.rs | 4 ++-- crates/wit-parser/src/ast/resolve.rs | 2 +- crates/wit-parser/src/decoding.rs | 7 ------- crates/wit-parser/src/lib.rs | 5 +++-- crates/wit-parser/src/sizealign.rs | 5 ++++- crates/wit-smith/src/generate.rs | 2 +- 19 files changed, 38 insertions(+), 39 deletions(-) diff --git a/crates/wasm-compose/src/encoding.rs b/crates/wasm-compose/src/encoding.rs index 07bdba48d9..7719408c58 100644 --- a/crates/wasm-compose/src/encoding.rs +++ b/crates/wasm-compose/src/encoding.rs @@ -716,7 +716,7 @@ impl<'a> TypeEncoder<'a> { &self, state: &mut TypeState<'a>, ty: ct::ComponentValType, - elements: usize, + elements: u32, ) -> u32 { let ty = self.component_val_type(state, ty); let index = state.cur.encodable.type_count(); diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index 5edf85f224..6d6a8f7b1a 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -594,10 +594,10 @@ impl ComponentDefinedTypeEncoder<'_> { } /// Define a fixed size list type. - pub fn fixed_size_list(self, ty: impl Into, elements: usize) { + pub fn fixed_size_list(self, ty: impl Into, elements: u32) { self.0.push(0x67); ty.into().encode(self.0); - (elements as u32).encode(self.0); + elements.encode(self.0); } /// Define a tuple type. diff --git a/crates/wasm-wave/src/value/ty.rs b/crates/wasm-wave/src/value/ty.rs index 1f74d58f38..852051971e 100644 --- a/crates/wasm-wave/src/value/ty.rs +++ b/crates/wasm-wave/src/value/ty.rs @@ -10,7 +10,7 @@ pub struct Type(pub(super) TypeEnum); pub(super) enum TypeEnum { Simple(SimpleType), List(Arc), - FixedSizeList(Arc, usize), + FixedSizeList(Arc, u32), Record(Arc), Tuple(Arc), Variant(Arc), @@ -57,7 +57,7 @@ impl Type { } /// Returns a list type with the given element type. - pub fn fixed_size_list(element_type: impl Into, elements: usize) -> Self { + pub fn fixed_size_list(element_type: impl Into, elements: u32) -> Self { let element = element_type.into(); Self(TypeEnum::FixedSizeList( Arc::new(ListType { element }), diff --git a/crates/wasm-wave/src/value/wit.rs b/crates/wasm-wave/src/value/wit.rs index 1872b076f9..d0822f9713 100644 --- a/crates/wasm-wave/src/value/wit.rs +++ b/crates/wasm-wave/src/value/wit.rs @@ -149,7 +149,7 @@ impl<'a> TypeResolver<'a> { Ok(value::Type::list(element_type)) } - fn resolve_fixed_size_list(&self, element_type: &Type, elements: usize) -> ValueResult { + fn resolve_fixed_size_list(&self, element_type: &Type, elements: u32) -> ValueResult { let element_type = self.resolve_type(*element_type)?; Ok(value::Type::fixed_size_list(element_type, elements)) } diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index fbe88a38f9..d8e95670e6 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -254,7 +254,8 @@ define_wasm_features! { /// Corresponds to the 📝 character in /// . pub cm_error_context: CM_ERROR_CONTEXT(1 << 30) = false; - } + /// Support for fixed size lists + pub cm_fixed_size_list: COMPONENT_MODEL_FIXED_SIZE_LIST(1 << 31) = false; } impl WasmFeatures { diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index 8c4b4918d9..888a977c95 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -442,7 +442,7 @@ pub enum ComponentDefinedType<'a> { /// The type is a list of the given value type. List(ComponentValType), /// The type is a fixed size list of the given value type. - FixedSizeList(ComponentValType, usize), + FixedSizeList(ComponentValType, u32), /// The type is a tuple of the given value types. Tuple(Box<[ComponentValType]>), /// The type is flags with the given names. @@ -482,9 +482,6 @@ impl<'a> ComponentDefinedType<'a> { .collect::>()?, ), 0x70 => ComponentDefinedType::List(reader.read()?), - 0x67 => { - ComponentDefinedType::FixedSizeList(reader.read()?, reader.read_var_u32()? as usize) - } 0x6f => ComponentDefinedType::Tuple( reader .read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")? @@ -508,8 +505,9 @@ impl<'a> ComponentDefinedType<'a> { }, 0x69 => ComponentDefinedType::Own(reader.read()?), 0x68 => ComponentDefinedType::Borrow(reader.read()?), - 0x65 => ComponentDefinedType::Future(reader.read()?), + 0x67 => ComponentDefinedType::FixedSizeList(reader.read()?, reader.read_var_u32()?), 0x66 => ComponentDefinedType::Stream(reader.read()?), + 0x65 => ComponentDefinedType::Future(reader.read()?), x => return reader.invalid_leading_byte(x, "component defined type"), }) } diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index a8b4031894..54c25e4ee2 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -3440,6 +3440,12 @@ impl ComponentState { self.create_component_val_type(ty, offset)?, )), crate::ComponentDefinedType::FixedSizeList(ty, elements) => { + if !features.cm_fixed_size_list() { + bail!( + offset, + "Fixed size lists require the component model fixed size list feature" + ) + } Ok(ComponentDefinedType::FixedSizeList( self.create_component_val_type(ty, offset)?, elements, diff --git a/crates/wasmparser/src/validator/component_types.rs b/crates/wasmparser/src/validator/component_types.rs index db440be9e6..d06171b480 100644 --- a/crates/wasmparser/src/validator/component_types.rs +++ b/crates/wasmparser/src/validator/component_types.rs @@ -1085,7 +1085,7 @@ pub enum ComponentDefinedType { /// The type is a list. List(ComponentValType), /// The type is a fixed size list. - FixedSizeList(ComponentValType, usize), + FixedSizeList(ComponentValType, u32), /// The type is a tuple. Tuple(TupleType), /// The type is a set of flags. @@ -1252,7 +1252,8 @@ impl ComponentDefinedType { ComponentDefinedType::Enum(_) => "enum", ComponentDefinedType::Flags(_) => "flags", ComponentDefinedType::Option(_) => "option", - ComponentDefinedType::List(_) | ComponentDefinedType::FixedSizeList(_, _) => "list", + ComponentDefinedType::List(_) => "list", + ComponentDefinedType::FixedSizeList(_, _) => "fixed size list", ComponentDefinedType::Result { .. } => "result", ComponentDefinedType::Own(_) => "own", ComponentDefinedType::Borrow(_) => "borrow", diff --git a/crates/wasmprinter/src/component.rs b/crates/wasmprinter/src/component.rs index f747db242f..3198872646 100644 --- a/crates/wasmprinter/src/component.rs +++ b/crates/wasmprinter/src/component.rs @@ -173,7 +173,7 @@ impl Printer<'_, '_> { &mut self, state: &State, element_ty: &ComponentValType, - elements: usize, + elements: u32, ) -> Result<()> { self.start_group("list ")?; self.print_component_val_type(state, element_ty)?; diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index c2c65598c6..6912238569 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -585,18 +585,14 @@ pub struct List<'a> { /// The element type of the array. pub element: Box>, /// Optional fixed size - pub elements: Option, + pub elements: Option, } impl<'a> Parse<'a> for List<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; let tp = parser.parse()?; - let elements = if !parser.is_empty() { - Some(parser.parse::()? as usize) - } else { - None - }; + let elements = parser.parse()?; Ok(Self { element: Box::new(tp), elements, diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index e85c950b39..d9b88c4f21 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -320,7 +320,7 @@ impl TypeContents { } TypeDefKind::Enum(_) => Self::empty(), TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::LIST, - TypeDefKind::FixedSizeList(t, _elements) => Self::for_type(resolve, t) | Self::LIST, + TypeDefKind::FixedSizeList(t, _elements) => Self::for_type(resolve, t), TypeDefKind::Type(t) => Self::for_type(resolve, t), TypeDefKind::Future(_) => Self::empty(), TypeDefKind::Stream(_) => Self::empty(), diff --git a/crates/wit-component/src/printing.rs b/crates/wit-component/src/printing.rs index af13e68012..22669224b8 100644 --- a/crates/wit-component/src/printing.rs +++ b/crates/wit-component/src/printing.rs @@ -975,7 +975,7 @@ impl WitPrinter { resolve: &Resolve, name: Option<&str>, ty: &Type, - elements: usize, + elements: u32, ) -> Result<()> { if let Some(name) = name { self.output.keyword("type"); diff --git a/crates/wit-encoder/src/ty.rs b/crates/wit-encoder/src/ty.rs index d7dc88c92b..09766d0450 100644 --- a/crates/wit-encoder/src/ty.rs +++ b/crates/wit-encoder/src/ty.rs @@ -25,7 +25,7 @@ pub enum Type { Borrow(Ident), Option(Box), Result(Box), - List(Box, Option), + List(Box, Option), Tuple(Tuple), Future(Option>), Stream(Option>), @@ -55,7 +55,7 @@ impl Type { pub fn result_empty() -> Self { Type::Result(Box::new(Result_::empty())) } - pub fn list(type_: Type, size: Option) -> Self { + pub fn list(type_: Type, size: Option) -> Self { Type::List(Box::new(type_), size) } pub fn tuple(types: impl IntoIterator) -> Self { diff --git a/crates/wit-parser/src/ast.rs b/crates/wit-parser/src/ast.rs index 2797324906..26f65bd573 100644 --- a/crates/wit-parser/src/ast.rs +++ b/crates/wit-parser/src/ast.rs @@ -903,7 +903,7 @@ struct Option_<'a> { struct List<'a> { span: Span, ty: Box>, - fixed_size: Option, + fixed_size: Option, } struct Future<'a> { @@ -1371,7 +1371,7 @@ impl<'a> Type<'a> { let size = if tokens.eat(Token::Comma)? { let number = tokens.next()?; if let Some((span, Token::Integer)) = number { - let size: usize = tokens.get_span(span).parse()?; + let size: u32 = tokens.get_span(span).parse()?; Some(size) } else { return Err(err_expected(tokens, "fixed size", number).into()); diff --git a/crates/wit-parser/src/ast/resolve.rs b/crates/wit-parser/src/ast/resolve.rs index 18daefe623..105992709c 100644 --- a/crates/wit-parser/src/ast/resolve.rs +++ b/crates/wit-parser/src/ast/resolve.rs @@ -91,7 +91,7 @@ enum Key { Flags(Vec), Tuple(Vec), Enum(Vec), - List(Type, Option), + List(Type, Option), Option(Type), Result(Option, Option), Future(Option), diff --git a/crates/wit-parser/src/decoding.rs b/crates/wit-parser/src/decoding.rs index cdd624559a..7dce0d1cb1 100644 --- a/crates/wit-parser/src/decoding.rs +++ b/crates/wit-parser/src/decoding.rs @@ -1595,13 +1595,6 @@ impl Registrar<'_> { ComponentDefinedType::FixedSizeList(t, elements) => { let ty = match &self.resolve.types[id].kind { TypeDefKind::FixedSizeList(r, elements2) if elements2 == elements => r, - // Note that all cases below have this match and the general - // idea is that once a type is named or otherwise identified - // here there's no need to recurse. The purpose of this - // registrar is to build connections for anonymous types - // that don't otherwise have a name to ensure that they're - // decoded to reuse the same constructs consistently. For - // that reason once something is named we can bail out. TypeDefKind::Type(Type::Id(_)) => return Ok(()), _ => bail!("expected a fixed size {elements} list"), }; diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs index 9c86cb7f67..5f8aa6c9f4 100644 --- a/crates/wit-parser/src/lib.rs +++ b/crates/wit-parser/src/lib.rs @@ -569,7 +569,7 @@ pub enum TypeDefKind { Option(Type), Result(Result_), List(Type), - FixedSizeList(Type, usize), + FixedSizeList(Type, u32), Future(Option), Stream(Option), Type(Type), @@ -597,7 +597,8 @@ impl TypeDefKind { TypeDefKind::Enum(_) => "enum", TypeDefKind::Option(_) => "option", TypeDefKind::Result(_) => "result", - TypeDefKind::List(_) | TypeDefKind::FixedSizeList(..) => "list", + TypeDefKind::List(_) => "list", + TypeDefKind::FixedSizeList(..) => "fixed size list", TypeDefKind::Future(_) => "future", TypeDefKind::Stream(_) => "stream", TypeDefKind::Type(_) => "type", diff --git a/crates/wit-parser/src/sizealign.rs b/crates/wit-parser/src/sizealign.rs index 2286f1beb7..a9b96dc008 100644 --- a/crates/wit-parser/src/sizealign.rs +++ b/crates/wit-parser/src/sizealign.rs @@ -264,7 +264,10 @@ impl SizeAlign { let field_align = self.align(t); let field_size = self.size(t); ElementInfo::new( - ArchitectureSize::new(field_size.bytes * size, field_size.pointers * size), + ArchitectureSize::new( + field_size.bytes.checked_mul(*size as usize).unwrap(), + field_size.pointers.checked_mul(*size as usize).unwrap(), + ), field_align, ) } diff --git a/crates/wit-smith/src/generate.rs b/crates/wit-smith/src/generate.rs index cb309de80b..30a96e409e 100644 --- a/crates/wit-smith/src/generate.rs +++ b/crates/wit-smith/src/generate.rs @@ -803,7 +803,7 @@ impl<'a> InterfaceGenerator<'a> { Some(fuel) => fuel, None => continue, }; - let elements = u.int_in_range(1..=self.config.max_type_parts)?; + let elements = u.int_in_range(1..=self.config.max_type_parts as u32)?; dst.push_str("list<"); self.gen_type(u, fuel, dst)?; dst.push_str(&format!(", {elements}>")); From 36e2bd8b225cd2b7754e2fdbb983735f809f9632 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Tue, 11 Feb 2025 16:38:59 +0100 Subject: [PATCH 11/25] implement roundtrip tests --- .../component-model/fixed-size-list.wast | 28 ++++++++++++++ .../fixed-size-list.wast | 38 +++++++++++++++++++ .../component-model/fixed-size-list.wast.json | 19 ++++++++++ .../fixed-size-list.wast.json | 17 +++++++++ .../fixed-size-list.wast/0.print | 18 +++++++++ .../fixed-size-list.wast/1.print | 15 ++++++++ 6 files changed, 135 insertions(+) create mode 100644 tests/cli/missing-features/component-model/fixed-size-list.wast create mode 100644 tests/local/component-model/component-model-fixed-size-list/fixed-size-list.wast create mode 100644 tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json create mode 100644 tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast.json create mode 100644 tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/0.print create mode 100644 tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/1.print diff --git a/tests/cli/missing-features/component-model/fixed-size-list.wast b/tests/cli/missing-features/component-model/fixed-size-list.wast new file mode 100644 index 0000000000..08433ec72e --- /dev/null +++ b/tests/cli/missing-features/component-model/fixed-size-list.wast @@ -0,0 +1,28 @@ +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "ret-list") (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "ret-list") (result (list u32 4)) + (canon lift (core func $i "ret-list") (memory $i "memory")) + ) + ) + "Fixed size lists require the component model fixed size list feature (at offset 0x54)" +) + +(assert_invalid + (component + (core module $m + (func (export "param-list") (param i32 i32 i32 i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "param-list") (param "l" (list u32 4)) + (canon lift (core func $i "param-list")) + ) + ) + "Fixed size lists require the component model fixed size list feature" +) diff --git a/tests/local/component-model/component-model-fixed-size-list/fixed-size-list.wast b/tests/local/component-model/component-model-fixed-size-list/fixed-size-list.wast new file mode 100644 index 0000000000..784586cde0 --- /dev/null +++ b/tests/local/component-model/component-model-fixed-size-list/fixed-size-list.wast @@ -0,0 +1,38 @@ +(component + (core module $m + (memory (export "memory") 1) + (func (export "ret-list") (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "ret-list") (result (list u32 4)) + (canon lift (core func $i "ret-list") (memory $i "memory")) + ) +) + +(component + (core module $m + (func (export "param-list") (param i32 i32 i32 i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "param-list") (param "l" (list u32 4)) + (canon lift (core func $i "param-list")) + ) +) + +;; no easy way to check for an invalid u32? +;;(assert_invalid +;; (component +;; (core module $m +;; (memory (export "memory") 1) +;; (func (export "ret-list") (result i32) unreachable) +;; ) +;; (core instance $i (instantiate $m)) +;; +;; (func (export "ret-list") (result (list u32 10000000000)) +;; (canon lift (core func $i "ret-list") (memory $i "memory")) +;; ) +;; ) +;; "invalid u32 number: constant out of range" +;;) diff --git a/tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json b/tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json new file mode 100644 index 0000000000..ee56c16daa --- /dev/null +++ b/tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json @@ -0,0 +1,19 @@ +{ + "source_filename": "tests/local/missing-features/component-model/fixed-size-list.wast", + "commands": [ + { + "type": "assert_invalid", + "line": 2, + "filename": "fixed-size-list.0.wasm", + "module_type": "binary", + "text": "Fixed size lists require the component model fixed size list feature (at offset 0x54)" + }, + { + "type": "assert_invalid", + "line": 17, + "filename": "fixed-size-list.1.wasm", + "module_type": "binary", + "text": "Fixed size lists require the component model fixed size list feature" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast.json b/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast.json new file mode 100644 index 0000000000..8488e9b758 --- /dev/null +++ b/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast.json @@ -0,0 +1,17 @@ +{ + "source_filename": "tests/local/component-model/component-model-fixed-size-list/fixed-size-list.wast", + "commands": [ + { + "type": "module", + "line": 1, + "filename": "fixed-size-list.0.wasm", + "module_type": "binary" + }, + { + "type": "module", + "line": 13, + "filename": "fixed-size-list.1.wasm", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/0.print b/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/0.print new file mode 100644 index 0000000000..79848d6748 --- /dev/null +++ b/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/0.print @@ -0,0 +1,18 @@ +(component + (core module $m (;0;) + (type (;0;) (func (result i32))) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "ret-list" (func 0)) + (func (;0;) (type 0) (result i32) + unreachable + ) + ) + (core instance $i (;0;) (instantiate $m)) + (type (;0;) (list u32 4)) + (type (;1;) (func (result 0))) + (alias core export $i "ret-list" (core func (;0;))) + (alias core export $i "memory" (core memory (;0;))) + (func (;0;) (type 1) (canon lift (core func 0) (memory 0))) + (export (;1;) "ret-list" (func 0)) +) diff --git a/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/1.print b/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/1.print new file mode 100644 index 0000000000..ee75456d39 --- /dev/null +++ b/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/1.print @@ -0,0 +1,15 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32 i32 i32 i32))) + (export "param-list" (func 0)) + (func (;0;) (type 0) (param i32 i32 i32 i32) + unreachable + ) + ) + (core instance $i (;0;) (instantiate $m)) + (type (;0;) (list u32 4)) + (type (;1;) (func (param "l" 0))) + (alias core export $i "param-list" (core func (;0;))) + (func (;0;) (type 1) (canon lift (core func 0))) + (export (;1;) "param-list" (func 0)) +) From 2abd0f8d3ec2c4284c12ca91573e3fc1e1b31c68 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 9 Mar 2025 14:50:13 +0100 Subject: [PATCH 12/25] limit the maximum size of a fixed list. to avoid memory explosion at parsing --- crates/wasmparser/src/validator/component_types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/wasmparser/src/validator/component_types.rs b/crates/wasmparser/src/validator/component_types.rs index d06171b480..c9757dfded 100644 --- a/crates/wasmparser/src/validator/component_types.rs +++ b/crates/wasmparser/src/validator/component_types.rs @@ -1177,7 +1177,7 @@ impl ComponentDefinedType { ), Self::List(_) => lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32), Self::FixedSizeList(ty, length) => { - (0..*length).all(|_n| ty.push_wasm_types(types, lowered_types)) + (0..(*length).min(8192)).all(|_n| ty.push_wasm_types(types, lowered_types)) } Self::Tuple(t) => t .types From 0b8d062ab63bd8a74554412a1c2a41cefd50b4b5 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 9 Mar 2025 14:57:17 +0100 Subject: [PATCH 13/25] separate list types, as proposed by Alex --- crates/wit-parser/src/ast/resolve.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/wit-parser/src/ast/resolve.rs b/crates/wit-parser/src/ast/resolve.rs index 105992709c..9b4739bc56 100644 --- a/crates/wit-parser/src/ast/resolve.rs +++ b/crates/wit-parser/src/ast/resolve.rs @@ -91,7 +91,8 @@ enum Key { Flags(Vec), Tuple(Vec), Enum(Vec), - List(Type, Option), + List(Type), + FixedSizeList(Type, u32), Option(Type), Result(Option, Option), Future(Option), @@ -1448,8 +1449,8 @@ impl<'a> Resolver<'a> { TypeDefKind::Enum(r) => { Key::Enum(r.cases.iter().map(|f| f.name.clone()).collect::>()) } - TypeDefKind::List(ty) => Key::List(*ty, None), - TypeDefKind::FixedSizeList(ty, size) => Key::List(*ty, Some(*size)), + TypeDefKind::List(ty) => Key::List(*ty), + TypeDefKind::FixedSizeList(ty, size) => Key::FixedSizeList(*ty, *size), TypeDefKind::Option(t) => Key::Option(*t), TypeDefKind::Result(r) => Key::Result(r.ok, r.err), TypeDefKind::Future(ty) => Key::Future(*ty), From 4b30b54dd075ac5ffc35c3ba38d8c04a6b909261 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Wed, 2 Apr 2025 22:49:04 +0200 Subject: [PATCH 14/25] post-rebase fixes --- crates/wasmparser/src/features.rs | 1 + crates/wasmparser/src/validator/component.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index d8e95670e6..b09e823442 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -256,6 +256,7 @@ define_wasm_features! { pub cm_error_context: CM_ERROR_CONTEXT(1 << 30) = false; /// Support for fixed size lists pub cm_fixed_size_list: COMPONENT_MODEL_FIXED_SIZE_LIST(1 << 31) = false; + } } impl WasmFeatures { diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 54c25e4ee2..6e5bfe06e5 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -3440,7 +3440,7 @@ impl ComponentState { self.create_component_val_type(ty, offset)?, )), crate::ComponentDefinedType::FixedSizeList(ty, elements) => { - if !features.cm_fixed_size_list() { + if !self.features.cm_fixed_size_list() { bail!( offset, "Fixed size lists require the component model fixed size list feature" From cca37334e7487c590c05fc0bdc894af869d1f965 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Wed, 2 Apr 2025 23:07:19 +0200 Subject: [PATCH 15/25] fix the tests --- crates/wasmparser/src/features.rs | 2 +- .../missing-features/component-model/fixed-size-list.wast | 2 ++ tests/cli/validate-unknown-features.wat.stderr | 2 +- .../fixed-size-list.wast.json | 2 +- .../fixed-size-list.wast/0.print | 0 .../fixed-size-list.wast/1.print | 0 .../component-model/fixed-size-list.wast.json | 6 +++--- 7 files changed, 8 insertions(+), 6 deletions(-) rename tests/snapshots/{local/component-model => cli}/component-model-fixed-size-list/fixed-size-list.wast.json (72%) rename tests/snapshots/{local/component-model => cli}/component-model-fixed-size-list/fixed-size-list.wast/0.print (100%) rename tests/snapshots/{local/component-model => cli}/component-model-fixed-size-list/fixed-size-list.wast/1.print (100%) diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index b09e823442..f60b04019b 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -255,7 +255,7 @@ define_wasm_features! { /// . pub cm_error_context: CM_ERROR_CONTEXT(1 << 30) = false; /// Support for fixed size lists - pub cm_fixed_size_list: COMPONENT_MODEL_FIXED_SIZE_LIST(1 << 31) = false; + pub cm_fixed_size_list: CM_FIXED_SIZE_LIST(1 << 31) = false; } } diff --git a/tests/cli/missing-features/component-model/fixed-size-list.wast b/tests/cli/missing-features/component-model/fixed-size-list.wast index 08433ec72e..ebc4eca1f8 100644 --- a/tests/cli/missing-features/component-model/fixed-size-list.wast +++ b/tests/cli/missing-features/component-model/fixed-size-list.wast @@ -1,3 +1,5 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % -f=-cm-fixed-size-list + (assert_invalid (component (core module $m diff --git a/tests/cli/validate-unknown-features.wat.stderr b/tests/cli/validate-unknown-features.wat.stderr index 1c6e4539c4..6c52f3ea8b 100644 --- a/tests/cli/validate-unknown-features.wat.stderr +++ b/tests/cli/validate-unknown-features.wat.stderr @@ -1,4 +1,4 @@ error: invalid value 'unknown' for '--features ': unknown feature `unknown` -Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, legacy-exceptions, gc-types, stack-switching, wide-arithmetic, cm-values, cm-nested-names, cm-async, cm-async-stackful, cm-async-builtins, cm-error-context, mvp, wasm1, wasm2, wasm3, all +Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, legacy-exceptions, gc-types, stack-switching, wide-arithmetic, cm-values, cm-nested-names, cm-async, cm-async-stackful, cm-async-builtins, cm-error-context, cm-fixed-size-list, mvp, wasm1, wasm2, wasm3, all For more information, try '--help'. diff --git a/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast.json b/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast.json similarity index 72% rename from tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast.json rename to tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast.json index 8488e9b758..88bc8c2fd0 100644 --- a/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast.json +++ b/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast.json @@ -1,5 +1,5 @@ { - "source_filename": "tests/local/component-model/component-model-fixed-size-list/fixed-size-list.wast", + "source_filename": "tests/cli/component-model/component-model-fixed-size-list/fixed-size-list.wast", "commands": [ { "type": "module", diff --git a/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/0.print b/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/0.print similarity index 100% rename from tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/0.print rename to tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/0.print diff --git a/tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/1.print b/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/1.print similarity index 100% rename from tests/snapshots/local/component-model/component-model-fixed-size-list/fixed-size-list.wast/1.print rename to tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/1.print diff --git a/tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json b/tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json index ee56c16daa..d91233361d 100644 --- a/tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json +++ b/tests/snapshots/cli/missing-features/component-model/fixed-size-list.wast.json @@ -1,16 +1,16 @@ { - "source_filename": "tests/local/missing-features/component-model/fixed-size-list.wast", + "source_filename": "tests/cli/missing-features/component-model/fixed-size-list.wast", "commands": [ { "type": "assert_invalid", - "line": 2, + "line": 4, "filename": "fixed-size-list.0.wasm", "module_type": "binary", "text": "Fixed size lists require the component model fixed size list feature (at offset 0x54)" }, { "type": "assert_invalid", - "line": 17, + "line": 19, "filename": "fixed-size-list.1.wasm", "module_type": "binary", "text": "Fixed size lists require the component model fixed size list feature" From 879702bc6e8b5472f9d65782691589f2bd85ac53 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 12 Mar 2025 15:41:21 -0700 Subject: [PATCH 16/25] Move local test to CLI test --- .../component-model}/fixed-size-list.wast | 2 ++ .../component-model/fixed-size-list.wast.json | 17 +++++++++++++++++ .../fixed-size-list.wast/0.print | 18 ++++++++++++++++++ .../fixed-size-list.wast/1.print | 15 +++++++++++++++ 4 files changed, 52 insertions(+) rename tests/{local/component-model/component-model-fixed-size-list => cli/component-model}/fixed-size-list.wast (92%) create mode 100644 tests/snapshots/cli/component-model/fixed-size-list.wast.json create mode 100644 tests/snapshots/cli/component-model/fixed-size-list.wast/0.print create mode 100644 tests/snapshots/cli/component-model/fixed-size-list.wast/1.print diff --git a/tests/local/component-model/component-model-fixed-size-list/fixed-size-list.wast b/tests/cli/component-model/fixed-size-list.wast similarity index 92% rename from tests/local/component-model/component-model-fixed-size-list/fixed-size-list.wast rename to tests/cli/component-model/fixed-size-list.wast index 784586cde0..2587942af8 100644 --- a/tests/local/component-model/component-model-fixed-size-list/fixed-size-list.wast +++ b/tests/cli/component-model/fixed-size-list.wast @@ -1,3 +1,5 @@ +;; RUN: wast % --assert default --snapshot tests/snapshots -f cm-fixed-size-list + (component (core module $m (memory (export "memory") 1) diff --git a/tests/snapshots/cli/component-model/fixed-size-list.wast.json b/tests/snapshots/cli/component-model/fixed-size-list.wast.json new file mode 100644 index 0000000000..67c98a6d2b --- /dev/null +++ b/tests/snapshots/cli/component-model/fixed-size-list.wast.json @@ -0,0 +1,17 @@ +{ + "source_filename": "tests/cli/component-model/fixed-size-list.wast", + "commands": [ + { + "type": "module", + "line": 3, + "filename": "fixed-size-list.0.wasm", + "module_type": "binary" + }, + { + "type": "module", + "line": 15, + "filename": "fixed-size-list.1.wasm", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/cli/component-model/fixed-size-list.wast/0.print b/tests/snapshots/cli/component-model/fixed-size-list.wast/0.print new file mode 100644 index 0000000000..79848d6748 --- /dev/null +++ b/tests/snapshots/cli/component-model/fixed-size-list.wast/0.print @@ -0,0 +1,18 @@ +(component + (core module $m (;0;) + (type (;0;) (func (result i32))) + (memory (;0;) 1) + (export "memory" (memory 0)) + (export "ret-list" (func 0)) + (func (;0;) (type 0) (result i32) + unreachable + ) + ) + (core instance $i (;0;) (instantiate $m)) + (type (;0;) (list u32 4)) + (type (;1;) (func (result 0))) + (alias core export $i "ret-list" (core func (;0;))) + (alias core export $i "memory" (core memory (;0;))) + (func (;0;) (type 1) (canon lift (core func 0) (memory 0))) + (export (;1;) "ret-list" (func 0)) +) diff --git a/tests/snapshots/cli/component-model/fixed-size-list.wast/1.print b/tests/snapshots/cli/component-model/fixed-size-list.wast/1.print new file mode 100644 index 0000000000..ee75456d39 --- /dev/null +++ b/tests/snapshots/cli/component-model/fixed-size-list.wast/1.print @@ -0,0 +1,15 @@ +(component + (core module $m (;0;) + (type (;0;) (func (param i32 i32 i32 i32))) + (export "param-list" (func 0)) + (func (;0;) (type 0) (param i32 i32 i32 i32) + unreachable + ) + ) + (core instance $i (;0;) (instantiate $m)) + (type (;0;) (list u32 4)) + (type (;1;) (func (param "l" 0))) + (alias core export $i "param-list" (core func (;0;))) + (func (;0;) (type 1) (canon lift (core func 0))) + (export (;1;) "param-list" (func 0)) +) From 1fc9e727a0c51e9687310fa68ba89f792f051497 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Wed, 2 Apr 2025 23:12:17 +0200 Subject: [PATCH 17/25] use same command line order as proposed by Alex --- tests/cli/missing-features/component-model/fixed-size-list.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cli/missing-features/component-model/fixed-size-list.wast b/tests/cli/missing-features/component-model/fixed-size-list.wast index ebc4eca1f8..d28d0d6081 100644 --- a/tests/cli/missing-features/component-model/fixed-size-list.wast +++ b/tests/cli/missing-features/component-model/fixed-size-list.wast @@ -1,4 +1,4 @@ -;; RUN: wast --assert default --snapshot tests/snapshots % -f=-cm-fixed-size-list +;; RUN: wast % --assert default --snapshot tests/snapshots -f=-cm-fixed-size-list (assert_invalid (component From 0bfcb28e9cfaa275dd010516776f019c4c3ea61c Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Wed, 2 Apr 2025 23:31:12 +0200 Subject: [PATCH 18/25] prefer the name chosen by Alex --- .../fixed-size-list.wast.json | 17 ----------------- .../fixed-size-list.wast/0.print | 18 ------------------ .../fixed-size-list.wast/1.print | 15 --------------- 3 files changed, 50 deletions(-) delete mode 100644 tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast.json delete mode 100644 tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/0.print delete mode 100644 tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/1.print diff --git a/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast.json b/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast.json deleted file mode 100644 index 88bc8c2fd0..0000000000 --- a/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "source_filename": "tests/cli/component-model/component-model-fixed-size-list/fixed-size-list.wast", - "commands": [ - { - "type": "module", - "line": 1, - "filename": "fixed-size-list.0.wasm", - "module_type": "binary" - }, - { - "type": "module", - "line": 13, - "filename": "fixed-size-list.1.wasm", - "module_type": "binary" - } - ] -} \ No newline at end of file diff --git a/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/0.print b/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/0.print deleted file mode 100644 index 79848d6748..0000000000 --- a/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/0.print +++ /dev/null @@ -1,18 +0,0 @@ -(component - (core module $m (;0;) - (type (;0;) (func (result i32))) - (memory (;0;) 1) - (export "memory" (memory 0)) - (export "ret-list" (func 0)) - (func (;0;) (type 0) (result i32) - unreachable - ) - ) - (core instance $i (;0;) (instantiate $m)) - (type (;0;) (list u32 4)) - (type (;1;) (func (result 0))) - (alias core export $i "ret-list" (core func (;0;))) - (alias core export $i "memory" (core memory (;0;))) - (func (;0;) (type 1) (canon lift (core func 0) (memory 0))) - (export (;1;) "ret-list" (func 0)) -) diff --git a/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/1.print b/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/1.print deleted file mode 100644 index ee75456d39..0000000000 --- a/tests/snapshots/cli/component-model-fixed-size-list/fixed-size-list.wast/1.print +++ /dev/null @@ -1,15 +0,0 @@ -(component - (core module $m (;0;) - (type (;0;) (func (param i32 i32 i32 i32))) - (export "param-list" (func 0)) - (func (;0;) (type 0) (param i32 i32 i32 i32) - unreachable - ) - ) - (core instance $i (;0;) (instantiate $m)) - (type (;0;) (list u32 4)) - (type (;1;) (func (param "l" 0))) - (alias core export $i "param-list" (core func (;0;))) - (func (;0;) (type 1) (canon lift (core func 0))) - (export (;1;) "param-list" (func 0)) -) From e7b59522407bb8e934d694812f05274bacd1dfac Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Wed, 2 Apr 2025 23:48:03 +0200 Subject: [PATCH 19/25] apply missing changes by Alex (I should have fetched before rebase) --- crates/wasmparser/src/features.rs | 3 +++ .../cli/missing-features/component-model/fixed-size-list.wast | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index f60b04019b..c0d5e8e0c6 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -255,6 +255,9 @@ define_wasm_features! { /// . pub cm_error_context: CM_ERROR_CONTEXT(1 << 30) = false; /// Support for fixed size lists + /// + /// Corresponds to the 🔧 character in + /// . pub cm_fixed_size_list: CM_FIXED_SIZE_LIST(1 << 31) = false; } } diff --git a/tests/cli/missing-features/component-model/fixed-size-list.wast b/tests/cli/missing-features/component-model/fixed-size-list.wast index d28d0d6081..b6a92ada29 100644 --- a/tests/cli/missing-features/component-model/fixed-size-list.wast +++ b/tests/cli/missing-features/component-model/fixed-size-list.wast @@ -1,4 +1,4 @@ -;; RUN: wast % --assert default --snapshot tests/snapshots -f=-cm-fixed-size-list +;; RUN: wast % --assert default --snapshot tests/snapshots (assert_invalid (component From bc48583670432219d1dc59225f5dac58d24a20d4 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 27 Apr 2025 12:18:29 +0200 Subject: [PATCH 20/25] limit the size of flattened fixed size lists, forbid empty ones --- crates/wasmparser/src/validator/component.rs | 3 +++ .../wasmparser/src/validator/component_types.rs | 5 ++++- crates/wit-parser/src/abi.rs | 15 +++++++++------ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index b12996864c..8436110797 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -3482,6 +3482,9 @@ impl ComponentState { "Fixed size lists require the component model fixed size list feature" ) } + if elements < 1 { + bail!(offset, "Fixed size lists must have more than zero elements") + } Ok(ComponentDefinedType::FixedSizeList( self.create_component_val_type(ty, offset)?, elements, diff --git a/crates/wasmparser/src/validator/component_types.rs b/crates/wasmparser/src/validator/component_types.rs index c9757dfded..2f14b37134 100644 --- a/crates/wasmparser/src/validator/component_types.rs +++ b/crates/wasmparser/src/validator/component_types.rs @@ -1177,7 +1177,10 @@ impl ComponentDefinedType { ), Self::List(_) => lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32), Self::FixedSizeList(ty, length) => { - (0..(*length).min(8192)).all(|_n| ty.push_wasm_types(types, lowered_types)) + if *length as usize > lowered_types.max { + return false; + } + (0..*length).all(|_n| ty.push_wasm_types(types, lowered_types)) } Self::Tuple(t) => t .types diff --git a/crates/wit-parser/src/abi.rs b/crates/wit-parser/src/abi.rs index 8a83f4dc5a..de1bb745a6 100644 --- a/crates/wit-parser/src/abi.rs +++ b/crates/wit-parser/src/abi.rs @@ -133,6 +133,9 @@ pub enum AbiVariant { } impl Resolve { + const MAX_FLAT_PARAMS: usize = 16; + const MAX_FLAT_RESULTS: usize = 1; + /// Get the WebAssembly type signature for this interface function /// /// The first entry returned is the list of parameters and the second entry @@ -147,16 +150,13 @@ impl Resolve { }; } - const MAX_FLAT_PARAMS: usize = 16; - const MAX_FLAT_RESULTS: usize = 1; - let mut params = Vec::new(); let mut indirect_params = false; for (_, param) in func.params.iter() { self.push_flat(param, &mut params); } - if params.len() > MAX_FLAT_PARAMS { + if params.len() > Self::MAX_FLAT_PARAMS { params.truncate(0); params.push(WasmType::Pointer); indirect_params = true; @@ -212,7 +212,7 @@ impl Resolve { // would have multiple results then instead truncate it. Imports take a // return pointer to write into and exports return a pointer they wrote // into. - if results.len() > MAX_FLAT_RESULTS { + if results.len() > Self::MAX_FLAT_RESULTS { retptr = true; results.truncate(0); match variant { @@ -289,7 +289,10 @@ impl Resolve { } TypeDefKind::FixedSizeList(ty, size) => { - for _ in 0..*size { + for _ in 0..usize::try_from(*size) + .unwrap_or(Self::MAX_FLAT_PARAMS) + .min(Self::MAX_FLAT_PARAMS) + { self.push_flat(ty, result); } } From 62fa3b758dfc0283a3fa6095b0bdc4b455af9be0 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 27 Apr 2025 12:52:38 +0200 Subject: [PATCH 21/25] test for zero and too high number --- .../cli/component-model/fixed-size-list.wast | 44 ++++++++++++------- .../component-model/fixed-size-list.wast.json | 14 ++++++ 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/tests/cli/component-model/fixed-size-list.wast b/tests/cli/component-model/fixed-size-list.wast index 2587942af8..f2488526ed 100644 --- a/tests/cli/component-model/fixed-size-list.wast +++ b/tests/cli/component-model/fixed-size-list.wast @@ -23,18 +23,32 @@ ) ) -;; no easy way to check for an invalid u32? -;;(assert_invalid -;; (component -;; (core module $m -;; (memory (export "memory") 1) -;; (func (export "ret-list") (result i32) unreachable) -;; ) -;; (core instance $i (instantiate $m)) -;; -;; (func (export "ret-list") (result (list u32 10000000000)) -;; (canon lift (core func $i "ret-list") (memory $i "memory")) -;; ) -;; ) -;; "invalid u32 number: constant out of range" -;;) +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "ret-list") (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "ret-list") (result (list u32 0)) + (canon lift (core func $i "ret-list") (memory $i "memory")) + ) + ) + "Fixed size lists must have more than zero elements (at offset 0x54)" +) + +(assert_malformed + (component quote + "(core module $m" + "(memory (export \"memory\") 1)" + "(func (export \"ret-list\") (result i32) unreachable)" + ")" + "(core instance $i (instantiate $m))" + + "(func (export \"ret-list\") (result (list u32 10000000000))" + "(canon lift (core func $i \"ret-list\") (memory $i \"memory\"))" + ")" + ) + "invalid u32 number: constant out of range" +) diff --git a/tests/snapshots/cli/component-model/fixed-size-list.wast.json b/tests/snapshots/cli/component-model/fixed-size-list.wast.json index 67c98a6d2b..d5297a84c9 100644 --- a/tests/snapshots/cli/component-model/fixed-size-list.wast.json +++ b/tests/snapshots/cli/component-model/fixed-size-list.wast.json @@ -12,6 +12,20 @@ "line": 15, "filename": "fixed-size-list.1.wasm", "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 27, + "filename": "fixed-size-list.2.wasm", + "module_type": "binary", + "text": "Fixed size lists must have more than zero elements (at offset 0x54)" + }, + { + "type": "assert_malformed", + "line": 42, + "filename": "fixed-size-list.3.wat", + "module_type": "text", + "text": "invalid u32 number: constant out of range" } ] } \ No newline at end of file From 1a6ac1e47bd8e8dce155ea210a44964cec0634de Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 27 Apr 2025 14:35:40 +0200 Subject: [PATCH 22/25] check for type mismatch during composition --- .../cli/component-model/fixed-size-list.wast | 25 +++++++++++++++++++ .../component-model/fixed-size-list.wast.json | 14 +++++++++++ 2 files changed, 39 insertions(+) diff --git a/tests/cli/component-model/fixed-size-list.wast b/tests/cli/component-model/fixed-size-list.wast index f2488526ed..63b8943f11 100644 --- a/tests/cli/component-model/fixed-size-list.wast +++ b/tests/cli/component-model/fixed-size-list.wast @@ -52,3 +52,28 @@ ) "invalid u32 number: constant out of range" ) + +(assert_invalid + (component + (import "y" (component $c + (type $t (list s32 10)) + (import "x" (type (eq $t))) + )) + + (type $x (list u32 9)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch for import `x`") + + +(assert_invalid + (component + (import "y" (component $c + (type $t (list s32 10)) + (import "x" (type (eq $t))) + )) + + (type $x (list u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch for import `x`") diff --git a/tests/snapshots/cli/component-model/fixed-size-list.wast.json b/tests/snapshots/cli/component-model/fixed-size-list.wast.json index d5297a84c9..2d7c8c444c 100644 --- a/tests/snapshots/cli/component-model/fixed-size-list.wast.json +++ b/tests/snapshots/cli/component-model/fixed-size-list.wast.json @@ -26,6 +26,20 @@ "filename": "fixed-size-list.3.wat", "module_type": "text", "text": "invalid u32 number: constant out of range" + }, + { + "type": "assert_invalid", + "line": 57, + "filename": "fixed-size-list.4.wasm", + "module_type": "binary", + "text": "type mismatch for import `x`" + }, + { + "type": "assert_invalid", + "line": 70, + "filename": "fixed-size-list.5.wasm", + "module_type": "binary", + "text": "type mismatch for import `x`" } ] } \ No newline at end of file From bf43b1095cd6bf7d338be59b9a3521b9c6189f60 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 27 Apr 2025 15:43:57 +0200 Subject: [PATCH 23/25] clearly separate list from fixed-size-list in code --- crates/wast/src/component/binary.rs | 9 ++++---- crates/wast/src/component/expand.rs | 5 +++-- crates/wast/src/component/resolve.rs | 5 +++-- crates/wast/src/component/types.rs | 31 +++++++++++++++++---------- crates/wit-encoder/src/from_parser.rs | 8 +++---- crates/wit-encoder/src/ty.rs | 21 ++++++++++-------- 6 files changed, 46 insertions(+), 33 deletions(-) diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index 9ed03fa011..b80455f660 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -107,11 +107,10 @@ fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefin })); } ComponentDefinedType::List(l) => { - if let Some(elements) = l.elements { - encoder.fixed_size_list(l.element.as_ref(), elements); - } else { - encoder.list(l.element.as_ref()); - } + encoder.list(l.element.as_ref()); + } + ComponentDefinedType::FixedSizeList(l) => { + encoder.fixed_size_list(l.element.as_ref(), l.elements); } ComponentDefinedType::Tuple(t) => { encoder.tuple(t.fields.iter()); diff --git a/crates/wast/src/component/expand.rs b/crates/wast/src/component/expand.rs index 01b00d7038..a76fb57763 100644 --- a/crates/wast/src/component/expand.rs +++ b/crates/wast/src/component/expand.rs @@ -532,8 +532,9 @@ impl<'a> Expander<'a> { } } } - ComponentDefinedType::List(t) => { - self.expand_component_val_ty(&mut t.element); + ComponentDefinedType::List(List{element: t}) + | ComponentDefinedType::FixedSizeList(FixedSizeList{element: t, elements :_}) => { + self.expand_component_val_ty(t); } ComponentDefinedType::Tuple(t) => { for field in t.fields.iter_mut() { diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index 21c0e56bda..56344e7fc5 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -547,8 +547,9 @@ impl<'a> Resolver<'a> { } } } - ComponentDefinedType::List(l) => { - self.component_val_type(&mut l.element)?; + ComponentDefinedType::List(List{element: t}) + | ComponentDefinedType::FixedSizeList(FixedSizeList{element: t, elements :_}) => { + self.component_val_type(t)?; } ComponentDefinedType::Tuple(t) => { for field in t.fields.iter_mut() { diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index 6912238569..a39e7f8d1a 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -386,6 +386,7 @@ pub enum ComponentDefinedType<'a> { Record(Record<'a>), Variant(Variant<'a>), List(List<'a>), + FixedSizeList(FixedSizeList<'a>), Tuple(Tuple<'a>), Flags(Flags<'a>), Enum(Enum<'a>), @@ -405,7 +406,7 @@ impl<'a> ComponentDefinedType<'a> { } else if l.peek::()? { Ok(Self::Variant(parser.parse()?)) } else if l.peek::()? { - Ok(Self::List(parser.parse()?)) + parse_list(parser) } else if l.peek::()? { Ok(Self::Tuple(parser.parse()?)) } else if l.peek::()? { @@ -584,19 +585,27 @@ impl<'a> Parse<'a> for Refinement<'a> { pub struct List<'a> { /// The element type of the array. pub element: Box>, - /// Optional fixed size - pub elements: Option, } -impl<'a> Parse<'a> for List<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let tp = parser.parse()?; - let elements = parser.parse()?; - Ok(Self { +/// A fixed size list type. +#[derive(Debug)] +pub struct FixedSizeList<'a> { + /// The element type of the array. + pub element: Box>, + /// Number of Elements + pub elements: u32, +} + +fn parse_list<'a>(parser: Parser<'a>) -> Result> { + parser.parse::()?; + let tp = parser.parse()?; + let elements = parser.parse::>()?; + if let Some(elements) = elements { + Ok(ComponentDefinedType::FixedSizeList(FixedSizeList { element: Box::new(tp), elements })) + } else { + Ok(ComponentDefinedType::List(List{ element: Box::new(tp), - elements, - }) + })) } } diff --git a/crates/wit-encoder/src/from_parser.rs b/crates/wit-encoder/src/from_parser.rs index 844d6f8601..c07da9c6af 100644 --- a/crates/wit-encoder/src/from_parser.rs +++ b/crates/wit-encoder/src/from_parser.rs @@ -240,11 +240,11 @@ impl<'a> Converter<'a> { TypeDefKind::Type(output) } wit_parser::TypeDefKind::List(ty) => { - let output = Type::list(self.convert_type(ty), None); + let output = Type::list(self.convert_type(ty)); TypeDefKind::Type(output) } wit_parser::TypeDefKind::FixedSizeList(ty, size) => { - let output = Type::list(self.convert_type(ty), Some(*size)); + let output = Type::fixed_size_list(self.convert_type(ty), *size); TypeDefKind::Type(output) } wit_parser::TypeDefKind::Handle(handle) => { @@ -306,10 +306,10 @@ impl<'a> Converter<'a> { Type::result(self.convert_result(result)) } wit_parser::TypeDefKind::List(type_) => { - Type::list(self.convert_type(type_), None) + Type::list(self.convert_type(type_)) } wit_parser::TypeDefKind::FixedSizeList(type_, size) => { - Type::list(self.convert_type(type_), Some(*size)) + Type::fixed_size_list(self.convert_type(type_), *size) } wit_parser::TypeDefKind::Handle(handle) => self.handle_to_type(handle), wit_parser::TypeDefKind::Future(type_) => { diff --git a/crates/wit-encoder/src/ty.rs b/crates/wit-encoder/src/ty.rs index 933f3cc4b3..18513b53f1 100644 --- a/crates/wit-encoder/src/ty.rs +++ b/crates/wit-encoder/src/ty.rs @@ -25,7 +25,8 @@ pub enum Type { Borrow(Ident), Option(Box), Result(Box), - List(Box, Option), + List(Box), + FixedSizeList(Box, u32), Tuple(Tuple), Future(Option>), Stream(Option>), @@ -55,8 +56,11 @@ impl Type { pub fn result_empty() -> Self { Type::Result(Box::new(Result_::empty())) } - pub fn list(type_: Type, size: Option) -> Self { - Type::List(Box::new(type_), size) + pub fn list(type_: Type) -> Self { + Type::List(Box::new(type_)) + } + pub fn fixed_size_list(type_: Type, size: u32) -> Self { + Type::FixedSizeList(Box::new(type_), size) } pub fn tuple(types: impl IntoIterator) -> Self { Type::Tuple(Tuple { @@ -113,12 +117,11 @@ impl Display for Type { write!(f, "option<{type_}>") } Type::Result(result) => result.fmt(f), - Type::List(type_, size) => { - if let Some(size) = size { - write!(f, "list<{type_}, {size}>") - } else { - write!(f, "list<{type_}>") - } + Type::List(type_) => { + write!(f, "list<{type_}>") + } + Type::FixedSizeList(type_, size) => { + write!(f, "list<{type_}, {size}>") } Type::Tuple(tuple) => tuple.fmt(f), Type::Future(None) => { From b74e6d173551d34eb4a2177d7b82f6e8150ba710 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 27 Apr 2025 15:53:45 +0200 Subject: [PATCH 24/25] separate list types in encoder as well --- crates/wit-encoder/tests/type_defs.rs | 4 ++-- crates/wit-encoder/tests/world.rs | 2 +- crates/wit-parser/src/ast.rs | 26 ++++++++++++++++++++------ crates/wit-parser/src/ast/resolve.rs | 16 ++++++++-------- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/crates/wit-encoder/tests/type_defs.rs b/crates/wit-encoder/tests/type_defs.rs index 974d2f1a7f..02d0147f5b 100644 --- a/crates/wit-encoder/tests/type_defs.rs +++ b/crates/wit-encoder/tests/type_defs.rs @@ -139,7 +139,7 @@ fn types() { interface.type_def(TypeDef::type_("t10a", Type::F64)); interface.type_def(TypeDef::type_("t10b", Type::F64)); interface.type_def(TypeDef::type_("t11", Type::Char)); - interface.type_def(TypeDef::type_("t12", Type::list(Type::Char, None))); + interface.type_def(TypeDef::type_("t12", Type::list(Type::Char))); interface.type_def(TypeDef::type_("t13", Type::String)); interface.type_def(TypeDef::type_("t14", Type::option(Type::U32))); interface.type_def(TypeDef::type_( @@ -206,7 +206,7 @@ fn types() { interface.type_def(TypeDef::type_("t44", Type::String)); interface.type_def(TypeDef::type_( "t45", - Type::list(Type::list(Type::list(Type::named("t32"), None), None), None), + Type::list(Type::list(Type::list(Type::named("t32")))), )); interface.type_def(TypeDef::type_("t46", Type::named("t44"))); interface.type_def(TypeDef::type_("foo", Type::named("bar"))); diff --git a/crates/wit-encoder/tests/world.rs b/crates/wit-encoder/tests/world.rs index 395cbb753b..192d5fe464 100644 --- a/crates/wit-encoder/tests/world.rs +++ b/crates/wit-encoder/tests/world.rs @@ -40,7 +40,7 @@ fn worlds() { }); world.function_export({ let mut func = StandaloneFunc::new("scan", false); - func.set_result(Some(Type::list(Type::U8, None))); + func.set_result(Some(Type::list(Type::U8))); func.set_docs(Some("scan stuff")); func }); diff --git a/crates/wit-parser/src/ast.rs b/crates/wit-parser/src/ast.rs index b35476f1f1..41186ab39a 100644 --- a/crates/wit-parser/src/ast.rs +++ b/crates/wit-parser/src/ast.rs @@ -754,6 +754,7 @@ enum Type<'a> { String(Span), Name(Id<'a>), List(List<'a>), + FixedSizeList(FixedSizeList<'a>), Handle(Handle<'a>), Resource(Resource<'a>), Record(Record<'a>), @@ -903,7 +904,12 @@ struct Option_<'a> { struct List<'a> { span: Span, ty: Box>, - fixed_size: Option, +} + +struct FixedSizeList<'a> { + span: Span, + ty: Box>, + size: u32, } struct Future<'a> { @@ -1380,11 +1386,18 @@ impl<'a> Type<'a> { None }; tokens.expect(Token::GreaterThan)?; - Ok(Type::List(List { - span, - ty: Box::new(ty), - fixed_size: size, - })) + if let Some(size) = size { + Ok(Type::FixedSizeList(FixedSizeList { + span, + ty: Box::new(ty), + size, + })) + } else { + Ok(Type::List(List { + span, + ty: Box::new(ty), + })) + } } // option @@ -1497,6 +1510,7 @@ impl<'a> Type<'a> { | Type::ErrorContext(span) => *span, Type::Name(id) => id.span, Type::List(l) => l.span, + Type::FixedSizeList(l) => l.span, Type::Handle(h) => h.span(), Type::Resource(r) => r.span, Type::Record(r) => r.span, diff --git a/crates/wit-parser/src/ast/resolve.rs b/crates/wit-parser/src/ast/resolve.rs index bb1b3925e8..0e626d8751 100644 --- a/crates/wit-parser/src/ast/resolve.rs +++ b/crates/wit-parser/src/ast/resolve.rs @@ -1173,11 +1173,11 @@ impl<'a> Resolver<'a> { } ast::Type::List(list) => { let ty = self.resolve_type(&list.ty, stability)?; - if let Some(elements) = list.fixed_size { - TypeDefKind::FixedSizeList(ty, elements) - } else { - TypeDefKind::List(ty) - } + TypeDefKind::List(ty) + } + ast::Type::FixedSizeList(list) => { + let ty = self.resolve_type(&list.ty, stability)?; + TypeDefKind::FixedSizeList(ty, list.size) } ast::Type::Handle(handle) => TypeDefKind::Handle(match handle { ast::Handle::Own { resource } => Handle::Own(self.validate_resource(resource)?), @@ -1686,9 +1686,9 @@ fn collect_deps<'a>(ty: &ast::Type<'a>, deps: &mut Vec>) { } } } - ast::Type::Option(ast::Option_ { ty, .. }) | ast::Type::List(ast::List { ty, .. }) => { - collect_deps(ty, deps) - } + ast::Type::Option(ast::Option_ { ty, .. }) + | ast::Type::List(ast::List { ty, .. }) + | ast::Type::FixedSizeList(ast::FixedSizeList { ty, .. }) => collect_deps(ty, deps), ast::Type::Result(r) => { if let Some(ty) = &r.ok { collect_deps(ty, deps); From 9669555dd2656a5a12710682812de12c3e82da04 Mon Sep 17 00:00:00 2001 From: Christof Petig Date: Sun, 27 Apr 2025 18:48:51 +0200 Subject: [PATCH 25/25] manually run rustfmt --- crates/wast/src/component/expand.rs | 7 +++++-- crates/wast/src/component/resolve.rs | 7 +++++-- crates/wast/src/component/types.rs | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/crates/wast/src/component/expand.rs b/crates/wast/src/component/expand.rs index a76fb57763..0887fc4254 100644 --- a/crates/wast/src/component/expand.rs +++ b/crates/wast/src/component/expand.rs @@ -532,8 +532,11 @@ impl<'a> Expander<'a> { } } } - ComponentDefinedType::List(List{element: t}) - | ComponentDefinedType::FixedSizeList(FixedSizeList{element: t, elements :_}) => { + ComponentDefinedType::List(List { element: t }) + | ComponentDefinedType::FixedSizeList(FixedSizeList { + element: t, + elements: _, + }) => { self.expand_component_val_ty(t); } ComponentDefinedType::Tuple(t) => { diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index 56344e7fc5..95ef0ef678 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -547,8 +547,11 @@ impl<'a> Resolver<'a> { } } } - ComponentDefinedType::List(List{element: t}) - | ComponentDefinedType::FixedSizeList(FixedSizeList{element: t, elements :_}) => { + ComponentDefinedType::List(List { element: t }) + | ComponentDefinedType::FixedSizeList(FixedSizeList { + element: t, + elements: _, + }) => { self.component_val_type(t)?; } ComponentDefinedType::Tuple(t) => { diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index a39e7f8d1a..a9ef3ba855 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -601,9 +601,12 @@ fn parse_list<'a>(parser: Parser<'a>) -> Result> { let tp = parser.parse()?; let elements = parser.parse::>()?; if let Some(elements) = elements { - Ok(ComponentDefinedType::FixedSizeList(FixedSizeList { element: Box::new(tp), elements })) + Ok(ComponentDefinedType::FixedSizeList(FixedSizeList { + element: Box::new(tp), + elements, + })) } else { - Ok(ComponentDefinedType::List(List{ + Ok(ComponentDefinedType::List(List { element: Box::new(tp), })) }