diff --git a/crates/wasmtime/src/component/func/typed.rs b/crates/wasmtime/src/component/func/typed.rs index 5842bc2627..c25520b3b8 100644 --- a/crates/wasmtime/src/component/func/typed.rs +++ b/crates/wasmtime/src/component/func/typed.rs @@ -603,74 +603,6 @@ forward_impls! { (T: Lower) Vec => [T], } -unsafe impl ComponentType for () { - // A 0-sized array is used here to represent that it has zero-size but it - // still has the alignment of `ValRaw`. - type Lower = [ValRaw; 0]; - - fn typecheck(ty: &InterfaceType, _types: &ComponentTypes) -> Result<()> { - match ty { - // FIXME(WebAssembly/component-model#21) this may either want to - // match more types, not actually exist as a trait impl, or - // something like that. Figuring out on that issue about the - // relationship between the 0-tuple, unit, and empty structs. - InterfaceType::Unit => Ok(()), - other => bail!("expected `unit` found `{}`", desc(other)), - } - } - - #[inline] - fn size() -> usize { - 0 - } - - #[inline] - fn align() -> u32 { - 1 - } -} - -unsafe impl Lift for () { - #[inline] - fn lift(_store: &StoreOpaque, _options: &Options, _src: &Self::Lower) -> Result { - Ok(()) - } - - #[inline] - fn load(_mem: &Memory, _bytes: &[u8]) -> Result { - Ok(()) - } -} - -unsafe impl Lower for () { - #[inline] - fn lower( - &self, - _store: &mut StoreContextMut, - _options: &Options, - _dst: &mut MaybeUninit, - ) -> Result<()> { - Ok(()) - } - - #[inline] - fn store(&self, _memory: &mut MemoryMut<'_, T>, _offset: usize) -> Result<()> { - Ok(()) - } -} - -unsafe impl ComponentParams for () { - fn typecheck_params( - params: &[(Option, InterfaceType)], - _types: &ComponentTypes, - ) -> Result<()> { - if params.len() != 0 { - bail!("expected 0 types, found {}", params.len()); - } - Ok(()) - } -} - // Macro to help generate `ComponentValue` implementations for primitive types // such as integers, char, bool, etc. macro_rules! integers { @@ -1376,9 +1308,16 @@ fn typecheck_tuple( expected: &[fn(&InterfaceType, &ComponentTypes) -> Result<()>], ) -> Result<()> { match ty { + InterfaceType::Unit if expected.len() == 0 => Ok(()), InterfaceType::Tuple(t) => { let tuple = &types[*t]; if tuple.types.len() != expected.len() { + if expected.len() == 0 { + bail!( + "expected unit or 0-tuple, found {}-tuple", + tuple.types.len(), + ); + } bail!( "expected {}-tuple, found {}-tuple", expected.len(), @@ -1390,6 +1329,9 @@ fn typecheck_tuple( } Ok(()) } + other if expected.len() == 0 => { + bail!("expected `unit` or 0-tuple found `{}`", desc(other)) + } other => bail!("expected `tuple` found `{}`", desc(other)), } } @@ -1636,13 +1578,6 @@ where } macro_rules! impl_component_ty_for_tuples { - // the unit tuple goes to the `Unit` type, not the `Tuple` type - // - // FIXME(WebAssembly/component-model#21) there's some active discussion on - // the relationship between the 0-tuple and the unit type in the component - // model. - (0) => {}; - ($n:tt $($t:ident)*) => {paste::paste!{ #[allow(non_snake_case)] #[doc(hidden)] @@ -1650,6 +1585,7 @@ macro_rules! impl_component_ty_for_tuples { #[repr(C)] pub struct []<$($t),*> { $($t: $t,)* + _align_tuple_lower0_correctly: [ValRaw; 0], } #[allow(non_snake_case)] @@ -1667,16 +1603,16 @@ macro_rules! impl_component_ty_for_tuples { #[inline] fn size() -> usize { - let mut size = 0; - $(next_field::<$t>(&mut size);)* - size + let mut _size = 0; + $(next_field::<$t>(&mut _size);)* + _size } #[inline] fn align() -> u32 { - let mut align = 1; - $(align = align.max($t::align());)* - align + let mut _align = 1; + $(_align = _align.max($t::align());)* + _align } } @@ -1686,19 +1622,19 @@ macro_rules! impl_component_ty_for_tuples { { fn lower( &self, - store: &mut StoreContextMut, - options: &Options, - dst: &mut MaybeUninit, + _store: &mut StoreContextMut, + _options: &Options, + _dst: &mut MaybeUninit, ) -> Result<()> { let ($($t,)*) = self; - $($t.lower(store, options, map_maybe_uninit!(dst.$t))?;)* + $($t.lower(_store, _options, map_maybe_uninit!(_dst.$t))?;)* Ok(()) } - fn store(&self, memory: &mut MemoryMut<'_, U>, mut offset: usize) -> Result<()> { - debug_assert!(offset % (Self::align() as usize) == 0); + fn store(&self, _memory: &mut MemoryMut<'_, U>, mut _offset: usize) -> Result<()> { + debug_assert!(_offset % (Self::align() as usize) == 0); let ($($t,)*) = self; - $($t.store(memory, next_field::<$t>(&mut offset))?;)* + $($t.store(_memory, next_field::<$t>(&mut _offset))?;)* Ok(()) } } @@ -1707,14 +1643,14 @@ macro_rules! impl_component_ty_for_tuples { unsafe impl<$($t,)*> Lift for ($($t,)*) where $($t: Lift),* { - fn lift(store: &StoreOpaque, options: &Options, src: &Self::Lower) -> Result { - Ok(($($t::lift(store, options, &src.$t)?,)*)) + fn lift(_store: &StoreOpaque, _options: &Options, _src: &Self::Lower) -> Result { + Ok(($($t::lift(_store, _options, &_src.$t)?,)*)) } - fn load(memory: &Memory<'_>, bytes: &[u8]) -> Result { + fn load(_memory: &Memory<'_>, bytes: &[u8]) -> Result { debug_assert!((bytes.as_ptr() as usize) % (Self::align() as usize) == 0); - let mut offset = 0; - $(let $t = $t::load(memory, &bytes[next_field::<$t>(&mut offset)..][..$t::size()])?;)* + let mut _offset = 0; + $(let $t = $t::load(_memory, &bytes[next_field::<$t>(&mut _offset)..][..$t::size()])?;)* Ok(($($t,)*)) } } diff --git a/tests/all/component_model/func.rs b/tests/all/component_model/func.rs index c3a6e1e6ce..5e0019adbe 100644 --- a/tests/all/component_model/func.rs +++ b/tests/all/component_model/func.rs @@ -62,6 +62,9 @@ fn typecheck() -> Result<()> { (func (export "thunk") (canon.lift (func) (func $i "thunk")) ) + (func (export "tuple-thunk") + (canon.lift (func (param (tuple)) (result (tuple))) (func $i "thunk")) + ) (func (export "take-string") (canon.lift (func (param string)) (into $i) (func $i "take-string")) ) @@ -88,6 +91,7 @@ fn typecheck() -> Result<()> { let mut store = Store::new(&engine, ()); let instance = Linker::new(&engine).instantiate(&mut store, &component)?; let thunk = instance.get_func(&mut store, "thunk").unwrap(); + let tuple_thunk = instance.get_func(&mut store, "tuple-thunk").unwrap(); let take_string = instance.get_func(&mut store, "take-string").unwrap(); let take_two_args = instance.get_func(&mut store, "take-two-args").unwrap(); let ret_tuple = instance.get_func(&mut store, "ret-tuple").unwrap(); @@ -97,6 +101,8 @@ fn typecheck() -> Result<()> { assert!(thunk.typed::<(), u32, _>(&store).is_err()); assert!(thunk.typed::<(u32,), (), _>(&store).is_err()); assert!(thunk.typed::<(), (), _>(&store).is_ok()); + assert!(tuple_thunk.typed::<(), (), _>(&store).is_err()); + assert!(tuple_thunk.typed::<((),), (), _>(&store).is_ok()); assert!(take_string.typed::<(), (), _>(&store).is_err()); assert!(take_string.typed::<(String,), (), _>(&store).is_ok()); assert!(take_string.typed::<(&str,), (), _>(&store).is_ok());