-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
- Loading branch information
Showing
10 changed files
with
927 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 => {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 => {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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`. |