Skip to content
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

Precise range exhaustiveness check for match on integer patterns #1550

Closed
pnkfelix opened this Issue Mar 21, 2016 · 13 comments

Comments

Projects
None yet
@pnkfelix
Copy link
Member

pnkfelix commented Mar 21, 2016

In theory the compiler should be able to detect that the following range is exhaustive and not error about non-exaustive match:

fn wont_compile(x : u8) { 
    match (x) {
        0x00 ... 0xff => { }
    }
}

Proposed (as a side-portion) in #880

Discussed in rust-lang/rust#12483 and rust-lang/rust#32381

@oli-obk

This comment has been minimized.

Copy link
Contributor

oli-obk commented Mar 22, 2016

The following will then error due to _ being unreachable, but it currently is allowed. So we'd need some way to prevent "new" unreachable patterns from being a hard error.

match x {
    0x00...0xFF => {},
    _ => {},
}
@jonas-schievink

This comment has been minimized.

Copy link
Member

jonas-schievink commented Mar 22, 2016

@oli-obk We could just warn in that case (and make it a lint so people can #[deny] or #[allow] it, depending on what they want)

@nrc nrc added the T-lang label Aug 18, 2016

@igor-krawczuk

This comment has been minimized.

Copy link

igor-krawczuk commented Jan 5, 2017

Are there any new discussion/plans on this? Adding a warning which can be turned off for legacy code seems like the most elegant solution to me. If that aligns with the consensus, I'd try and take a shot at this during my spring vacation and send a pull request

@burdges

This comment has been minimized.

Copy link

burdges commented Jan 5, 2017

It's another issue, and likely unsolvable, but this also fails the range exhaustiveness check:

match x & 0x03 {
    0 .. 3 => ..
}
@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Jan 6, 2017

@igor-krawczuk Unreachable patterns have already been downgraded from errors to warnings in rust-lang/rust#38069 I believe, so that sounds reasonable to me.

@leonardo-m

This comment has been minimized.

Copy link

leonardo-m commented Feb 18, 2017

Perhaps it's time to remove the "postponed" tag.

"match x & 0x03 {}" can be solved with a small amount of value range analysis, that will benefit other parts of Rust.

@euclio

This comment has been minimized.

Copy link

euclio commented Jul 6, 2017

I'd also like to see discussion start on this again. I ran into this today and was very surprised to see that Rust can't determine that all ranges of a given integer type were covered. I had to add a _ => unreachable!() arm instead.

@iamrecursion

This comment has been minimized.

Copy link

iamrecursion commented Jul 7, 2017

Determining the completeness of a set of guards/pattern matches over a given domain is a fairly non-trivial problem. I ran into it writing my thesis and it requires applications of the Simplex Algorithm to solve what is effectively a linear programming problem.

It's not impossible to solve, but the complexity of doing so needs to be weighed against the possible ergonomic benefits.

@leonardo-m

This comment has been minimized.

Copy link

leonardo-m commented Jul 7, 2017

Step 1: perform this conservatively, on integral ranges only and only if there are no guards. This is a common case in low-level code. Benefits: avoided a class of bugs, etc.

@euclio

This comment has been minimized.

Copy link

euclio commented Jul 7, 2017

Yes, this problem in general is very much non-trivial, but the case outlined by @leonardo-m covers my use case and is certainly doable.

@scottmcm

This comment has been minimized.

Copy link
Member

scottmcm commented Oct 28, 2017

This could be particularly elegant for char:

match c {
    '\u{0000}'..='\u{D7FF}' => ...
    '\u{E000}'..='\u{10_FFFF}' => ...
    // No wildcard needed; all legal USVs are covered
}
@varkor

This comment has been minimized.

Copy link
Member

varkor commented May 19, 2018

I have an implementation of this (specifically: interval exhaustiveness checking over integer types). If we need to write up an RFC before integrating it, I'll try to do so in a couple of weeks or so (or if anyone'd like to accelerate the process and write one sooner, that'd be great too)!

Edit: Actually, I'm going to try merged it under a feature flag immediately, as it seems like a straightforward extension to the existing exhaustiveness checks, but it may require an RFC to stabilise.

I've created a tracking issue here: rust-lang/rust#50907 and the pull request is at: rust-lang/rust#50912.

bors added a commit to rust-lang/rust that referenced this issue Aug 22, 2018

Auto merge of #50912 - varkor:exhaustive-integer-matching, r=arielb1
Exhaustive integer matching

This adds a new feature flag `exhaustive_integer_patterns` that enables exhaustive matching of integer types by their values. For example, the following is now accepted:
```rust
#![feature(exhaustive_integer_patterns)]
#![feature(exclusive_range_pattern)]

fn matcher(x: u8) {
  match x { // ok
    0 .. 32 => { /* foo */ }
    32 => { /* bar */ }
    33 ..= 255 => { /* baz */ }
  }
}
```
This matching is permitted on all integer (signed/unsigned and char) types. Sensible error messages are also provided. For example:
```rust
fn matcher(x: u8) {
  match x { //~ ERROR
    0 .. 32 => { /* foo */ }
  }
}
```
results in:
```
error[E0004]: non-exhaustive patterns: `32u8...255u8` not covered
 --> matches.rs:3:9
  |
6 |   match x {
  |         ^ pattern `32u8...255u8` not covered
```

This implements rust-lang/rfcs#1550 for #50907. While there hasn't been a full RFC for this feature, it was suggested that this might be a feature that obviously complements the existing exhaustiveness checks (e.g. for `bool`) and so a feature gate would be sufficient for now.
@varkor

This comment has been minimized.

Copy link
Member

varkor commented Aug 22, 2018

This has been implemented in rust-lang/rust#50912 as #![feature(exhaustive_integer_patterns)] (tracking issue). We can probably close this issue now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.