Browse Source

fix: allow dynamic owned resources to be used as borrowed parameters (#7783)

* fix: allow dynamic owned resources to be used as borrowed parameters

Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>

* tests: add `can_use_own_for_borrow` test

Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>

---------

Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
pull/7794/head
Roman Volosatovs 10 months ago
committed by GitHub
parent
commit
2c86e26b25
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      crates/wasmtime/src/component/func.rs
  2. 2
      crates/wasmtime/src/component/func/host.rs
  3. 11
      crates/wasmtime/src/component/types.rs
  4. 12
      crates/wasmtime/src/component/values.rs
  5. 66
      tests/all/component_model/resources.rs

3
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(

2
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();

11
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!(

12
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<Val>) -> Result<Self> {
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)
})

66
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::<MyType>(), |_, _| 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<MyType>,), ()>(&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::<MyType>::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::<MyType>::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();

Loading…
Cancel
Save