-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Awaiting a function returning a never type does not warn for unreachable code after the await #128434
Labels
A-diagnostics
Area: Messages for errors, warnings, and lints
T-compiler
Relevant to the compiler team, which will review and decide on the PR/issue.
WG-async
Working group: Async & await
Comments
ungrichtepfl
added
A-diagnostics
Area: Messages for errors, warnings, and lints
T-compiler
Relevant to the compiler team, which will review and decide on the PR/issue.
labels
Jul 31, 2024
I'll take a look at this 👀 This almost certainly has something to do with the await desugaring into a poll loop |
tgross35
added a commit
to tgross35/rust
that referenced
this issue
Jul 31, 2024
… r=fmease Properly mark loop as diverging if it has no breaks Due to specifics about the desugaring of the `.await` operator, HIR typeck doesn't recognize that `.await`ing an `impl Future<Output = !>` will diverge in the same way as calling a `fn() -> !`. This is because the await operator desugars to approximately: ```rust loop { match future.poll(...) { Poll::Ready(x) => break x, Poll::Pending => {} } } ``` We know that the value of `x` is `!`, however since `break` is a coercion site, we coerce `!` to some `?0` (the type of the loop expression). Then since the type of the `loop {...}` expression is `?0`, we will not detect the loop as diverging like we do with other expressions that evaluate to `!`: https://github.com/rust-lang/rust/blob/0b5eb7ba7bd796fb39c8bb6acd9ef6c140f28b65/compiler/rustc_hir_typeck/src/expr.rs#L240-L243 We can technically fix this in two ways: 1. Make coercion of loop exprs more eagerly result in a type of `!` when the only break expressions have type `!`. 2. Make loops understand that all of that if they have only diverging break values, then the loop diverges as well. (1.) likely has negative effects on inference, and seems like a weird special case to drill into coercion. However, it turns out that (2.) is very easy to implement, we already record whether a loop has any break expressions, and when we do so, we actually skip over any break expressions with diverging values!: https://github.com/rust-lang/rust/blob/0b5eb7ba7bd796fb39c8bb6acd9ef6c140f28b65/compiler/rustc_hir_typeck/src/expr.rs#L713-L716 Thus, we can consider the loop as diverging if we see that it has no breaks, which is the change implemented in this PR. This is not usually a problem in regular code for two reasons: 1. In regular code, we already mark `break diverging()` as unreachable if `diverging()` is unreachable. We don't do this for `.await`, since we suppress unreachable errors within `.await` (rust-lang#64930). Un-suppressing this code will result in spurious unreachable expression errors pointing to internal await machinery. 3. In loops that truly have no breaks (e.g. `loop {}`), we already evaluate the type of the loop to `!`, so this special case is kinda moot. This only affects loops that have `break`s with values of type `!`. Thus, this seems like a change that may affect more code than just `.await`, but it likely does not in meaningful ways; if it does, it's certainly correct to apply. Fixes rust-lang#128434
rust-timer
added a commit
to rust-lang-ci/rust
that referenced
this issue
Aug 1, 2024
Rollup merge of rust-lang#128443 - compiler-errors:async-unreachable, r=fmease Properly mark loop as diverging if it has no breaks Due to specifics about the desugaring of the `.await` operator, HIR typeck doesn't recognize that `.await`ing an `impl Future<Output = !>` will diverge in the same way as calling a `fn() -> !`. This is because the await operator desugars to approximately: ```rust loop { match future.poll(...) { Poll::Ready(x) => break x, Poll::Pending => {} } } ``` We know that the value of `x` is `!`, however since `break` is a coercion site, we coerce `!` to some `?0` (the type of the loop expression). Then since the type of the `loop {...}` expression is `?0`, we will not detect the loop as diverging like we do with other expressions that evaluate to `!`: https://github.com/rust-lang/rust/blob/0b5eb7ba7bd796fb39c8bb6acd9ef6c140f28b65/compiler/rustc_hir_typeck/src/expr.rs#L240-L243 We can technically fix this in two ways: 1. Make coercion of loop exprs more eagerly result in a type of `!` when the only break expressions have type `!`. 2. Make loops understand that all of that if they have only diverging break values, then the loop diverges as well. (1.) likely has negative effects on inference, and seems like a weird special case to drill into coercion. However, it turns out that (2.) is very easy to implement, we already record whether a loop has any break expressions, and when we do so, we actually skip over any break expressions with diverging values!: https://github.com/rust-lang/rust/blob/0b5eb7ba7bd796fb39c8bb6acd9ef6c140f28b65/compiler/rustc_hir_typeck/src/expr.rs#L713-L716 Thus, we can consider the loop as diverging if we see that it has no breaks, which is the change implemented in this PR. This is not usually a problem in regular code for two reasons: 1. In regular code, we already mark `break diverging()` as unreachable if `diverging()` is unreachable. We don't do this for `.await`, since we suppress unreachable errors within `.await` (rust-lang#64930). Un-suppressing this code will result in spurious unreachable expression errors pointing to internal await machinery. 3. In loops that truly have no breaks (e.g. `loop {}`), we already evaluate the type of the loop to `!`, so this special case is kinda moot. This only affects loops that have `break`s with values of type `!`. Thus, this seems like a change that may affect more code than just `.await`, but it likely does not in meaningful ways; if it does, it's certainly correct to apply. Fixes rust-lang#128434
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
A-diagnostics
Area: Messages for errors, warnings, and lints
T-compiler
Relevant to the compiler team, which will review and decide on the PR/issue.
WG-async
Working group: Async & await
Code
Current output
Desired output
Rationale and extra context
No response
Other cases
No response
Rust Version
Anything else?
Same behaviour with the current nightly version:
The text was updated successfully, but these errors were encountered: