Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 2 additions & 2 deletions crates/component-macro/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ impl Expander for LiftExpander {
if let Some(ty) = ty {
let payload_ty = match style {
VariantStyle::Variant => {
quote!(ty.cases[#index].ty.unwrap_or_else(#internal::bad_type_info))
quote!(ty.cases[#index].unwrap_or_else(#internal::bad_type_info))
}
VariantStyle::Enum => unreachable!(),
};
Expand Down Expand Up @@ -626,7 +626,7 @@ impl Expander for LowerExpander {
if ty.is_some() {
let ty = match style {
VariantStyle::Variant => {
quote!(ty.cases[#index].ty.unwrap_or_else(#internal::bad_type_info))
quote!(ty.cases[#index].unwrap_or_else(#internal::bad_type_info))
}
VariantStyle::Enum => unreachable!(),
};
Expand Down
72 changes: 46 additions & 26 deletions crates/environ/src/component/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use cranelift_entity::EntityRef;
use indexmap::{IndexMap, IndexSet};
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::hash::Hash;
use std::hash::{Hash, Hasher};
use std::ops::Index;
use wasmparser::names::KebabString;
use wasmparser::types;
Expand Down Expand Up @@ -757,19 +757,20 @@ impl ComponentTypesBuilder {
if case.refines.is_some() {
bail!("refines is not supported at this time");
}
Ok(VariantCase {
name: name.to_string(),
ty: match &case.ty.as_ref() {
Ok((
name.to_string(),
match &case.ty.as_ref() {
Some(ty) => Some(self.valtype(types, ty)?),
None => None,
},
})
))
})
.collect::<Result<Box<[_]>>>()?;
let (info, abi) = VariantInfo::new(cases.iter().map(|c| {
c.ty.as_ref()
.map(|ty| self.component_types.canonical_abi(ty))
}));
.collect::<Result<IndexMap<_, _>>>()?;
let (info, abi) = VariantInfo::new(
cases
.iter()
.map(|(_, c)| c.as_ref().map(|ty| self.component_types.canonical_abi(ty))),
);
Ok(self.add_variant_type(TypeVariant { cases, abi, info }))
}

Expand Down Expand Up @@ -804,7 +805,10 @@ impl ComponentTypesBuilder {
}

fn enum_type(&mut self, variants: &IndexSet<KebabString>) -> TypeEnumIndex {
let names = variants.iter().map(|s| s.to_string()).collect::<Box<[_]>>();
let names = variants
.iter()
.map(|s| s.to_string())
.collect::<IndexSet<_>>();
let (info, abi) = VariantInfo::new(names.iter().map(|_| None));
self.add_enum_type(TypeEnum { names, abi, info })
}
Expand Down Expand Up @@ -1485,24 +1489,23 @@ pub struct RecordField {
/// Variants are close to Rust `enum` declarations where a value is one of many
/// cases and each case has a unique name and an optional payload associated
/// with it.
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
pub struct TypeVariant {
/// The list of cases that this variant can take.
pub cases: Box<[VariantCase]>,
pub cases: IndexMap<String, Option<InterfaceType>>,
/// Byte information about this type in the canonical ABI.
pub abi: CanonicalAbiInfo,
/// Byte information about this variant type.
pub info: VariantInfo,
}

/// One case of a `variant` type which contains the name of the variant as well
/// as the payload.
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct VariantCase {
/// Name of the variant, unique amongst all cases in a variant.
pub name: String,
/// Optional type associated with this payload.
pub ty: Option<InterfaceType>,
impl Hash for TypeVariant {
fn hash<H: Hasher>(&self, h: &mut H) {
let TypeVariant { cases, abi, info } = self;
cases.as_slice().hash(h);
abi.hash(h);
info.hash(h);
}
}

/// Shape of a "tuple" type in interface types.
Expand All @@ -1521,29 +1524,46 @@ pub struct TypeTuple {
///
/// This can be thought of as a record-of-bools, although the representation is
/// more efficient as bitflags.
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
pub struct TypeFlags {
/// The names of all flags, all of which are unique.
pub names: Box<[String]>,
pub names: IndexSet<String>,
/// Byte information about this type in the canonical ABI.
pub abi: CanonicalAbiInfo,
}

impl Hash for TypeFlags {
fn hash<H: Hasher>(&self, h: &mut H) {
let TypeFlags { names, abi } = self;
names.as_slice().hash(h);
abi.hash(h);
}
}

/// Shape of an "enum" type in interface types, not to be confused with a Rust
/// `enum` type.
///
/// In interface types enums are simply a bag of names, and can be seen as a
/// variant where all payloads are `Unit`.
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
pub struct TypeEnum {
/// The names of this enum, all of which are unique.
pub names: Box<[String]>,
pub names: IndexSet<String>,
/// Byte information about this type in the canonical ABI.
pub abi: CanonicalAbiInfo,
/// Byte information about this variant type.
pub info: VariantInfo,
}

impl Hash for TypeEnum {
fn hash<H: Hasher>(&self, h: &mut H) {
let TypeEnum { names, abi, info } = self;
names.as_slice().hash(h);
abi.hash(h);
info.hash(h);
}
}

/// Shape of an "option" interface type.
#[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, Debug)]
pub struct TypeOption {
Expand Down Expand Up @@ -1909,7 +1929,7 @@ impl TypeInformation {
self.build_variant(
ty.cases
.iter()
.map(|c| c.ty.as_ref().map(|ty| types.type_information(ty))),
.map(|(_, c)| c.as_ref().map(|ty| types.type_information(ty))),
)
}

Expand Down
40 changes: 22 additions & 18 deletions crates/environ/src/fact/trampoline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2179,25 +2179,29 @@ impl Compiler<'_, '_> {
_ => panic!("expected a variant"),
};

let src_info = variant_info(self.types, src_ty.cases.iter().map(|c| c.ty.as_ref()));
let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|c| c.ty.as_ref()));
let src_info = variant_info(self.types, src_ty.cases.iter().map(|(_, c)| c.as_ref()));
let dst_info = variant_info(self.types, dst_ty.cases.iter().map(|(_, c)| c.as_ref()));

let iter = src_ty.cases.iter().enumerate().map(|(src_i, src_case)| {
let dst_i = dst_ty
.cases
.iter()
.position(|c| c.name == src_case.name)
.unwrap();
let dst_case = &dst_ty.cases[dst_i];
let src_i = u32::try_from(src_i).unwrap();
let dst_i = u32::try_from(dst_i).unwrap();
VariantCase {
src_i,
src_ty: src_case.ty.as_ref(),
dst_i,
dst_ty: dst_case.ty.as_ref(),
}
});
let iter = src_ty
.cases
.iter()
.enumerate()
.map(|(src_i, (src_case, src_case_ty))| {
let dst_i = dst_ty
.cases
.iter()
.position(|(c, _)| c == src_case)
.unwrap();
let dst_case_ty = &dst_ty.cases[dst_i];
let src_i = u32::try_from(src_i).unwrap();
let dst_i = u32::try_from(dst_i).unwrap();
VariantCase {
src_i,
src_ty: src_case_ty.as_ref(),
dst_i,
dst_ty: dst_case_ty.as_ref(),
}
});
self.convert_variant(src, &src_info, dst, &dst_info, iter);
}

Expand Down
96 changes: 43 additions & 53 deletions crates/fuzzing/src/generators/component_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,77 +46,67 @@ pub fn arbitrary_val(ty: &component::Type, input: &mut Unstructured) -> arbitrar
Ok(ControlFlow::Continue(()))
})?;

list.new_val(values.into()).unwrap()
Val::List(values.into())
}
Type::Record(record) => record
.new_val(
record
.fields()
.map(|field| Ok((field.name, arbitrary_val(&field.ty, input)?)))
.collect::<arbitrary::Result<Vec<_>>>()?,
)
.unwrap(),
Type::Tuple(tuple) => tuple
.new_val(
tuple
.types()
.map(|ty| arbitrary_val(&ty, input))
.collect::<arbitrary::Result<_>>()?,
)
.unwrap(),
Type::Record(record) => Val::Record(
record
.fields()
.map(|field| Ok((field.name.to_string(), arbitrary_val(&field.ty, input)?)))
.collect::<arbitrary::Result<_>>()?,
),
Type::Tuple(tuple) => Val::Tuple(
tuple
.types()
.map(|ty| arbitrary_val(&ty, input))
.collect::<arbitrary::Result<_>>()?,
),
Type::Variant(variant) => {
let cases = variant.cases().collect::<Vec<_>>();
let case = input.choose(&cases)?;
let payload = match &case.ty {
Some(ty) => Some(arbitrary_val(ty, input)?),
Some(ty) => Some(Box::new(arbitrary_val(ty, input)?)),
None => None,
};
variant.new_val(case.name, payload).unwrap()
Val::Variant(case.name.to_string(), payload)
}
Type::Enum(en) => {
let names = en.names().collect::<Vec<_>>();
let name = input.choose(&names)?;
en.new_val(name).unwrap()
Val::Enum(name.to_string())
}
Type::Option(option) => {
let discriminant = input.int_in_range(0..=1)?;
option
.new_val(match discriminant {
0 => None,
1 => Some(arbitrary_val(&option.ty(), input)?),
_ => unreachable!(),
})
.unwrap()
Val::Option(match discriminant {
0 => None,
1 => Some(Box::new(arbitrary_val(&option.ty(), input)?)),
_ => unreachable!(),
})
}
Type::Result(result) => {
let discriminant = input.int_in_range(0..=1)?;
result
.new_val(match discriminant {
0 => Ok(match result.ok() {
Some(ty) => Some(arbitrary_val(&ty, input)?),
None => None,
}),
1 => Err(match result.err() {
Some(ty) => Some(arbitrary_val(&ty, input)?),
None => None,
}),
_ => unreachable!(),
})
.unwrap()
Val::Result(match discriminant {
0 => Ok(match result.ok() {
Some(ty) => Some(Box::new(arbitrary_val(&ty, input)?)),
None => None,
}),
1 => Err(match result.err() {
Some(ty) => Some(Box::new(arbitrary_val(&ty, input)?)),
None => None,
}),
_ => unreachable!(),
})
}
Type::Flags(flags) => flags
.new_val(
&flags
.names()
.filter_map(|name| {
input
.arbitrary()
.map(|p| if p { Some(name) } else { None })
.transpose()
})
.collect::<arbitrary::Result<Box<[_]>>>()?,
)
.unwrap(),
Type::Flags(flags) => Val::Flags(
flags
.names()
.filter_map(|name| {
input
.arbitrary()
.map(|p| if p { Some(name.to_string()) } else { None })
.transpose()
})
.collect::<arbitrary::Result<_>>()?,
),

// Resources aren't fuzzed at this time.
Type::Own(_) | Type::Borrow(_) => unreachable!(),
Expand Down
5 changes: 0 additions & 5 deletions crates/wasmtime/src/runtime/component/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,11 +395,6 @@ impl Func {
);
}

for (param, ty) in params.iter().zip(param_tys.iter()) {
ty.is_supertype_of(param)
.context("type mismatch with parameters")?;
}

self.call_raw(
store,
params,
Expand Down
6 changes: 1 addition & 5 deletions crates/wasmtime/src/runtime/component/func/host.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::component::func::{LiftContext, LowerContext, Options};
use crate::component::matching::InstanceType;
use crate::component::storage::slice_to_storage_mut;
use crate::component::{ComponentNamedList, ComponentType, Lift, Lower, Type, Val};
use crate::component::{ComponentNamedList, ComponentType, Lift, Lower, Val};
use crate::{AsContextMut, StoreContextMut, ValRaw};
use anyhow::{anyhow, bail, Context, Result};
use std::any::Any;
Expand Down Expand Up @@ -383,10 +383,6 @@ where
flags.set_may_leave(false);

let mut cx = LowerContext::new(store, &options, types, instance);
let instance = cx.instance_type();
for (val, ty) in result_vals.iter().zip(result_tys.types.iter()) {
Type::from(ty, &instance).is_supertype_of(val)?;
}
if let Some(cnt) = result_tys.abi.flat_count(MAX_FLAT_RESULTS) {
let mut dst = storage[..cnt].iter_mut();
for (val, ty) in result_vals.iter().zip(result_tys.types.iter()) {
Expand Down
8 changes: 4 additions & 4 deletions crates/wasmtime/src/runtime/component/func/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1787,12 +1787,12 @@ pub fn typecheck_variant(
);
}

for (case, &(name, check)) in cases.iter().zip(expected) {
if case.name != name {
bail!("expected variant case named {name}, found {}", case.name);
for ((case_name, case_ty), &(name, check)) in cases.iter().zip(expected) {
if *case_name != name {
bail!("expected variant case named {name}, found {case_name}");
}

match (check, &case.ty) {
match (check, case_ty) {
(Some(check), Some(ty)) => check(ty, types)
.with_context(|| format!("type mismatch for case {name}"))?,
(None, None) => {}
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/runtime/component/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub use self::linker::{Linker, LinkerInstance, ResourceImportIndex};
pub use self::resource_table::{ResourceTable, ResourceTableError};
pub use self::resources::{Resource, ResourceAny};
pub use self::types::{ResourceType, Type};
pub use self::values::{Enum, Flags, List, OptionVal, Record, ResultVal, Tuple, Val, Variant};
pub use self::values::Val;

pub(crate) use self::resources::HostResourceData;

Expand Down
Loading