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 https://github.com/rust-lang/rfcs/issues/1550 for https://github.com/rust-lang/rust/issues/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.
This commit is contained in:
commit
a79cffb8b8
10 changed files with 927 additions and 84 deletions
173
src/test/ui/exhaustive_integer_patterns.rs
Normal file
173
src/test/ui/exhaustive_integer_patterns.rs
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(exhaustive_integer_patterns)]
|
||||
#![feature(exclusive_range_pattern)]
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
use std::{char, usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128};
|
||||
|
||||
fn main() {
|
||||
let x: u8 = 0;
|
||||
|
||||
// A single range covering the entire domain.
|
||||
match x {
|
||||
0 ..= 255 => {} // ok
|
||||
}
|
||||
|
||||
// A combination of ranges and values.
|
||||
// These are currently allowed to be overlapping.
|
||||
match x {
|
||||
0 ..= 32 => {}
|
||||
33 => {}
|
||||
34 .. 128 => {}
|
||||
100 ..= 200 => {}
|
||||
200 => {} //~ ERROR unreachable pattern
|
||||
201 ..= 255 => {}
|
||||
}
|
||||
|
||||
// An incomplete set of values.
|
||||
match x { //~ ERROR non-exhaustive patterns
|
||||
0 .. 128 => {}
|
||||
}
|
||||
|
||||
// A more incomplete set of values.
|
||||
match x { //~ ERROR non-exhaustive patterns
|
||||
0 ..= 10 => {}
|
||||
20 ..= 30 => {}
|
||||
35 => {}
|
||||
70 .. 255 => {}
|
||||
}
|
||||
|
||||
let x: i8 = 0;
|
||||
match x { //~ ERROR non-exhaustive patterns
|
||||
-7 => {}
|
||||
-5..=120 => {}
|
||||
-2..=20 => {} //~ ERROR unreachable pattern
|
||||
125 => {}
|
||||
}
|
||||
|
||||
// Let's test other types too!
|
||||
let c: char = '\u{0}';
|
||||
match c {
|
||||
'\u{0}' ..= char::MAX => {} // ok
|
||||
}
|
||||
|
||||
// We can actually get away with just covering the
|
||||
// following two ranges, which correspond to all
|
||||
// valid Unicode Scalar Values.
|
||||
match c {
|
||||
'\u{0000}' ..= '\u{D7FF}' => {}
|
||||
'\u{E000}' ..= '\u{10_FFFF}' => {}
|
||||
}
|
||||
|
||||
match 0usize {
|
||||
0 ..= usize::MAX => {} // ok
|
||||
}
|
||||
|
||||
match 0u16 {
|
||||
0 ..= u16::MAX => {} // ok
|
||||
}
|
||||
|
||||
match 0u32 {
|
||||
0 ..= u32::MAX => {} // ok
|
||||
}
|
||||
|
||||
match 0u64 {
|
||||
0 ..= u64::MAX => {} // ok
|
||||
}
|
||||
|
||||
match 0u128 {
|
||||
0 ..= u128::MAX => {} // ok
|
||||
}
|
||||
|
||||
match 0isize {
|
||||
isize::MIN ..= isize::MAX => {} // ok
|
||||
}
|
||||
|
||||
match 0i8 {
|
||||
-128 ..= 127 => {} // ok
|
||||
}
|
||||
|
||||
match 0i8 { //~ ERROR non-exhaustive patterns
|
||||
-127 ..= 127 => {}
|
||||
}
|
||||
|
||||
match 0i16 {
|
||||
i16::MIN ..= i16::MAX => {} // ok
|
||||
}
|
||||
|
||||
match 0i16 { //~ ERROR non-exhaustive patterns
|
||||
i16::MIN ..= -1 => {}
|
||||
1 ..= i16::MAX => {}
|
||||
}
|
||||
|
||||
match 0i32 {
|
||||
i32::MIN ..= i32::MAX => {} // ok
|
||||
}
|
||||
|
||||
match 0i64 {
|
||||
i64::MIN ..= i64::MAX => {} // ok
|
||||
}
|
||||
|
||||
match 0i128 {
|
||||
i128::MIN ..= i128::MAX => {} // ok
|
||||
}
|
||||
|
||||
// Make sure that guards don't factor into the exhaustiveness checks.
|
||||
match 0u8 { //~ ERROR non-exhaustive patterns
|
||||
0 .. 128 => {}
|
||||
128 ..= 255 if true => {}
|
||||
}
|
||||
|
||||
match 0u8 {
|
||||
0 .. 128 => {}
|
||||
128 ..= 255 if false => {}
|
||||
128 ..= 255 => {} // ok, because previous arm was guarded
|
||||
}
|
||||
|
||||
// Now things start getting a bit more interesting. Testing products!
|
||||
match (0u8, Some(())) { //~ ERROR non-exhaustive patterns
|
||||
(1, _) => {}
|
||||
(_, None) => {}
|
||||
}
|
||||
|
||||
match (0u8, true) { //~ ERROR non-exhaustive patterns
|
||||
(0 ..= 125, false) => {}
|
||||
(128 ..= 255, false) => {}
|
||||
(0 ..= 255, true) => {}
|
||||
}
|
||||
|
||||
match (0u8, true) { // ok
|
||||
(0 ..= 125, false) => {}
|
||||
(128 ..= 255, false) => {}
|
||||
(0 ..= 255, true) => {}
|
||||
(125 .. 128, false) => {}
|
||||
}
|
||||
|
||||
match 0u8 { // ok
|
||||
0 .. 2 => {}
|
||||
1 ..= 2 => {}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
const LIM: u128 = u128::MAX - 1;
|
||||
match 0u128 { //~ ERROR non-exhaustive patterns
|
||||
0 ..= LIM => {}
|
||||
}
|
||||
|
||||
match 0u128 { //~ ERROR non-exhaustive patterns
|
||||
0 ..= 4 => {}
|
||||
}
|
||||
|
||||
match 0u128 { //~ ERROR non-exhaustive patterns
|
||||
4 ..= u128::MAX => {}
|
||||
}
|
||||
}
|
||||
87
src/test/ui/exhaustive_integer_patterns.stderr
Normal file
87
src/test/ui/exhaustive_integer_patterns.stderr
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
error: unreachable pattern
|
||||
--> $DIR/exhaustive_integer_patterns.rs:32:9
|
||||
|
|
||||
LL | 200 => {} //~ ERROR unreachable pattern
|
||||
| ^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/exhaustive_integer_patterns.rs:13:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `128u8..=255u8` not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:37:11
|
||||
|
|
||||
LL | match x { //~ ERROR non-exhaustive patterns
|
||||
| ^ pattern `128u8..=255u8` not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `11u8..=19u8`, `31u8..=34u8`, `36u8..=69u8` and 1 more not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:42:11
|
||||
|
|
||||
LL | match x { //~ ERROR non-exhaustive patterns
|
||||
| ^ patterns `11u8..=19u8`, `31u8..=34u8`, `36u8..=69u8` and 1 more not covered
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustive_integer_patterns.rs:53:9
|
||||
|
|
||||
LL | -2..=20 => {} //~ ERROR unreachable pattern
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `-128i8..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:50:11
|
||||
|
|
||||
LL | match x { //~ ERROR non-exhaustive patterns
|
||||
| ^ patterns `-128i8..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `-128i8` not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:99:11
|
||||
|
|
||||
LL | match 0i8 { //~ ERROR non-exhaustive patterns
|
||||
| ^^^ pattern `-128i8` not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `0i16` not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:107:11
|
||||
|
|
||||
LL | match 0i16 { //~ ERROR non-exhaustive patterns
|
||||
| ^^^^ pattern `0i16` not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `128u8..=255u8` not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:125:11
|
||||
|
|
||||
LL | match 0u8 { //~ ERROR non-exhaustive patterns
|
||||
| ^^^ pattern `128u8..=255u8` not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `(0u8, Some(_))` and `(2u8..=255u8, Some(_))` not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:137:11
|
||||
|
|
||||
LL | match (0u8, Some(())) { //~ ERROR non-exhaustive patterns
|
||||
| ^^^^^^^^^^^^^^^ patterns `(0u8, Some(_))` and `(2u8..=255u8, Some(_))` not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `(126u8..=127u8, false)` not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:142:11
|
||||
|
|
||||
LL | match (0u8, true) { //~ ERROR non-exhaustive patterns
|
||||
| ^^^^^^^^^^^ pattern `(126u8..=127u8, false)` not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211455u128` not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:162:11
|
||||
|
|
||||
LL | match 0u128 { //~ ERROR non-exhaustive patterns
|
||||
| ^^^^^ pattern `340282366920938463463374607431768211455u128` not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `5u128..=340282366920938463463374607431768211455u128` not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:166:11
|
||||
|
|
||||
LL | match 0u128 { //~ ERROR non-exhaustive patterns
|
||||
| ^^^^^ pattern `5u128..=340282366920938463463374607431768211455u128` not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `0u128..=3u128` not covered
|
||||
--> $DIR/exhaustive_integer_patterns.rs:170:11
|
||||
|
|
||||
LL | match 0u128 { //~ ERROR non-exhaustive patterns
|
||||
| ^^^^^ pattern `0u128..=3u128` not covered
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0004`.
|
||||
16
src/test/ui/feature-gate-exhaustive_integer_patterns.rs
Normal file
16
src/test/ui/feature-gate-exhaustive_integer_patterns.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
let x: u8 = 0;
|
||||
match x { //~ ERROR non-exhaustive patterns: `_` not covered
|
||||
0 ..= 255 => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/feature-gate-exhaustive_integer_patterns.rs:13:11
|
||||
|
|
||||
LL | match x { //~ ERROR non-exhaustive patterns: `_` not covered
|
||||
| ^ pattern `_` not covered
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0004`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue