Skip to content

Commit 961af12

Browse files
authored
futures-macro: improve diagnostics on type mismatch (#2433)
1 parent 5ea04ca commit 961af12

File tree

3 files changed

+40
-12
lines changed

3 files changed

+40
-12
lines changed

futures-macro/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ autocfg = "1"
2323
proc-macro2 = "1.0"
2424
proc-macro-hack = "0.5.19"
2525
quote = "1.0"
26-
syn = { version = "1.0", features = ["full"] }
26+
syn = { version = "1.0.56", features = ["full"] }

futures-macro/src/executor.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use proc_macro::TokenStream;
2-
use quote::quote;
2+
use proc_macro2::Span;
3+
use quote::{quote, quote_spanned, ToTokens};
34

45
pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
56
if !args.is_empty() {
@@ -9,23 +10,45 @@ pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
910
}
1011

1112
let mut input = syn::parse_macro_input!(item as syn::ItemFn);
12-
let attrs = &input.attrs;
13-
let vis = &input.vis;
14-
let sig = &mut input.sig;
15-
let body = &input.block;
1613

17-
if sig.asyncness.take().is_none() {
18-
return syn::Error::new_spanned(sig.fn_token, "Only async functions are supported")
14+
if input.sig.asyncness.take().is_none() {
15+
return syn::Error::new_spanned(input.sig.fn_token, "Only async functions are supported")
1916
.to_compile_error()
2017
.into();
2118
}
2219

20+
// If type mismatch occurs, the current rustc points to the last statement.
21+
let (last_stmt_start_span, last_stmt_end_span) = {
22+
let mut last_stmt = input
23+
.block
24+
.stmts
25+
.last()
26+
.map(ToTokens::into_token_stream)
27+
.unwrap_or_default()
28+
.into_iter();
29+
// `Span` on stable Rust has a limitation that only points to the first
30+
// token, not the whole tokens. We can work around this limitation by
31+
// using the first/last span of the tokens like
32+
// `syn::Error::new_spanned` does.
33+
let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
34+
let end = last_stmt.last().map_or(start, |t| t.span());
35+
(start, end)
36+
};
37+
38+
let path = quote_spanned! {last_stmt_start_span=>
39+
::futures_test::__private
40+
};
41+
let body = &input.block;
42+
input.block.stmts = vec![syn::Stmt::Expr(
43+
syn::parse2(quote_spanned! {last_stmt_end_span=>
44+
#path::block_on(async #body)
45+
})
46+
.unwrap(),
47+
)];
48+
2349
let gen = quote! {
2450
#[::core::prelude::v1::test]
25-
#(#attrs)*
26-
#vis #sig {
27-
::futures_test::__private::block_on(async move #body)
28-
}
51+
#input
2952
};
3053

3154
gen.into()

futures/tests/test_macro.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ async fn it_is_being_run() {
1313
let fut = async { false };
1414
assert!(fut.await);
1515
}
16+
17+
#[futures_test::test]
18+
async fn return_ty() -> Result<(), ()> {
19+
Ok(())
20+
}

0 commit comments

Comments
 (0)