Improve type imports into components (#5777)

This commit fixes a panic related to type imports where an import of a
type didn't correctly declare the new type index on the Wasmtime side of
things. Additionally this plumbs more support throughout Wasmtime to
support type imports, namely that they do not need to be supplied
through a `Linker`. This additionally implements a feature where empty
instances, even transitively, do not need to be supplied by a Wasmtime
embedder. This means that instances which only have types, for example,
do not need to be supplied into a `Linker` since no runtime information
for them is required anyway.

Closes #5775
This commit is contained in:
Alex Crichton
2023-02-14 12:02:19 -06:00
committed by GitHub
parent e40a838beb
commit b5e9fb710b
7 changed files with 89 additions and 52 deletions

View File

@@ -134,8 +134,7 @@ impl<T> Linker<T> {
let import = self
.strings
.lookup(name)
.and_then(|name| self.map.get(&name))
.ok_or_else(|| anyhow!("import `{name}` not defined"))?;
.and_then(|name| self.map.get(&name));
cx.definition(ty, import)
.with_context(|| format!("import `{name}` has the wrong type"))?;
}

View File

@@ -14,22 +14,23 @@ pub struct TypeChecker<'a> {
}
impl TypeChecker<'_> {
pub fn definition(&self, expected: &TypeDef, actual: &Definition) -> Result<()> {
pub fn definition(&self, expected: &TypeDef, actual: Option<&Definition>) -> Result<()> {
match *expected {
TypeDef::Module(t) => match actual {
Definition::Module(actual) => self.module(&self.types[t], actual),
_ => bail!("expected module found {}", actual.desc()),
Some(Definition::Module(actual)) => self.module(&self.types[t], actual),
_ => bail!("expected module found {}", desc(actual)),
},
TypeDef::ComponentInstance(t) => match actual {
Definition::Instance(actual) => self.instance(&self.types[t], actual),
_ => bail!("expected instance found {}", actual.desc()),
Some(Definition::Instance(actual)) => self.instance(&self.types[t], Some(actual)),
None => self.instance(&self.types[t], None),
_ => bail!("expected instance found {}", desc(actual)),
},
TypeDef::ComponentFunc(t) => match actual {
Definition::Func(actual) => self.func(t, actual),
_ => bail!("expected func found {}", actual.desc()),
Some(Definition::Func(actual)) => self.func(t, actual),
_ => bail!("expected func found {}", desc(actual)),
},
TypeDef::Component(_) => bail!("expected component found {}", actual.desc()),
TypeDef::Interface(_) => bail!("expected type found {}", actual.desc()),
TypeDef::Component(_) => bail!("expected component found {}", desc(actual)),
TypeDef::Interface(_) => bail!("expected type found {}", desc(actual)),
// not possible for valid components to import
TypeDef::CoreFunc(_) => unreachable!(),
@@ -67,7 +68,7 @@ impl TypeChecker<'_> {
Ok(())
}
fn instance(&self, expected: &TypeComponentInstance, actual: &NameMap) -> Result<()> {
fn instance(&self, expected: &TypeComponentInstance, actual: Option<&NameMap>) -> Result<()> {
// Like modules, every export in the expected type must be present in
// the actual type. It's ok, though, to have extra exports in the actual
// type.
@@ -81,8 +82,7 @@ impl TypeChecker<'_> {
let actual = self
.strings
.lookup(name)
.and_then(|name| actual.get(&name))
.ok_or_else(|| anyhow!("instance export `{name}` not defined"))?;
.and_then(|name| actual?.get(&name));
self.definition(expected, actual)
.with_context(|| format!("instance export `{name}` has the wrong type"))?;
}
@@ -94,6 +94,13 @@ impl TypeChecker<'_> {
}
}
fn desc(def: Option<&Definition>) -> &'static str {
match def {
Some(def) => def.desc(),
None => "nothing",
}
}
impl Definition {
fn desc(&self) -> &'static str {
match self {