提交 a79cffb8 编写于 作者: B bors

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.
......@@ -2228,7 +2228,7 @@ pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Resul
}
}
pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result {
pub fn print_miri_value<'tcx, W: Write>(value: Value, ty: Ty<'tcx>, f: &mut W) -> fmt::Result {
use ty::TypeVariants::*;
// print some primitives
if let Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { bits, .. })) = value {
......
......@@ -272,7 +272,7 @@ fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) {
self.tables);
let pattern = patcx.lower_pattern(pat);
let pattern_ty = pattern.ty;
let pats : Matrix = vec![vec![
let pats: Matrix = vec![vec![
expand_pattern(cx, pattern)
]].into_iter().collect();
......@@ -391,7 +391,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
printed_if_let_err = true;
}
}
},
}
hir::MatchSource::WhileLetDesugar => {
// check which arm we're on.
......
......@@ -233,7 +233,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
PatternKind::Range { lo, hi, end } => {
fmt_const_val(f, lo)?;
match end {
RangeEnd::Included => write!(f, "...")?,
RangeEnd::Included => write!(f, "..=")?,
RangeEnd::Excluded => write!(f, "..")?,
}
fmt_const_val(f, hi)
......@@ -368,9 +368,14 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
"lower range bound must be less than upper",
);
PatternKind::Wild
},
(RangeEnd::Included, None) |
(RangeEnd::Included, Some(Ordering::Greater)) => {
}
(RangeEnd::Included, Some(Ordering::Equal)) => {
PatternKind::Constant { value: lo }
}
(RangeEnd::Included, Some(Ordering::Less)) => {
PatternKind::Range { lo, hi, end }
}
(RangeEnd::Included, _) => {
let mut err = struct_span_err!(
self.tcx.sess,
lo_expr.span,
......@@ -390,8 +395,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
}
err.emit();
PatternKind::Wild
},
(RangeEnd::Included, Some(_)) => PatternKind::Range { lo, hi, end },
}
}
}
_ => PatternKind::Wild
......
......@@ -36,6 +36,7 @@
#![feature(unicode_internals)]
#![feature(step_trait)]
#![feature(slice_concat_ext)]
#![feature(if_while_or_patterns)]
#![recursion_limit="256"]
......
......@@ -471,6 +471,9 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
// 'a: { break 'a; }
(active, label_break_value, "1.28.0", Some(48594), None),
// Integer match exhaustiveness checking
(active, exhaustive_integer_patterns, "1.30.0", Some(50907), None),
// #[panic_implementation]
(active, panic_implementation, "1.28.0", Some(44489), None),
......
// 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 => {}
}
}
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`.
// 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 => {}
}
}
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`.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册