From 43f5499f82354a9ef9f7c04c4fc076a0f73d07da Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 26 Dec 2025 14:28:51 +0530 Subject: [PATCH 01/10] fixed the macro issue where it returned the wrong return type in some cases --- tokio-macros/src/entry.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 09c6c48a445..ce0de74268a 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -494,22 +494,31 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt // // We don't do this for the main function as it should only be used once so // there will be no benefit. + // We don't do this for the main function as it should only be used once so + // there will be no benefit. + let output_type = match &input.sig.output { + // For functions with no return value syn doesn't print anything, + // but that doesn't work as `Output` for our boxed `Future`, so + // default to `()` (the same type as the function output). + syn::ReturnType::Default => quote! { () }, + syn::ReturnType::Type(_, ret_type) => quote! { #ret_type }, + }; + let body = if is_test { - let output_type = match &input.sig.output { - // For functions with no return value syn doesn't print anything, - // but that doesn't work as `Output` for our boxed `Future`, so - // default to `()` (the same type as the function output). - syn::ReturnType::Default => quote! { () }, - syn::ReturnType::Type(_, ret_type) => quote! { #ret_type }, - }; quote! { let body = async #body; #crate_path::pin!(body); let body: ::core::pin::Pin<&mut dyn ::core::future::Future> = body; } } else { + //force typecheck without runtime overhead quote! { let body = async #body; + //identity function that constraints the future's output type to ensure better error messages + let body = { + fn check_output>(f: F) -> F { f } + check_output(body) + }; } }; From f7d2d1d59805e9c9ccb9ea6dd54d546843494632 Mon Sep 17 00:00:00 2001 From: daschinmoy21 Date: Sat, 27 Dec 2025 17:26:33 +0530 Subject: [PATCH 02/10] fixed wrong expected return type bug --- .gitignore | 1 + tokio-macros/src/entry.rs | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 32ec3fe4b79..0d525ab5819 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ Cargo.lock .cargo/config.toml .cargo/config + diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index ce0de74268a..815ec893064 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -494,9 +494,7 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt // // We don't do this for the main function as it should only be used once so // there will be no benefit. - // We don't do this for the main function as it should only be used once so - // there will be no benefit. - let output_type = match &input.sig.output { + ; let output_type = match &input.sig.output { // For functions with no return value syn doesn't print anything, // but that doesn't work as `Output` for our boxed `Future`, so // default to `()` (the same type as the function output). @@ -511,10 +509,10 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt let body: ::core::pin::Pin<&mut dyn ::core::future::Future> = body; } } else { - //force typecheck without runtime overhead + // force typecheck without runtime overhead quote! { let body = async #body; - //identity function that constraints the future's output type to ensure better error messages + // identity function that constraints the future's output type to ensure better error messages let body = { fn check_output>(f: F) -> F { f } check_output(body) From 05c54d7a367c7941fcca9152d35d358bd66d3cd2 Mon Sep 17 00:00:00 2001 From: daschinmoy21 Date: Wed, 14 Jan 2026 21:49:30 +0530 Subject: [PATCH 03/10] fix(macros): improve error message for return type mismatch in #[tokio::main] --- tokio-macros/src/entry.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 815ec893064..ac710c35b71 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -494,7 +494,7 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt // // We don't do this for the main function as it should only be used once so // there will be no benefit. - ; let output_type = match &input.sig.output { + let output_type = match &input.sig.output { // For functions with no return value syn doesn't print anything, // but that doesn't work as `Output` for our boxed `Future`, so // default to `()` (the same type as the function output). @@ -509,10 +509,10 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt let body: ::core::pin::Pin<&mut dyn ::core::future::Future> = body; } } else { - // force typecheck without runtime overhead + // force typecheck without runtime overhead quote! { let body = async #body; - // identity function that constraints the future's output type to ensure better error messages + // identity function that constrains the future's output type to ensure better error messages let body = { fn check_output>(f: F) -> F { f } check_output(body) From a9c4ffa81164354a29924d25da0d4d13e7c5d11c Mon Sep 17 00:00:00 2001 From: daschinmoy21 Date: Wed, 14 Jan 2026 22:23:41 +0530 Subject: [PATCH 04/10] fix:dead code assertation to support generics E0401 --- tokio-macros/src/entry.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index ac710c35b71..75d2f8b2b30 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -514,8 +514,10 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt let body = async #body; // identity function that constrains the future's output type to ensure better error messages let body = { - fn check_output>(f: F) -> F { f } - check_output(body) + if false { + let _: &dyn ::core::future::Future = &body; + } + body }; } }; From cb8f45958943f0a4397c92971af1c208d4d4cb23 Mon Sep 17 00:00:00 2001 From: daschinmoy21 Date: Wed, 14 Jan 2026 22:32:23 +0530 Subject: [PATCH 05/10] skipped check for ! return types --- tokio-macros/src/entry.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 75d2f8b2b30..717a9bb98ca 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -510,13 +510,20 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt } } else { // force typecheck without runtime overhead - quote! { - let body = async #body; - // identity function that constrains the future's output type to ensure better error messages - let body = { + let check_block = match &input.sig.output { + syn::ReturnType::Type(_, t) if matches!(**t, syn::Type::Never(_)) => quote! {}, + _ => quote! { if false { let _: &dyn ::core::future::Future = &body; } + }, + }; + + quote! { + let body = async #body; + // Compile-time assertion that the future's output matches the return type. + let body = { + #check_block body }; } From de08ca97e247c36ca2b42e1141338eca0d3c1e4a Mon Sep 17 00:00:00 2001 From: daschinmoy21 Date: Wed, 14 Jan 2026 22:39:41 +0530 Subject: [PATCH 06/10] test: update expected errors for improved type mismatch messages --- .../tests/fail/macros_type_mismatch.stderr | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tests-build/tests/fail/macros_type_mismatch.stderr b/tests-build/tests/fail/macros_type_mismatch.stderr index c20dae30268..075ca6434ba 100644 --- a/tests-build/tests/fail/macros_type_mismatch.stderr +++ b/tests-build/tests/fail/macros_type_mismatch.stderr @@ -1,3 +1,14 @@ +error[E0271]: expected `{async block@$DIR/tests/fail/macros_type_mismatch.rs:3:1: 3:15}` to be a future that resolves to `()`, but it resolves to `Result<(), _>` + --> tests/fail/macros_type_mismatch.rs:3:1 + | +3 | #[tokio::main] + | ^^^^^^^^^^^^^^ expected `()`, found `Result<(), _>` + | + = note: expected unit type `()` + found enum `Result<(), _>` + = note: required for the cast from `&{async block@$DIR/tests/fail/macros_type_mismatch.rs:3:1: 3:15}` to `&dyn Future` + = note: this error originates in the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0308]: mismatched types --> tests/fail/macros_type_mismatch.rs:5:5 | @@ -15,6 +26,17 @@ help: consider using `Result::expect` to unwrap the `Result<(), _>` value, panic 5 | Ok(()).expect("REASON") | +++++++++++++++++ +error[E0271]: expected `{async block@$DIR/tests/fail/macros_type_mismatch.rs:8:1: 8:15}` to be a future that resolves to `()`, but it resolves to `Result<(), _>` + --> tests/fail/macros_type_mismatch.rs:8:1 + | +8 | #[tokio::main] + | ^^^^^^^^^^^^^^ expected `()`, found `Result<(), _>` + | + = note: expected unit type `()` + found enum `Result<(), _>` + = note: required for the cast from `&{async block@$DIR/tests/fail/macros_type_mismatch.rs:8:1: 8:15}` to `&dyn Future` + = note: this error originates in the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0308]: mismatched types --> tests/fail/macros_type_mismatch.rs:10:5 | @@ -32,6 +54,17 @@ help: consider using `Result::expect` to unwrap the `Result<(), _>` value, panic 10 | return Ok(());.expect("REASON") | +++++++++++++++++ +error[E0271]: expected `{async block@$DIR/tests/fail/macros_type_mismatch.rs:13:1: 13:15}` to be a future that resolves to `Result<(), ()>`, but it resolves to `()` + --> tests/fail/macros_type_mismatch.rs:13:1 + | +13 | #[tokio::main] + | ^^^^^^^^^^^^^^ expected `Result<(), ()>`, found `()` + | + = note: expected enum `Result<(), ()>` + found unit type `()` + = note: required for the cast from `&{async block@$DIR/tests/fail/macros_type_mismatch.rs:13:1: 13:15}` to `&dyn Future>` + = note: this error originates in the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0308]: mismatched types --> tests/fail/macros_type_mismatch.rs:23:5 | @@ -58,6 +91,17 @@ error[E0277]: the `?` operator can only be used in an async block that returns ` 40 | None?; | ^ cannot use the `?` operator in an async block that returns `()` +error[E0271]: expected `{async block@$DIR/tests/fail/macros_type_mismatch.rs:38:1: 38:15}` to be a future that resolves to `Option<()>`, but it resolves to `()` + --> tests/fail/macros_type_mismatch.rs:38:1 + | +38 | #[tokio::main] + | ^^^^^^^^^^^^^^ expected `Option<()>`, found `()` + | + = note: expected enum `Option<()>` + found unit type `()` + = note: required for the cast from `&{async block@$DIR/tests/fail/macros_type_mismatch.rs:38:1: 38:15}` to `&dyn Future>` + = note: this error originates in the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0308]: mismatched types --> tests/fail/macros_type_mismatch.rs:40:5 | @@ -86,6 +130,17 @@ error[E0277]: the `?` operator can only be used in an async block that returns ` 57 | Ok(())?; | ^ cannot use the `?` operator in an async block that returns `()` +error[E0271]: expected `{async block@$DIR/tests/fail/macros_type_mismatch.rs:55:1: 55:15}` to be a future that resolves to `Result<(), ()>`, but it resolves to `()` + --> tests/fail/macros_type_mismatch.rs:55:1 + | +55 | #[tokio::main] + | ^^^^^^^^^^^^^^ expected `Result<(), ()>`, found `()` + | + = note: expected enum `Result<(), ()>` + found unit type `()` + = note: required for the cast from `&{async block@$DIR/tests/fail/macros_type_mismatch.rs:55:1: 55:15}` to `&dyn Future>` + = note: this error originates in the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0308]: mismatched types --> tests/fail/macros_type_mismatch.rs:57:5 | @@ -102,6 +157,15 @@ help: try adding an expression at the end of the block 58 + Ok(()) | +error[E0271]: expected `{async block@$DIR/tests/fail/macros_type_mismatch.rs:63:1: 63:15}` to be a future that resolves to `()`, but it resolves to `{integer}` + --> tests/fail/macros_type_mismatch.rs:63:1 + | +63 | #[tokio::main] + | ^^^^^^^^^^^^^^ expected `()`, found integer + | + = note: required for the cast from `&{async block@$DIR/tests/fail/macros_type_mismatch.rs:63:1: 63:15}` to `&dyn Future` + = note: this error originates in the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0308]: mismatched types --> tests/fail/macros_type_mismatch.rs:66:5 | From 63d66ba3e4d29b3ff16902c18be33056ea454e88 Mon Sep 17 00:00:00 2001 From: daschinmoy21 Date: Sun, 18 Jan 2026 21:09:48 +0530 Subject: [PATCH 07/10] fix(macros): skip type check for impl Trait and ! return types --- tokio-macros/src/entry.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 717a9bb98ca..a2d61e3b830 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -511,7 +511,9 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt } else { // force typecheck without runtime overhead let check_block = match &input.sig.output { - syn::ReturnType::Type(_, t) if matches!(**t, syn::Type::Never(_)) => quote! {}, + syn::ReturnType::Type(_, t) if matches!(**t, syn::Type::Never(_) | syn::Type::ImplTrait(_)) => { + quote! {} + } _ => quote! { if false { let _: &dyn ::core::future::Future = &body; From 64c7908e85f9fc93bf9e8a339bbbe1b83827d974 Mon Sep 17 00:00:00 2001 From: daschinmoy21 Date: Sun, 18 Jan 2026 21:14:03 +0530 Subject: [PATCH 08/10] style: apply rustfmt to entry.rs --- tokio-macros/src/entry.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index a2d61e3b830..947f661b5d0 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -511,7 +511,9 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt } else { // force typecheck without runtime overhead let check_block = match &input.sig.output { - syn::ReturnType::Type(_, t) if matches!(**t, syn::Type::Never(_) | syn::Type::ImplTrait(_)) => { + syn::ReturnType::Type(_, t) + if matches!(**t, syn::Type::Never(_) | syn::Type::ImplTrait(_)) => + { quote! {} } _ => quote! { From 126d954a3abdba3c360e571a85cdac2d6bbf24e8 Mon Sep 17 00:00:00 2001 From: daschinmoy21 Date: Sun, 18 Jan 2026 21:34:23 +0530 Subject: [PATCH 09/10] ci: re-run checks From b611eaa7b3f8435d63c000f18d3fdf8d922a5697 Mon Sep 17 00:00:00 2001 From: daschinmoy21 Date: Sun, 18 Jan 2026 22:55:32 +0530 Subject: [PATCH 10/10] fix(macros): support nested impl Trait in return types --- tests-build/tests/pass/impl_trait.rs | 6 ++++++ tokio-macros/src/entry.rs | 31 +++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tests-build/tests/pass/impl_trait.rs b/tests-build/tests/pass/impl_trait.rs index e0b7b958371..5dfe6747f21 100644 --- a/tests-build/tests/pass/impl_trait.rs +++ b/tests-build/tests/pass/impl_trait.rs @@ -10,8 +10,14 @@ async fn impl_trait() -> impl Iterator { [()].into_iter() } +#[tokio::main] +async fn impl_trait2() -> Result<(), impl core::fmt::Debug> { + Err(()) +} + fn main() { if impl_trait().count() == 10 { never(); } + let _ = impl_trait2(); } diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 947f661b5d0..7328325aa51 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -293,6 +293,35 @@ fn parse_bool(bool: syn::Lit, span: Span, field: &str) -> Result bool { + match ty { + syn::Type::ImplTrait(_) => true, + syn::Type::Array(t) => contains_impl_trait(&t.elem), + syn::Type::Ptr(t) => contains_impl_trait(&t.elem), + syn::Type::Reference(t) => contains_impl_trait(&t.elem), + syn::Type::Slice(t) => contains_impl_trait(&t.elem), + syn::Type::Tuple(t) => t.elems.iter().any(contains_impl_trait), + syn::Type::Paren(t) => contains_impl_trait(&t.elem), + syn::Type::Group(t) => contains_impl_trait(&t.elem), + syn::Type::Path(t) => match t.path.segments.last() { + Some(segment) => match &segment.arguments { + syn::PathArguments::AngleBracketed(args) => args.args.iter().any(|arg| match arg { + syn::GenericArgument::Type(t) => contains_impl_trait(t), + syn::GenericArgument::AssocType(t) => contains_impl_trait(&t.ty), + _ => false, + }), + syn::PathArguments::Parenthesized(args) => { + args.inputs.iter().any(contains_impl_trait) + || matches!(&args.output, syn::ReturnType::Type(_, t) if contains_impl_trait(t)) + } + syn::PathArguments::None => false, + }, + None => false, + }, + _ => false, + } +} + fn build_config( input: &ItemFn, args: AttributeArgs, @@ -512,7 +541,7 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt // force typecheck without runtime overhead let check_block = match &input.sig.output { syn::ReturnType::Type(_, t) - if matches!(**t, syn::Type::Never(_) | syn::Type::ImplTrait(_)) => + if matches!(**t, syn::Type::Never(_)) || contains_impl_trait(t) => { quote! {} }