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
Closed

Precise range exhaustiveness check for match on integer patterns #1550

pnkfelix opened this issue Mar 21, 2016 · 13 comments
Labels
postponed RFCs that have been postponed and may be revisited at a later time. T-lang Relevant to the language team, which will review and decide on the RFC.

Comments

@pnkfelix
Copy link
Member

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

@pnkfelix pnkfelix added the postponed RFCs that have been postponed and may be revisited at a later time. label Mar 21, 2016
@oli-obk
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
Copy link
Contributor

@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 Relevant to the language team, which will review and decide on the RFC. label Aug 18, 2016
@igor-krawczuk
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
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
Copy link
Contributor

@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
Copy link

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
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
Copy link

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
Copy link

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
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
Copy link
Member

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
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
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
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
Labels
postponed RFCs that have been postponed and may be revisited at a later time. T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

No branches or pull requests