-
Notifications
You must be signed in to change notification settings - Fork 13.9k
never_patterns: Count ! bindings as diverging
#120104
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
Conversation
This comment has been minimized.
This comment has been minimized.
02e95c9 to
0fb3c7f
Compare
083eedc to
8f76b9c
Compare
| } | ||
|
|
||
| // 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 codeas 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-lets
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