Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions crates/wasm-compose/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,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::Map(key, value) => self.map(state, *key, *value),
ComponentDefinedType::FixedSizeList(ty, elements) => {
self.fixed_size_list(state, *ty, *elements)
}
Expand Down Expand Up @@ -713,6 +714,19 @@ impl<'a> TypeEncoder<'a> {
index
}

fn map(
&self,
state: &mut TypeState<'a>,
key: ct::ComponentValType,
value: ct::ComponentValType,
) -> u32 {
let key = self.component_val_type(state, key);
let value = self.component_val_type(state, value);
let index = state.cur.encodable.type_count();
state.cur.encodable.ty().defined_type().map(key, value);
index
}

fn fixed_size_list(
&self,
state: &mut TypeState<'a>,
Expand Down Expand Up @@ -1253,6 +1267,10 @@ impl DependencyRegistrar<'_, '_> {
ComponentDefinedType::List(t)
| ComponentDefinedType::FixedSizeList(t, _)
| ComponentDefinedType::Option(t) => self.val_type(*t),
ComponentDefinedType::Map(k, v) => {
self.val_type(*k);
self.val_type(*v);
}
ComponentDefinedType::Own(r) | ComponentDefinedType::Borrow(r) => {
self.ty(ComponentAnyTypeId::Resource(*r))
}
Expand Down
7 changes: 7 additions & 0 deletions crates/wasm-encoder/src/component/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,13 @@ impl ComponentDefinedTypeEncoder<'_> {
ty.into().encode(self.0);
}

/// Define a map type.
pub fn map(self, key: impl Into<ComponentValType>, value: impl Into<ComponentValType>) {
self.0.push(0x63);
key.into().encode(self.0);
value.into().encode(self.0);
}

/// Define a fixed size list type.
pub fn fixed_size_list(self, ty: impl Into<ComponentValType>, elements: u32) {
self.0.push(0x67);
Expand Down
6 changes: 6 additions & 0 deletions crates/wasm-encoder/src/reencode/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,12 @@ pub mod component_utils {
wasmparser::ComponentDefinedType::List(t) => {
defined.list(reencoder.component_val_type(t));
}
wasmparser::ComponentDefinedType::Map(k, v) => {
defined.map(
reencoder.component_val_type(k),
reencoder.component_val_type(v),
);
}
wasmparser::ComponentDefinedType::FixedSizeList(t, elements) => {
defined.fixed_size_list(reencoder.component_val_type(t), elements);
}
Expand Down
3 changes: 3 additions & 0 deletions crates/wasmparser/src/readers/component/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,8 @@ pub enum ComponentDefinedType<'a> {
Variant(Box<[VariantCase<'a>]>),
/// The type is a list of the given value type.
List(ComponentValType),
/// The type is a map of the given key and value types.
Map(ComponentValType, ComponentValType),
/// The type is a fixed size list of the given value type.
FixedSizeList(ComponentValType, u32),
/// The type is a tuple of the given value types.
Expand Down Expand Up @@ -481,6 +483,7 @@ impl<'a> ComponentDefinedType<'a> {
.collect::<Result<_>>()?,
),
0x70 => ComponentDefinedType::List(reader.read()?),
0x63 => ComponentDefinedType::Map(reader.read()?, reader.read()?),
0x6f => ComponentDefinedType::Tuple(
reader
.read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")?
Expand Down
7 changes: 7 additions & 0 deletions crates/wasmparser/src/validator/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,9 @@ impl ComponentState {
ComponentDefinedType::List(ty)
| ComponentDefinedType::FixedSizeList(ty, _)
| ComponentDefinedType::Option(ty) => types.type_named_valtype(ty, set),
ComponentDefinedType::Map(k, v) => {
types.type_named_valtype(k, set) && types.type_named_valtype(v, set)
}

// The resource referred to by own/borrow must be named.
ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => {
Expand Down Expand Up @@ -3928,6 +3931,10 @@ impl ComponentState {
crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List(
self.create_component_val_type(ty, offset)?,
)),
crate::ComponentDefinedType::Map(key, value) => Ok(ComponentDefinedType::Map(
self.create_component_val_type(key, offset)?,
self.create_component_val_type(value, offset)?,
)),
crate::ComponentDefinedType::FixedSizeList(ty, elements) => {
if !self.features.cm_fixed_size_list() {
bail!(
Expand Down
34 changes: 31 additions & 3 deletions crates/wasmparser/src/validator/component_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,8 @@ pub enum ComponentDefinedType {
Variant(VariantType),
/// The type is a list.
List(ComponentValType),
/// The type is a map.
Map(ComponentValType, ComponentValType),
/// The type is a fixed size list.
FixedSizeList(ComponentValType, u32),
/// The type is a tuple.
Expand Down Expand Up @@ -1494,6 +1496,11 @@ impl TypeData for ComponentDefinedType {
Self::Variant(v) => v.info,
Self::Tuple(t) => t.info,
Self::List(ty) | Self::FixedSizeList(ty, _) | Self::Option(ty) => ty.info(types),
Self::Map(k, v) => {
let mut info = k.info(types);
info.combine(v.info(types), 0).unwrap();
info
}
Self::Result { ok, err } => {
let default = TypeInfo::new();
let mut info = ok.map(|ty| ty.type_info(types)).unwrap_or(default);
Expand All @@ -1514,7 +1521,7 @@ impl ComponentDefinedType {
.cases
.values()
.any(|case| case.ty.map(|ty| ty.contains_ptr(types)).unwrap_or(false)),
Self::List(_) => true,
Self::List(_) | Self::Map(_, _) => true,
Self::Tuple(t) => t.types.iter().any(|ty| ty.contains_ptr(types)),
Self::Flags(_)
| Self::Enum(_)
Expand Down Expand Up @@ -1542,7 +1549,7 @@ impl ComponentDefinedType {
types,
lowered_types,
),
Self::List(_) => {
Self::List(_) | Self::Map(_, _) => {
lowered_types.try_push(ValType::I32) && lowered_types.try_push(ValType::I32)
}
Self::FixedSizeList(ty, length) => {
Expand Down Expand Up @@ -1622,6 +1629,7 @@ impl ComponentDefinedType {
ComponentDefinedType::Flags(_) => "flags",
ComponentDefinedType::Option(_) => "option",
ComponentDefinedType::List(_) => "list",
ComponentDefinedType::Map(_, _) => "map",
ComponentDefinedType::FixedSizeList(_, _) => "fixed size list",
ComponentDefinedType::Result { .. } => "result",
ComponentDefinedType::Own(_) => "own",
Expand All @@ -1646,7 +1654,9 @@ impl ComponentDefinedType {

ComponentDefinedType::Variant(ty) => ty.lower_gc(types, abi, options, offset, core),

ComponentDefinedType::List(ty) | ComponentDefinedType::FixedSizeList(ty, _) => {
ComponentDefinedType::List(ty)
| ComponentDefinedType::Map(ty, _)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this I think it would be best for Map to be routed to some sort of "not implemented" error and you can defer the work to someone fleshing out GC support in the future

| ComponentDefinedType::FixedSizeList(ty, _) => {
let id = match core.as_concrete_ref() {
Some(id) => id,
None => bail!(
Expand Down Expand Up @@ -2498,6 +2508,10 @@ impl TypeAlloc {
| ComponentDefinedType::Option(ty) => {
self.free_variables_valtype(ty, set);
}
ComponentDefinedType::Map(k, v) => {
self.free_variables_valtype(k, set);
self.free_variables_valtype(v, set);
}
ComponentDefinedType::Result { ok, err } => {
if let Some(ok) = ok {
self.free_variables_valtype(ok, set);
Expand Down Expand Up @@ -2640,6 +2654,9 @@ impl TypeAlloc {
ComponentDefinedType::List(ty)
| ComponentDefinedType::FixedSizeList(ty, _)
| ComponentDefinedType::Option(ty) => self.type_named_valtype(ty, set),
ComponentDefinedType::Map(k, v) => {
self.type_named_valtype(k, set) && self.type_named_valtype(v, set)
}

// own/borrow themselves don't have to be named, but the resource
// they refer to must be named.
Expand Down Expand Up @@ -2832,6 +2849,10 @@ where
| ComponentDefinedType::Option(ty) => {
any_changed |= self.remap_valtype(ty, map);
}
ComponentDefinedType::Map(k, v) => {
any_changed |= self.remap_valtype(k, map);
any_changed |= self.remap_valtype(v, map);
}
ComponentDefinedType::Result { ok, err } => {
if let Some(ok) = ok {
any_changed |= self.remap_valtype(ok, map);
Expand Down Expand Up @@ -3724,6 +3745,13 @@ impl<'a> SubtypeCx<'a> {
(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()),
(Map(ak, av), Map(bk, bv)) => {
self.component_val_type(ak, bk, offset)
.with_context(|| "type mismatch in map key")?;
self.component_val_type(av, bv, offset)
.with_context(|| "type mismatch in map value")
}
(Map(_, _), b) => bail!(offset, "expected {}, found map", b.desc()),
(FixedSizeList(a, asize), FixedSizeList(b, bsize)) => {
if asize != bsize {
bail!(offset, "expected fixed size {bsize}, found size {asize}")
Expand Down
15 changes: 15 additions & 0 deletions crates/wasmprinter/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,20 @@ impl Printer<'_, '_> {
Ok(())
}

pub(crate) fn print_map_type(
&mut self,
state: &State,
key_ty: &ComponentValType,
value_ty: &ComponentValType,
) -> Result<()> {
self.start_group("map ")?;
self.print_component_val_type(state, key_ty)?;
self.result.write_str(" ")?;
self.print_component_val_type(state, value_ty)?;
self.end_group()?;
Ok(())
}

pub(crate) fn print_fixed_size_list_type(
&mut self,
state: &State,
Expand Down Expand Up @@ -278,6 +292,7 @@ impl Printer<'_, '_> {
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::Map(key, value) => self.print_map_type(state, key, value)?,
ComponentDefinedType::FixedSizeList(ty, elements) => {
self.print_fixed_size_list_type(state, ty, *elements)?
}
Expand Down
3 changes: 3 additions & 0 deletions crates/wit-component/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,9 @@ impl TypeContents {
}
TypeDefKind::Enum(_) => Self::empty(),
TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::LIST,
TypeDefKind::Map(k, v) => {
Self::for_type(resolve, k) | Self::for_type(resolve, v) | Self::LIST
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Self::for_type(resolve, k) | Self::for_type(resolve, v) | Self::LIST
Self::for_type(resolve, k) | Self::for_type(resolve, v)

Should this be Self::MAP or just removed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're up for it renaming LIST to something like NEEDS_MEMORY or something like that would be appropriate. Otherwise though this looks correct where LIST is mostly a proxy for "needs a memory canon option" which is always true for map

}
TypeDefKind::FixedSizeList(t, _elements) => Self::for_type(resolve, t),
TypeDefKind::Type(t) => Self::for_type(resolve, t),
TypeDefKind::Future(_) => Self::empty(),
Expand Down
7 changes: 7 additions & 0 deletions crates/wit-component/src/encoding/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,13 @@ pub trait ValtypeEncoder<'a> {
encoder.list(ty);
ComponentValType::Type(index)
}
TypeDefKind::Map(key_ty, value_ty) => {
let key = self.encode_valtype(resolve, key_ty)?;
let value = self.encode_valtype(resolve, value_ty)?;
let (index, encoder) = self.defined_type();
encoder.map(key, value);
ComponentValType::Type(index)
}
TypeDefKind::FixedSizeList(ty, elements) => {
let ty = self.encode_valtype(resolve, ty)?;
let (index, encoder) = self.defined_type();
Expand Down
38 changes: 38 additions & 0 deletions crates/wit-component/src/printing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,14 @@ impl<O: Output> WitPrinter<O> {
self.print_type_name(resolve, ty)?;
self.output.generic_args_end();
}
TypeDefKind::Map(key_ty, value_ty) => {
self.output.ty("map", TypeKind::BuiltIn);
self.output.generic_args_start();
self.print_type_name(resolve, key_ty)?;
self.output.str(", ");
self.print_type_name(resolve, value_ty)?;
self.output.generic_args_end();
}
TypeDefKind::FixedSizeList(ty, size) => {
self.output.ty("list", TypeKind::BuiltIn);
self.output.generic_args_start();
Expand Down Expand Up @@ -787,6 +795,9 @@ impl<O: Output> WitPrinter<O> {
TypeDefKind::List(inner) => {
self.declare_list(resolve, ty.name.as_deref(), inner)?
}
TypeDefKind::Map(key, value) => {
self.declare_map(resolve, ty.name.as_deref(), key, value)?
}
TypeDefKind::FixedSizeList(inner, size) => {
self.declare_fixed_size_list(resolve, ty.name.as_deref(), inner, *size)?
}
Expand Down Expand Up @@ -1003,6 +1014,31 @@ impl<O: Output> WitPrinter<O> {
Ok(())
}

fn declare_map(
&mut self,
resolve: &Resolve,
name: Option<&str>,
key_ty: &Type,
value_ty: &Type,
) -> Result<()> {
if let Some(name) = name {
self.output.keyword("type");
self.output.str(" ");
self.print_name_type(name, TypeKind::Map);
self.output.str(" = ");
self.output.ty("map", TypeKind::BuiltIn);
self.output.str("<");
self.print_type_name(resolve, key_ty)?;
self.output.str(", ");
self.print_type_name(resolve, value_ty)?;
self.output.str(">");
self.output.semicolon();
return Ok(());
}

Ok(())
}

fn declare_fixed_size_list(
&mut self,
resolve: &Resolve,
Expand Down Expand Up @@ -1343,6 +1379,8 @@ pub enum TypeKind {
InterfacePath,
/// A list type name.
List,
/// A map type name.
Map,
/// A namespace declaration.
NamespaceDeclaration,
/// A namespace when printing a path, for example in `use`.
Expand Down
Loading