diff --git a/crates/wasmtime/src/linker.rs b/crates/wasmtime/src/linker.rs index 9eb91506eb..0ea313dd07 100644 --- a/crates/wasmtime/src/linker.rs +++ b/crates/wasmtime/src/linker.rs @@ -5,7 +5,7 @@ use crate::{ AsContextMut, Caller, Engine, Extern, ExternType, Func, FuncType, ImportType, Instance, IntoFunc, Module, StoreContextMut, Trap, Val, ValRaw, }; -use anyhow::{anyhow, bail, Context, Error, Result}; +use anyhow::{anyhow, bail, Context, Result}; use log::warn; use std::collections::hash_map::{Entry, HashMap}; #[cfg(feature = "async")] @@ -1040,22 +1040,11 @@ impl Linker { let store = store.as_context_mut().0; let imports = module .imports() - .map(|import| { - self._get_by_import(&import) - .ok_or_else(|| self.link_error(&import)) - }) + .map(|import| self._get_by_import(&import)) .collect::>()?; unsafe { InstancePre::new(store, module, imports) } } - fn link_error(&self, import: &ImportType) -> Error { - let desc = match import.name() { - Some(name) => format!("{}::{}", import.module(), name), - None => import.module().to_string(), - }; - anyhow!("unknown import: `{}` has not been defined", desc) - } - /// Returns an iterator over all items defined in this `Linker`, in /// arbitrary order. /// @@ -1133,16 +1122,20 @@ impl Linker { ) -> Option { let store = store.as_context_mut().0; // Should be safe since `T` is connecting the linker and store - Some(unsafe { self._get_by_import(import)?.to_extern(store) }) + Some(unsafe { self._get_by_import(import).ok()?.to_extern(store) }) } - fn _get_by_import(&self, import: &ImportType) -> Option { - if let Some(item) = self._get(import.module(), import.name()) { - return Some(item.clone()); + fn _get_by_import(&self, import: &ImportType) -> anyhow::Result { + fn undef_err(missing_import: &str) -> anyhow::Error { + anyhow!("unknown import: `{}` has not been defined", missing_import) } - if import.name().is_some() { - return None; + if let Some(item) = self._get(import.module(), import.name()) { + return Ok(item.clone()); + } + + if let Some(name) = import.name() { + return Err(undef_err(&format!("{}::{}", import.module(), name))); } if let ExternType::Instance(t) = import.ty() { @@ -1163,13 +1156,15 @@ impl Linker { // suffice. let mut map = indexmap::IndexMap::new(); for export in t.exports() { - let item = self._get(import.module(), Some(export.name()))?; + let item = self + ._get(import.module(), Some(export.name())) + .ok_or_else(|| undef_err(&format!("{}::{}", import.module(), export.name())))?; map.insert(export.name().to_string(), item.clone()); } - return Some(Definition::Instance(Arc::new(map))); + return Ok(Definition::Instance(Arc::new(map))); } - None + Err(undef_err(&import.module())) } /// Returns the "default export" of a module. diff --git a/tests/all/linker.rs b/tests/all/linker.rs index f89adb0301..da4929810a 100644 --- a/tests/all/linker.rs +++ b/tests/all/linker.rs @@ -23,6 +23,34 @@ fn link_undefined() -> Result<()> { Ok(()) } +#[test] +fn undefined_error_message_with_linking() { + let mut config = Config::new(); + config.wasm_module_linking(true); + let engine = Engine::new(&config).unwrap(); + let module = Module::new( + &engine, + r#" + (module + (import "foo" "bar" (func)) + ) + "#, + ) + .unwrap(); + let linker = Linker::new(&engine); + let mut store = Store::new(&engine, ()); + assert!(linker + .instantiate(&mut store, &module) + .unwrap_err() + .to_string() + .contains("foo")); + assert!(linker + .instantiate(&mut store, &module) + .unwrap_err() + .to_string() + .contains("bar")); +} + #[test] fn link_twice_bad() -> Result<()> { let mut store = Store::<()>::default();