Skip to content

Incorrect non-exaustive match statement (where the user may think that all case are covered) #92197

Closed
@robinmoussu

Description

@robinmoussu

Given the following code:

match (order(lhs), order(rhs)) {
    (lhs_, rhs_) if lhs_  < rhs_ => std::cmp::Ordering::Less,
    (lhs_, rhs_) if lhs_  > rhs_ => std::cmp::Ordering::Greater,
    (lhs_, rhs_) if lhs_ == rhs_ => lhs.cmp(rhs),
}

The current output is:

  2 src/main.rs|26 col 15 error   4| non-exhaustive patterns: `(_, _)` not covered                                                                                                                                                                            
  3 ||    |
  4 || 26 |         match (order(lhs), order(rhs)) {
  5 ||    |               ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
  6 ||    |
  7 ||    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
  8 ||    = note: the matched value is of type `(i32, i32)`

For more information about this error, try `rustc --explain E0004`.

At first, I thought it was a compiler bug (an understandable one since exhaustiveness checking is hard), but then I realized that an buggy (or adversarial) implementation of Ord could lead to lhs being neither less than, greater than nor equal to rhs. So the compiler is right, just confusing.

Ideally the output should look like (line 8 has been edited):

  2 src/main.rs|26 col 15 error   4| non-exhaustive patterns: `(_, _)` not covered                                                                                                                                                                            
  3 ||    |
  4 || 26 |         match (order(lhs), order(rhs)) {
  5 ||    |               ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
  6 ||    |
  7 ||    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
  8 ||    = help: a bad implementation of comparison operators of the matched type could lead to all cases not being handled
  9 ||    = 
 10 ||    = note: the matched value is of type `(i32, i32)`

For more information about this error, try `rustc --explain E0004`.

And the error E0004 could contain or more detailed explanation of why such code isn’t covering all cases.

It addition, but I’m less sure of this, a suggestion to be made to either change the last arm to a wildcard (_ => lhs.cmp(rhs) or to add an extra arm _ => unreachable!() with an explanation of why the user should choose one or the other.

Of course in this specific case (i32, i32) we could trust the implementation, but I’m not sure either that it would be a good idea to special-case them (since it would be even more confusing for a user type that is not special cased).

Metadata

Metadata

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsA-exhaustiveness-checkingRelating to exhaustiveness / usefulness checking of patternsD-papercutDiagnostics: An error or lint that needs small tweaks.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions