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")]
|
#[cfg(feature = "full")]
|
||||||
t.compile_fail("tests/fail/macros_invalid_input.rs");
|
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")))]
|
#[cfg(all(feature = "rt", not(feature = "full")))]
|
||||||
t.compile_fail("tests/fail/macros_core_no_default.rs");
|
t.compile_fail("tests/fail/macros_core_no_default.rs");
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ proc-macro = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "1.0.7"
|
proc-macro2 = "1.0.7"
|
||||||
quote = "1"
|
quote = "1"
|
||||||
syn = { version = "1.0.3", features = ["full"] }
|
syn = { version = "1.0.56", features = ["full"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
|
tokio = { version = "1.0.0", path = "../tokio", features = ["full"] }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
use quote::quote;
|
use quote::{quote, quote_spanned, ToTokens};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
enum RuntimeFlavor {
|
enum RuntimeFlavor {
|
||||||
@ -278,11 +278,29 @@ fn parse_knobs(
|
|||||||
|
|
||||||
let config = config.build()?;
|
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 {
|
let mut rt = match config.flavor {
|
||||||
RuntimeFlavor::CurrentThread => quote! {
|
RuntimeFlavor::CurrentThread => quote_spanned! {last_stmt_start_span=>
|
||||||
tokio::runtime::Builder::new_current_thread()
|
tokio::runtime::Builder::new_current_thread()
|
||||||
},
|
},
|
||||||
RuntimeFlavor::Threaded => quote! {
|
RuntimeFlavor::Threaded => quote_spanned! {last_stmt_start_span=>
|
||||||
tokio::runtime::Builder::new_multi_thread()
|
tokio::runtime::Builder::new_multi_thread()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -302,7 +320,8 @@ fn parse_knobs(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let body = &input.block;
|
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
|
#rt
|
||||||
.enable_all()
|
.enable_all()
|
||||||
@ -310,7 +329,9 @@ fn parse_knobs(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.block_on(async #body)
|
.block_on(async #body)
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
.unwrap();
|
||||||
|
input.block.brace_token = brace_token;
|
||||||
|
|
||||||
let result = quote! {
|
let result = quote! {
|
||||||
#header
|
#header
|
||||||
|
@ -21,7 +21,20 @@ async fn test_macro_is_resilient_to_shadowing() {
|
|||||||
// https://github.com/tokio-rs/tokio/issues/3403
|
// 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.
|
#[rustfmt::skip] // this `rustfmt::skip` is necessary because unused_braces does not warn if the block contains newline.
|
||||||
#[tokio::main]
|
#[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.
|
#[rustfmt::skip] // this `rustfmt::skip` is necessary because unused_braces does not warn if the block contains newline.
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn unused_braces_test() { assert_eq!(1 + 1, 2) }
|
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