From 5aa30fed90aa9943ec6f8ba1c78eadac2e942130 Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Wed, 17 Jan 2024 19:39:46 +0100 Subject: [PATCH 1/2] fix: allow dynamic owned resources to be used as borrowed parameters Signed-off-by: Roman Volosatovs --- crates/wasmtime/src/component/func.rs | 3 ++- crates/wasmtime/src/component/func/host.rs | 2 +- crates/wasmtime/src/component/types.rs | 11 +++++++++-- crates/wasmtime/src/component/values.rs | 12 +++++++----- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/crates/wasmtime/src/component/func.rs b/crates/wasmtime/src/component/func.rs index 0b69aff34d8c..cf4f710f1b1b 100644 --- a/crates/wasmtime/src/component/func.rs +++ b/crates/wasmtime/src/component/func.rs @@ -362,7 +362,8 @@ impl Func { } for (param, ty) in params.iter().zip(param_tys.iter()) { - ty.check(param).context("type mismatch with parameters")?; + ty.is_supertype_of(param) + .context("type mismatch with parameters")?; } self.call_raw( diff --git a/crates/wasmtime/src/component/func/host.rs b/crates/wasmtime/src/component/func/host.rs index a048275b9090..c00f38c833bd 100644 --- a/crates/wasmtime/src/component/func/host.rs +++ b/crates/wasmtime/src/component/func/host.rs @@ -385,7 +385,7 @@ where 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).check(val)?; + 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(); diff --git a/crates/wasmtime/src/component/types.rs b/crates/wasmtime/src/component/types.rs index f751079fa037..401ba15ec407 100644 --- a/crates/wasmtime/src/component/types.rs +++ b/crates/wasmtime/src/component/types.rs @@ -675,9 +675,16 @@ impl Type { } } - pub(crate) fn check(&self, value: &Val) -> Result<()> { + /// Checks whether type of `value` is a subtype of `self`. + /// + /// # Errors + /// + /// Returns an error in case of a type mismatch + pub(crate) fn is_supertype_of(&self, value: &Val) -> Result<()> { let other = &value.ty(); - if self == other { + if self == other + || matches!((self, other), (Self::Borrow(s), Self::Own(other)) if s == other) + { Ok(()) } else if mem::discriminant(self) != mem::discriminant(other) { Err(anyhow!( diff --git a/crates/wasmtime/src/component/values.rs b/crates/wasmtime/src/component/values.rs index 332a0659a875..0775dcf7b2da 100644 --- a/crates/wasmtime/src/component/values.rs +++ b/crates/wasmtime/src/component/values.rs @@ -26,7 +26,7 @@ impl List { let element_type = ty.ty(); for (index, value) in values.iter().enumerate() { element_type - .check(value) + .is_supertype_of(value) .with_context(|| format!("type mismatch for element {index} of list"))?; } @@ -83,7 +83,7 @@ impl Record { if name == field.name { field .ty - .check(&value) + .is_supertype_of(&value) .with_context(|| format!("type mismatch for field {name} of record"))?; values.push(value); @@ -150,7 +150,7 @@ impl Tuple { } for (index, (value, ty)) in values.iter().zip(ty.types()).enumerate() { - ty.check(value) + ty.is_supertype_of(value) .with_context(|| format!("type mismatch for field {index} of tuple"))?; } @@ -256,7 +256,7 @@ impl Variant { fn typecheck_payload(name: &str, case_type: Option<&Type>, value: Option<&Val>) -> Result<()> { match (case_type, value) { (Some(expected), Some(actual)) => expected - .check(&actual) + .is_supertype_of(&actual) .with_context(|| format!("type mismatch for case {name} of variant")), (None, None) => Ok(()), (Some(_), None) => bail!("expected a payload for case `{name}`"), @@ -341,7 +341,9 @@ impl OptionVal { pub fn new(ty: &types::OptionType, value: Option) -> Result { let value = value .map(|value| { - ty.ty().check(&value).context("type mismatch for option")?; + ty.ty() + .is_supertype_of(&value) + .context("type mismatch for option")?; Ok::<_, Error>(value) }) From f38af4c348ae0aa6946f3f20b45db3e135fb9f54 Mon Sep 17 00:00:00 2001 From: Roman Volosatovs Date: Thu, 18 Jan 2024 13:22:28 +0100 Subject: [PATCH 2/2] tests: add `can_use_own_for_borrow` test Signed-off-by: Roman Volosatovs --- tests/all/component_model/resources.rs | 66 ++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/all/component_model/resources.rs b/tests/all/component_model/resources.rs index 448eceecf7ad..bb593894419b 100644 --- a/tests/all/component_model/resources.rs +++ b/tests/all/component_model/resources.rs @@ -856,6 +856,72 @@ fn cannot_use_borrow_for_own() -> Result<()> { Ok(()) } +#[test] +fn can_use_own_for_borrow() -> Result<()> { + let engine = super::engine(); + let c = Component::new( + &engine, + r#" + (component + (import "t" (type $t (sub resource))) + + (core func $drop (canon resource.drop $t)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (func (export "f") (param i32) + (call $drop (local.get 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + + (func (export "f") (param "x" (borrow $t)) + (canon lift (core func $i "f"))) + ) + "#, + )?; + + struct MyType; + + let mut store = Store::new(&engine, ()); + let mut linker = Linker::new(&engine); + let ty_idx = linker + .root() + .resource("t", ResourceType::host::(), |_, _| Ok(()))?; + let i_pre = linker.instantiate_pre(&c)?; + let i = i_pre.instantiate(&mut store)?; + + let f = i.get_func(&mut store, "f").unwrap(); + let f_typed = i.get_typed_func::<(&Resource,), ()>(&mut store, "f")?; + + let resource = Resource::new_own(100); + f_typed.call(&mut store, (&resource,))?; + f_typed.post_return(&mut store)?; + + let resource = Resource::new_borrow(200); + f_typed.call(&mut store, (&resource,))?; + f_typed.post_return(&mut store)?; + + let resource = + Resource::::new_own(300).try_into_resource_any(&mut store, &i_pre, ty_idx)?; + f.call(&mut store, &[Val::Resource(resource)], &mut [])?; + f.post_return(&mut store)?; + resource.resource_drop(&mut store)?; + + // TODO: Enable once https://github.com/bytecodealliance/wasmtime/issues/7793 is fixed + //let resource = + // Resource::::new_borrow(400).try_into_resource_any(&mut store, &i_pre, ty_idx)?; + //f.call(&mut store, &[Val::Resource(resource)], &mut [])?; + //f.post_return(&mut store)?; + //resource.resource_drop(&mut store)?; + + Ok(()) +} + #[test] fn passthrough_wrong_type() -> Result<()> { let engine = super::engine();