Rust: Exhaustive integer patterns tracking issue

Created on 20 May 2018  路  17Comments  路  Source: rust-lang/rust

Tentative tracking issue for the exhaustive_integer_patterns feature, in which integer types may be exhaustively matched over their values. Original RFC thread: https://github.com/rust-lang/rfcs/issues/1550.

  • [x] Implementation (https://github.com/rust-lang/rust/pull/50912)
  • [x] Stabilisation (https://github.com/rust-lang/rust/pull/56557)
#![feature(exhaustive_integer_patterns)]
#![feature(exclusive_range_pattern)]

fn matcher(x: u8) {
  match x { // ok -- every value has been accounted for
    0 .. 32 => { /* foo */ }
    32 => { /* bar */ }
    33 ..= 255 => { /* baz */ }
  }
}
B-unstable C-tracking-issue F-exclusive_range_pattern T-lang

Most helpful comment

This will be usable on the next Nightly under #![feature(exhaustive_integer_patterns)] now that https://github.com/rust-lang/rust/pull/50912's merged!

All 17 comments

Some common use cases, you don't need to support them all at once, but eventually Rust should handle them all:

#![feature(exclusive_range_pattern)]
#![feature(euclidean_division)]

fn foo1(x: u8) {
    match x {
        0 .. 120 => {},
        120 ..= 255 => {},
    }
}

fn foo2(x: u32) {
    match x % 3 {
        0 => {},
        1 => {},
        2 => {},
    }
}

fn foo3(x: i32) {
    match x.mod_euc(3) - 1 {
        -1 => {},
        0 => {},
        1 => {},
    }
}

fn main() {}

@leonardo-m: I'm focusing on exhaustive matching over the entire type right now. Eventually, it'd be nice to be able to handle cases like modulo too, but that involves some significant changes if it's to work well and I'm not sure how plausible it really is (without a huge memory footprint).

To range the result of arithmetic I think we have to implement it as something like type system contracts, which needs a full RFC.

The example with mod_euc could require some kind of contracts, but my second example with "x % 3" is within the compile-time capabilities of the DMD D language compiler (and it's faster than Rustc and it doesn't require lot of memory), some examples of what D Value Range Analysis does:

// temp.d(2,33): Error: cannot implicitly convert expression (x) of type const(uint) to ubyte
ubyte foo01(in uint x) { return x; }

ubyte foo02(in uint x) { return x % 300; } // Cannot implicitly convert
ubyte foo03(in uint x) { return x % 200; } // OK
ubyte foo04(in int x) { return x % 200; } // Cannot implicitly convert
ubyte foo05(in int x) { return x % 128 + 128; } // OK
byte foo06(in int x) { return x % 127; } // OK
byte foo07(in ubyte x) { return x - 128; } // OK
int foo08(in ubyte x) { return x - 128; } // OK
ubyte foo09(in uint x) { return x & 0b_1111; } // OK
ubyte foo10(in uint x) { return x / 10_000_000; } // Cannot implicitly convert
ubyte foo11(in uint x) { return x / 100_000_000; } // OK
ubyte foo12(in ubyte x, in ubyte y) { return x + y; } // Cannot implicitly convert
uint foo13(in ubyte x, in ubyte y) { return x + y; } // OK

void main() {}

I think Rust match{} could become equally smart.

I also think the same Value Range Analysis should allow code like this in Rust (note this uses into() instead of TryInto()):
fn foo07(x: u8) -> i8 { (x - 128).into() }

I'd say that range analysis should be solely an optimization, as it's very inflexible.

And on the optimization side, LLVM should be already able to eliminate the dead path.

And on the optimization side, LLVM should be already able to eliminate the dead path.

That misses the main point of using into() instead of TryInto(): the first one is statically proved to be correct by the compiler, unlike the second. The optimization is not the important thing here.

@leonardo-m: I think supporting such a feature would be interesting, but concur it would need a separate RFC with more details.

I concur it's for other pull requests and another RFC.

This will be usable on the next Nightly under #![feature(exhaustive_integer_patterns)] now that https://github.com/rust-lang/rust/pull/50912's merged!

N.B: Before we stabilize this, I would like to see an RFC accepted that details and motivates (shouldn't be too hard) the changes.

In https://github.com/rust-lang/rust/pull/50912#issuecomment-393991509 it was proposed that this extension was filling in a gap in the existing exhaustiveness checks and underwent a T-lang FCP, so an RFC probably isn't necessary here.

@varkor So, I had not read #50912 (comment). However, I do not view exhaustive integer matching as a bugfix or a trivial change. The feature was seen an addition to the language (as opposed to bug-fixes) in previous RFCs and were postponed then since they were not a priority leading up to 1.0. @nikomatsakis said as much in their move to FCP in the linked comment.

Therefore, I do not think that the proper process was followed and I will insist that an RFC is written prior to stabilization because I want to avoid the precedent of allowing larger and larger language changes to be accepted with no RFC.

I want to emphasize that this is not about this particular feature, which I think is an excellent idea and I have no doubt we would merge the RFC; but I do want to see the bits and pieces of text and reasoning that the RFC document provides (and I know that you're capable of writing excellent RFCs). Think of it as a stabilization report. Once we have that RFC merged, we can skip the extra FCP after it.

@varkor

This has been in the nightly compiler for ~80 days which approximates 12 weeks;
I think it would be appropriate to stabilize this soon.
If you could write the RFC aforementioned we can begin that process.
Also please attach an Appendix to the RFC pointing out relevant test files and such things.

@Centril should this also be tagged with relnotes when stabilized?

@jonhoo we tag the PR that stabilizes it with relnotes.

Stabilization proposal filed in https://github.com/rust-lang/rfcs/pull/2591.

This has been stabilised in https://github.com/rust-lang/rust/pull/56557.

Was this page helpful?
0 / 5 - 0 ratings