mirror of
https://github.com/tokio-rs/tokio.git
synced 2025-09-25 12:00:35 +00:00
macros: improve diagnostics on type mismatch (#3766)
This commit is contained in:
parent
05c3cf3a0a
commit
f9ce18a524
8
tests-build/tests/fail/macros_dead_code.rs
Normal file
8
tests-build/tests/fail/macros_dead_code.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![deny(dead_code)]
|
||||
|
||||
use tests_build::tokio;
|
||||
|
||||
#[tokio::main]
|
||||
async fn f() {}
|
||||
|
||||
fn main() {}
|
11
tests-build/tests/fail/macros_dead_code.stderr
Normal file
11
tests-build/tests/fail/macros_dead_code.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error: function is never used: `f`
|
||||
--> $DIR/macros_dead_code.rs:6:10
|
||||
|
|
||||
6 | async fn f() {}
|
||||
| ^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/macros_dead_code.rs:1:9
|
||||
|
|
||||
1 | #![deny(dead_code)]
|
||||
| ^^^^^^^^^
|
32
tests-build/tests/fail/macros_type_mismatch.rs
Normal file
32
tests-build/tests/fail/macros_type_mismatch.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use tests_build::tokio;
|
||||
|
||||
#[tokio::main]
|
||||
async fn missing_semicolon_or_return_type() {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn missing_return_type() {
|
||||
/* TODO(taiki-e): one of help messages still wrong
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
16 | return Ok(());;
|
||||
|
|
||||
*/
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn extra_semicolon() -> Result<(), ()> {
|
||||
/* TODO(taiki-e): help message still wrong
|
||||
help: try using a variant of the expected enum
|
||||
|
|
||||
29 | Ok(Ok(());)
|
||||
|
|
||||
29 | Err(Ok(());)
|
||||
|
|
||||
*/
|
||||
Ok(());
|
||||
}
|
||||
|
||||
fn main() {}
|
51
tests-build/tests/fail/macros_type_mismatch.stderr
Normal file
51
tests-build/tests/fail/macros_type_mismatch.stderr
Normal file
@ -0,0 +1,51 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/macros_type_mismatch.rs:5:5
|
||||
|
|
||||
5 | Ok(())
|
||||
| ^^^^^^ expected `()`, found enum `Result`
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found enum `Result<(), _>`
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
5 | Ok(());
|
||||
| ^
|
||||
help: try adding a return type
|
||||
|
|
||||
4 | async fn missing_semicolon_or_return_type() -> Result<(), _> {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/macros_type_mismatch.rs:16:5
|
||||
|
|
||||
16 | return Ok(());
|
||||
| ^^^^^^^^^^^^^^ expected `()`, found enum `Result`
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found enum `Result<(), _>`
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
16 | return Ok(());;
|
||||
| ^
|
||||
help: try adding a return type
|
||||
|
|
||||
9 | async fn missing_return_type() -> Result<(), _> {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/macros_type_mismatch.rs:29:5
|
||||
|
|
||||
20 | async fn extra_semicolon() -> Result<(), ()> {
|
||||
| -------------- expected `Result<(), ()>` because of return type
|
||||
...
|
||||
29 | Ok(());
|
||||
| ^^^^^^^ expected enum `Result`, found `()`
|
||||
|
|
||||
= note: expected enum `Result<(), ()>`
|
||||
found unit type `()`
|
||||
help: try using a variant of the expected enum
|
||||
|
|
||||
29 | Ok(Ok(());)
|
||||
|
|
||||
29 | Err(Ok(());)
|
||||
|
|
@ -8,6 +8,12 @@ fn compile_fail_full() {
|
||||
#[cfg(feature = "full")]
|
||||
t.compile_fail("tests/fail/macros_invalid_input.rs");
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
t.compile_fail("tests/fail/macros_dead_code.rs");
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
t.compile_fail("tests/fail/macros_type_mismatch.rs");
|
||||
|
||||
#[cfg(all(feature = "rt", not(feature = "full")))]
|
||||
t.compile_fail("tests/fail/macros_core_no_default.rs");
|
||||
|
||||
|
@ -26,7 +26,7 @@ proc-macro = true
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0.7"
|
||||
quote = "1"
|
||||
syn = { version = "1.0.3", features = ["full"] }
|
||||
syn = { version = "1.0.56", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
|
||||
|
@ -1,6 +1,6 @@
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Span;
|
||||
use quote::quote;
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum RuntimeFlavor {
|
||||
@ -278,11 +278,29 @@ fn parse_knobs(
|
||||
|
||||
let config = config.build()?;
|
||||
|
||||
// If type mismatch occurs, the current rustc points to the last statement.
|
||||
let (last_stmt_start_span, last_stmt_end_span) = {
|
||||
let mut last_stmt = input
|
||||
.block
|
||||
.stmts
|
||||
.last()
|
||||
.map(ToTokens::into_token_stream)
|
||||
.unwrap_or_default()
|
||||
.into_iter();
|
||||
// `Span` on stable Rust has a limitation that only points to the first
|
||||
// token, not the whole tokens. We can work around this limitation by
|
||||
// using the first/last span of the tokens like
|
||||
// `syn::Error::new_spanned` does.
|
||||
let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
|
||||
let end = last_stmt.last().map_or(start, |t| t.span());
|
||||
(start, end)
|
||||
};
|
||||
|
||||
let mut rt = match config.flavor {
|
||||
RuntimeFlavor::CurrentThread => quote! {
|
||||
RuntimeFlavor::CurrentThread => quote_spanned! {last_stmt_start_span=>
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
},
|
||||
RuntimeFlavor::Threaded => quote! {
|
||||
RuntimeFlavor::Threaded => quote_spanned! {last_stmt_start_span=>
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
},
|
||||
};
|
||||
@ -302,7 +320,8 @@ fn parse_knobs(
|
||||
};
|
||||
|
||||
let body = &input.block;
|
||||
input.block = syn::parse_quote! {
|
||||
let brace_token = input.block.brace_token;
|
||||
input.block = syn::parse2(quote_spanned! {last_stmt_end_span=>
|
||||
{
|
||||
#rt
|
||||
.enable_all()
|
||||
@ -310,7 +329,9 @@ fn parse_knobs(
|
||||
.unwrap()
|
||||
.block_on(async #body)
|
||||
}
|
||||
};
|
||||
})
|
||||
.unwrap();
|
||||
input.block.brace_token = brace_token;
|
||||
|
||||
let result = quote! {
|
||||
#header
|
||||
|
@ -21,7 +21,20 @@ async fn test_macro_is_resilient_to_shadowing() {
|
||||
// https://github.com/tokio-rs/tokio/issues/3403
|
||||
#[rustfmt::skip] // this `rustfmt::skip` is necessary because unused_braces does not warn if the block contains newline.
|
||||
#[tokio::main]
|
||||
async fn unused_braces_main() { println!("hello") }
|
||||
pub async fn unused_braces_main() { println!("hello") }
|
||||
#[rustfmt::skip] // this `rustfmt::skip` is necessary because unused_braces does not warn if the block contains newline.
|
||||
#[tokio::test]
|
||||
async fn unused_braces_test() { assert_eq!(1 + 1, 2) }
|
||||
|
||||
// https://github.com/tokio-rs/tokio/pull/3766#issuecomment-835508651
|
||||
#[std::prelude::v1::test]
|
||||
fn trait_method() {
|
||||
trait A {
|
||||
fn f(self);
|
||||
}
|
||||
impl A for () {
|
||||
#[tokio::main]
|
||||
async fn f(self) {}
|
||||
}
|
||||
().f()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user