Skip to content

Commit bc5f73e

Browse files
authored
Merge pull request #1550 from alexcrichton/more-better-errors
Improve diagnostics with missing trait implementations
2 parents b96186e + 2cbb8b8 commit bc5f73e

7 files changed

+104
-34
lines changed

crates/backend/src/codegen.rs

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -197,18 +197,23 @@ impl ToTokens for ast::Struct {
197197
impl wasm_bindgen::__rt::core::convert::From<#name> for
198198
wasm_bindgen::JsValue
199199
{
200-
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
201200
fn from(value: #name) -> Self {
202201
let ptr = wasm_bindgen::convert::IntoWasmAbi::into_abi(
203202
value,
204203
unsafe { &mut wasm_bindgen::convert::GlobalStack::new() },
205204
);
206205

207206
#[link(wasm_import_module = "__wbindgen_placeholder__")]
207+
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
208208
extern "C" {
209209
fn #new_fn(ptr: u32) -> u32;
210210
}
211211

212+
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
213+
unsafe fn #new_fn(ptr: u32) -> u32 {
214+
panic!("cannot convert to JsValue outside of the wasm target")
215+
}
216+
212217
unsafe {
213218
<wasm_bindgen::JsValue as wasm_bindgen::convert::FromWasmAbi>
214219
::from_abi(
@@ -217,11 +222,6 @@ impl ToTokens for ast::Struct {
217222
)
218223
}
219224
}
220-
221-
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
222-
fn from(_value: #name) -> Self {
223-
panic!("cannot convert to JsValue outside of the wasm target")
224-
}
225225
}
226226

227227
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
@@ -712,24 +712,22 @@ impl ToTokens for ast::ImportType {
712712
}
713713

714714
impl JsCast for #rust_name {
715-
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
716715
fn instanceof(val: &JsValue) -> bool {
717716
#[link(wasm_import_module = "__wbindgen_placeholder__")]
717+
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
718718
extern "C" {
719719
fn #instanceof_shim(val: u32) -> u32;
720720
}
721+
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
722+
unsafe fn #instanceof_shim(val: u32) -> u32 {
723+
panic!("cannot check instanceof on non-wasm targets");
724+
}
721725
unsafe {
722726
let idx = val.into_abi(&mut wasm_bindgen::convert::GlobalStack::new());
723727
#instanceof_shim(idx) != 0
724728
}
725729
}
726730

727-
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
728-
fn instanceof(val: &JsValue) -> bool {
729-
drop(val);
730-
panic!("cannot check instanceof on non-wasm targets");
731-
}
732-
733731
#is_type_of
734732

735733
#[inline]
@@ -998,6 +996,7 @@ impl TryToTokens for ast::ImportFunction {
998996
let import_name = &self.shim;
999997
let attrs = &self.function.rust_attrs;
1000998
let arguments = &arguments;
999+
let abi_arguments = &abi_arguments;
10011000

10021001
let doc_comment = match &self.doc_comment {
10031002
None => "",
@@ -1009,17 +1008,45 @@ impl TryToTokens for ast::ImportFunction {
10091008
quote!()
10101009
};
10111010

1011+
// Route any errors pointing to this imported function to the identifier
1012+
// of the function we're imported from so we at least know what function
1013+
// is causing issues.
1014+
//
1015+
// Note that this is where type errors like "doesn't implement
1016+
// FromWasmAbi" or "doesn't implement IntoWasmAbi" currently get routed.
1017+
// I suspect that's because they show up in the signature via trait
1018+
// projections as types of arguments, and all that needs to typecheck
1019+
// before the body can be typechecked. Due to rust-lang/rust#60980 (and
1020+
// probably related issues) we can't really get a precise span.
1021+
//
1022+
// Ideally what we want is to point errors for particular types back to
1023+
// the specific argument/type that generated the error, but it looks
1024+
// like rustc itself doesn't do great in that regard so let's just do
1025+
// the best we can in the meantime.
1026+
let extern_fn = respan(
1027+
quote! {
1028+
#[link(wasm_import_module = "__wbindgen_placeholder__")]
1029+
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
1030+
extern "C" {
1031+
fn #import_name(#(#abi_arguments),*) -> #abi_ret;
1032+
}
1033+
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
1034+
unsafe fn #import_name(#(#abi_arguments),*) -> #abi_ret {
1035+
panic!("cannot call wasm-bindgen imported functions on \
1036+
non-wasm targets");
1037+
}
1038+
},
1039+
&self.rust_name,
1040+
);
1041+
10121042
let invocation = quote! {
10131043
#(#attrs)*
10141044
#[allow(bad_style)]
1015-
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
10161045
#[doc = #doc_comment]
10171046
#[allow(clippy::all)]
10181047
#vis fn #rust_name(#me #(#arguments),*) #ret {
1019-
#[link(wasm_import_module = "__wbindgen_placeholder__")]
1020-
extern "C" {
1021-
fn #import_name(#(#abi_arguments),*) -> #abi_ret;
1022-
}
1048+
#extern_fn
1049+
10231050
unsafe {
10241051
#exn_data
10251052
let #ret_ident = {
@@ -1031,17 +1058,6 @@ impl TryToTokens for ast::ImportFunction {
10311058
#convert_ret
10321059
}
10331060
}
1034-
1035-
#(#attrs)*
1036-
#[allow(bad_style, unused_variables)]
1037-
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
1038-
#[doc = #doc_comment]
1039-
#[allow(clippy::all)]
1040-
#vis fn #rust_name(#me #(#arguments),*) #ret {
1041-
panic!("cannot call wasm-bindgen imported functions on \
1042-
non-wasm targets");
1043-
}
1044-
10451061
};
10461062

10471063
if let Some(class) = class_ty {
@@ -1164,12 +1180,17 @@ impl ToTokens for ast::ImportStatic {
11641180
#[allow(bad_style)]
11651181
#[allow(clippy::all)]
11661182
#vis static #name: wasm_bindgen::JsStatic<#ty> = {
1167-
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
11681183
fn init() -> #ty {
11691184
#[link(wasm_import_module = "__wbindgen_placeholder__")]
1185+
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
11701186
extern "C" {
11711187
fn #shim_name() -> <#ty as wasm_bindgen::convert::FromWasmAbi>::Abi;
11721188
}
1189+
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
1190+
unsafe fn #shim_name() -> <#ty as wasm_bindgen::convert::FromWasmAbi>::Abi {
1191+
panic!("cannot access imported statics on non-wasm targets")
1192+
}
1193+
11731194
unsafe {
11741195
<#ty as wasm_bindgen::convert::FromWasmAbi>::from_abi(
11751196
#shim_name(),
@@ -1178,10 +1199,6 @@ impl ToTokens for ast::ImportStatic {
11781199

11791200
}
11801201
}
1181-
#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
1182-
fn init() -> #ty {
1183-
panic!("cannot access imported statics on non-wasm targets")
1184-
}
11851202
thread_local!(static _VAL: #ty = init(););
11861203
wasm_bindgen::JsStatic {
11871204
__inner: &_VAL,
@@ -1449,6 +1466,8 @@ impl<'a, T: ToTokens> ToTokens for Descriptor<'a, T> {
14491466
}
14501467
}
14511468

1469+
/// Converts `span` into a stream of tokens, and attempts to ensure that `input`
1470+
/// has all the appropriate span information so errors in it point to `span`.
14521471
fn respan(input: TokenStream, span: &dyn ToTokens) -> TokenStream {
14531472
let mut first_span = Span::call_site();
14541473
let mut last_span = Span::call_site();
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen]
4+
extern "C" {
5+
#[wasm_bindgen]
6+
pub fn foo() -> Result<JsValue, JsValue>;
7+
}
8+
9+
fn main() {}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error[E0277]: the trait bound `std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>: wasm_bindgen::convert::traits::FromWasmAbi` is not satisfied
2+
--> $DIR/missing-catch.rs:6:9
3+
|
4+
6 | pub fn foo() -> Result<JsValue, JsValue>;
5+
| ^^^ the trait `wasm_bindgen::convert::traits::FromWasmAbi` is not implemented for `std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>`
6+
7+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
struct A;
4+
5+
#[wasm_bindgen]
6+
extern "C" {
7+
#[wasm_bindgen]
8+
pub fn foo(a: A);
9+
}
10+
11+
fn main() {}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error[E0277]: the trait bound `A: wasm_bindgen::convert::traits::IntoWasmAbi` is not satisfied
2+
--> $DIR/traits-not-implemented.rs:8:12
3+
|
4+
8 | pub fn foo(a: A);
5+
| ^^^ the trait `wasm_bindgen::convert::traits::IntoWasmAbi` is not implemented for `A`
6+
7+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen]
4+
extern "C" {
5+
#[wasm_bindgen]
6+
pub fn foo(a: A);
7+
}
8+
9+
fn main() {}
10+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error[E0412]: cannot find type `A` in this scope
2+
--> $DIR/unknown-type-in-import.rs:6:19
3+
|
4+
6 | pub fn foo(a: A);
5+
| ^ not found in this scope
6+
7+
For more information about this error, try `rustc --explain E0412`.

0 commit comments

Comments
 (0)