Skip to content

Consider arm to diverge if guard diverges #134735

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

Merged
merged 1 commit into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions compiler/rustc_hir_typeck/src/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut prior_non_diverging_arms = vec![]; // Used only for diagnostics.
let mut prior_arm = None;
for arm in arms {
self.diverges.set(Diverges::Maybe);

if let Some(e) = &arm.guard {
self.diverges.set(Diverges::Maybe);
self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {});

// FIXME: If this is the first arm and the pattern is irrefutable,
Copy link
Member Author

Choose a reason for hiding this comment

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

This would be the place to insert a fix for #134734 (it'll need some extra divergence state tracking variable or something), though it also requires some rudimentary heuristic to compute if a pattern is irrefutable in HIR, since that's currently the responsibility of THIR pattern analysis.

// e.g. `_` or `x`, and the guard diverges, then the whole match
// may also be considered to diverge. We should warn on all subsequent
// arms, too, just like we do for diverging scrutinees above.
}

self.diverges.set(Diverges::Maybe);
// N.B. We don't reset diverges here b/c we want to warn in the arm
// if the guard diverges, like: `x if { loop {} } => f()`, and we
// also want to consider the arm to diverge itself.

let arm_ty = self.check_expr_with_expectation(arm.body, expected);
all_arms_diverge &= self.diverges.get();
Expand Down
8 changes: 6 additions & 2 deletions tests/ui/reachable/expr_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ fn d() {
}

fn e() {
// Here the compiler fails to figure out that the `println` is dead.
Copy link
Member Author

Choose a reason for hiding this comment

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

Funny that this wasn't a FIXME, but it's obviously a bug.

match () { () if return => (), () => return }
match () {
() if return => (),
//~^ ERROR unreachable expression
() => return,
}
println!("I am dead");
//~^ ERROR unreachable statement
}

fn f() {
Expand Down
24 changes: 23 additions & 1 deletion tests/ui/reachable/expr_match.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,27 @@ LL | println!("I am dead");
|
= note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors
error: unreachable expression
--> $DIR/expr_match.rs:25:25
|
LL | () if return => (),
| ------ ^^ unreachable expression
| |
| any code following this expression is unreachable

error: unreachable statement
--> $DIR/expr_match.rs:29:5
|
LL | / match () {
LL | | () if return => (),
LL | |
LL | | () => return,
LL | | }
| |_____- any code following this `match` expression is unreachable, as all arms diverge
LL | println!("I am dead");
| ^^^^^^^^^^^^^^^^^^^^^ unreachable statement
|
= note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 4 previous errors

Loading