-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
never_patterns: Count !
bindings as diverging
#120104
Conversation
This comment has been minimized.
This comment has been minimized.
02e95c9
to
0fb3c7f
Compare
083eedc
to
8f76b9c
Compare
@@ -220,9 +220,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |||
self.warn_if_unreachable(expr.hir_id, expr.span, "expression"); | |||
} | |||
|
|||
// Hide the outer diverging and has_errors flags. | |||
// Whether a past expression diverges doesn't affect typechecking of this expression, so we |
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.
Ok, so I understand what this is doing, but I'm not certain if I understand why it's doing this. Is this to make some test pass?
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.
The old_diverges
bit you mean? That's because if an expression diverges then it typechecks as !
. So before we check a new expression we hide the previous state of diverges
. Else in the following 1
would be given type !
.
panic!();
let x = 1;
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.
No, why you added this is_whole_body
thing.
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.
Ah. Well the presence of !
in the arguments should affect the type of the function body, but not the type of any other expression in the function. So I only look at function_diverges_because_of_empty_arguments
if expr
is the function body
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.
The obvious thing to do would have been to set fcx.diverges
directly while checking the function arguments, but that resulted in:
fn never_arg(!: Void) -> u32 {}
^^ unreachable code
as well as a type error because the mechanism I explained above ensures that the type of the {}
was not affected by previous diverges
so the body is typechecked as ()
x)
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.
I guess I could use diverges
directly instead of adding function_diverges_because_of_empty_arguments
🤔 . But I still need is_whole_body
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.
I understand why this is implemented the way it is, though I'm still chewing on whether there's a better approach here. My main concern is the non-locality -- it relies on the fact that when type checking the top expression of the body, we'll always flow through check_expr_with_expectation_and_args
first. While I believe typeck will remain in that way, it seems somewhat easy for a refactoring of control flow to make this no longer true always.
Ideally, we'd treat the initial check_expr call for the top expr of a body in a privileged way, and do this logic there, but currently all of that is tangled into the coercion code that we use to check the body as if it were an implicit return value. Sigh.
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.
As an aside, could you please double check that this still behaves the right way for async fn
?
async fn(!: Void) { body... }
implicitly desugars to:
fn(arg1: Void) -> ... {
async {
let ! = arg1;
body...
}
}
so it should behave correctly afaict, but I think we should have tests for 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.
Yeah, I'm not a fan of the non-locality and the mutability of my implementation but I felt way out of my depth to refactor anything.
Good catch on the async fn, it in fact does not work. I'm surprised because I looked at all the call sites of check_pat_top
and they all do something with never patterns except expression-let
s
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.
Weird, it does desugar to what you said, but doesn't seem to detect the divergence
8f76b9c
to
8ba025e
Compare
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.
r=me after fixing up the async test commit
8ba025e
to
3ff1024
Compare
@bors r+ |
Ty! |
…mpiler-errors never_patterns: Count `!` bindings as diverging A binding that is a never pattern is not reachable, hence counts as diverging code. This allows in particular `fn foo(!: Void) -> SomeType {}` to typecheck. r? `@compiler-errors`
…iaskrgr Rollup of 9 pull requests Successful merges: - rust-lang#119664 (Fix tty detection for msys2's `/dev/ptmx`) - rust-lang#120104 (never_patterns: Count `!` bindings as diverging) - rust-lang#120109 (Move cmath into `sys`) - rust-lang#120143 (Consolidate logic around resolving built-in coroutine trait impls) - rust-lang#120159 (Track `verbose` and `verbose_internals`) - rust-lang#120188 (compiler: update freebsd and netbsd base specs.) - rust-lang#120216 (Fix a `trimmed_def_paths` assertion failure.) - rust-lang#120220 (Document `Token{Stream,Tree}::Display` more thoroughly.) - rust-lang#120233 (Revert stabilization of trait_upcasting feature) r? `@ghost` `@rustbot` modify labels: rollup
…iaskrgr Rollup of 8 pull requests Successful merges: - rust-lang#119664 (Fix tty detection for msys2's `/dev/ptmx`) - rust-lang#120104 (never_patterns: Count `!` bindings as diverging) - rust-lang#120109 (Move cmath into `sys`) - rust-lang#120143 (Consolidate logic around resolving built-in coroutine trait impls) - rust-lang#120159 (Track `verbose` and `verbose_internals`) - rust-lang#120216 (Fix a `trimmed_def_paths` assertion failure.) - rust-lang#120220 (Document `Token{Stream,Tree}::Display` more thoroughly.) - rust-lang#120233 (Revert stabilization of trait_upcasting feature) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of rust-lang#120104 - Nadrieril:never-pat-diverges, r=compiler-errors never_patterns: Count `!` bindings as diverging A binding that is a never pattern is not reachable, hence counts as diverging code. This allows in particular `fn foo(!: Void) -> SomeType {}` to typecheck. r? ``@compiler-errors``
…iaskrgr Rollup of 8 pull requests Successful merges: - rust-lang#119664 (Fix tty detection for msys2's `/dev/ptmx`) - rust-lang#120104 (never_patterns: Count `!` bindings as diverging) - rust-lang#120109 (Move cmath into `sys`) - rust-lang#120143 (Consolidate logic around resolving built-in coroutine trait impls) - rust-lang#120159 (Track `verbose` and `verbose_internals`) - rust-lang#120216 (Fix a `trimmed_def_paths` assertion failure.) - rust-lang#120220 (Document `Token{Stream,Tree}::Display` more thoroughly.) - rust-lang#120233 (Revert stabilization of trait_upcasting feature) r? `@ghost` `@rustbot` modify labels: rollup
A binding that is a never pattern is not reachable, hence counts as diverging code. This allows in particular
fn foo(!: Void) -> SomeType {}
to typecheck.r? @compiler-errors