-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve diagnostics for mismatched type in async main
#3039
Conversation
Previously, we wrapped the body of the `async main` function in an `async` block, which we passed to `block_on`. However, `block_on` is generic, so an incorrect return type ends up creating a diagnostic pointing a `block_on`, not the user's code. Since the call to `block_on` is generated by the `#[tokio::main]` macro, it ended up with a span of the `#[tokio::main]` attribute, producing a confusing diagnostic. We now wrap the body of the `async main` function in a new `async main_inner` function. This asserts a return type of `()` earlier on, producing a diagnostic. Given this code: ```rust async fn main() { Ok(()) } ``` We currently produce the error: ``` error[E0308]: mismatched types --> src/main.rs:1:1 | 1 | #[tokio::main] | ^^^^^^^^^^^^^^- help: try adding a semicolon: `;` | | | expected `()`, found enum `std::result::Result` | = note: expected unit type `()` found enum `std::result::Result<(), _>` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) ``` With this PR, we produce: ``` error[E0308]: mismatched types --> src/main.rs:3:5 | 3 | Ok(()) | ^^^^^^- help: try adding a semicolon: `;` | | | expected `()`, found enum `std::result::Result` | = note: expected unit type `()` found enum `std::result::Result<(), _>` ```
d770695
to
8b060aa
Compare
I didn't realize that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR. Unfortunately, this approach (split an async fn to two async or normal fns) causes a breaking change because #[tokio::main]
accepts arguments. The self
argument can be handled in the same way as async-trait, but we know that some regressions occur. (see dtolnay/async-trait#122 (comment))
If macro generate code like the following, it should work. block_on(async {
let res: #return_ty = #body;
return res;
}) (Note: If the return type contains impl trait, macro should omit the generation of |
@Aaron1011 Are you interested in continuing to work on this PR? |
Previously, we wrapped the body of the
async main
function in anasync
block, which we passed toblock_on
. However,block_on
isgeneric, so an incorrect return type ends up creating a diagnostic
pointing a
block_on
, not the user's code. Since the call toblock_on
is generated by the
#[tokio::main]
macro, it ended up with a span ofthe
#[tokio::main]
attribute, producing a confusing diagnostic.We now wrap the body of the
async main
function in a newasync main_inner
function. This asserts a return type of()
earlieron, producing a diagnostic.
Given this code:
We currently produce the error:
With this PR, we produce:
Tokio doesn't appear to have any kind of UI testing setup, so I'm not sure how to test the error message produced here.