Skip to content

(macros): improve error message for return type mismatch in #[tokio::main]#7856

Merged
taiki-e merged 15 commits intotokio-rs:masterfrom
daschinmoy21:master
Jan 24, 2026
Merged

(macros): improve error message for return type mismatch in #[tokio::main]#7856
taiki-e merged 15 commits intotokio-rs:masterfrom
daschinmoy21:master

Conversation

@daschinmoy21
Copy link
Copy Markdown
Contributor

Motivation

Fixes #7784
When using #[tokio::main] with conflicting return statements, the error message was misleading:

#[tokio::main]
async fn main() -> () {
    if true {
        return 1;
    }
    return ();
}

The compiler would report:

error[E0308]: mismatched types
 --> src/main.rs:7:12
  |
7 |     return ();
  |            ^^ expected integer, found `()`

This blames return () (which matches the declared -> ()) instead of return 1.

Solution

Added a check_output identity function that explicitly constrains the async block's output type to match the declared function return type:

fn check_output<F: Future<Output = #output_type>>(f: F) -> F { f }
check_output(body)

This ensures the compiler reports type mismatches against the declared return type rather than an inferred type. The function has zero runtime overhead since it just returns its input unchanged.

After this change, the error is clearer:

error[E0308]: mismatched types
 --> src/main.rs:6:12
  |
6 |     return ();
  |            ^^ expected integer, found `()`
  |
note: return type inferred to be `{integer}` here
 --> src/main.rs:4:16
  |
4 |         return 1;
  |                ^

error[E0271]: expected `{async block@src/main.rs:1:1: 1:15}` to be a future that resolves to `()`, but it resolves to `{integer}`
 --> src/main.rs:1:1
  |
1 | #[tokio::main]
  | ^^^^^^^^^^^^^^ expected `()`, found integer
  |
note: required by a bound in `check_output`

@taiki-e
Copy link
Copy Markdown
Member

taiki-e commented Jan 15, 2026

As said in #6306 (comment) (and #3039 (comment) and #5619 (comment) and #6438 (comment)), this needs to handle cases where the impl trait is included in Output (tokio::main can be used for functions other than the main function). Alternatively, for now, you could restrict its use to functions that return a unit.

(I've mentioned this point repeatedly, so we should probably add a test case like the following.)

#[tokio::main]
async fn never() -> ! {
    loop {}
}
#[tokio::main]
async fn impl_trait() -> impl Iterator<Item = impl core::fmt::Debug> {
    [()].into_iter()
}

@ADD-SP ADD-SP added the S-waiting-on-author Status: awaiting some action (such as code changes) from the PR or issue author. label Jan 16, 2026
@daschinmoy21
Copy link
Copy Markdown
Contributor Author

Updated the PR as requested by @taiki-e
All checks pass.including test cases added in #7857 ,thanks to @Darksonn

Comment thread tokio-macros/src/entry.rs Outdated
@daschinmoy21
Copy link
Copy Markdown
Contributor Author

Added another test case where impl trait can also be placed inside other types, so previous check wasn't sufficient.

#[tokio::main]
async fn impl_trait2() -> Result<(), impl core::fmt::Debug> {
    Err(())
}

updated code and test case to cover this

Copy link
Copy Markdown
Member

@taiki-e taiki-e left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks @daschinmoy21!

@taiki-e taiki-e removed the S-waiting-on-author Status: awaiting some action (such as code changes) from the PR or issue author. label Jan 21, 2026
@daschinmoy21
Copy link
Copy Markdown
Contributor Author

any update on this @taiki-e ?

@taiki-e taiki-e merged commit 8f6d086 into tokio-rs:master Jan 24, 2026
88 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-tokio-macros Area: The tokio-macros crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error message is inaccurate in tokio::main macro

4 participants