From 0a9aae4977f23d7289ad99aefe9517095d237695 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 10 Nov 2018 12:02:26 +0000 Subject: [PATCH 1/6] Initial draft of exhaustive integer pattern matching --- ...000-exhaustive-integer-pattern-matching.md | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 text/0000-exhaustive-integer-pattern-matching.md diff --git a/text/0000-exhaustive-integer-pattern-matching.md b/text/0000-exhaustive-integer-pattern-matching.md new file mode 100644 index 00000000000..90587ff1a04 --- /dev/null +++ b/text/0000-exhaustive-integer-pattern-matching.md @@ -0,0 +1,89 @@ +- Feature Name: `exhaustive_integer_patterns` +- Start Date: 10/11/2018 +- RFC PR: +- Rust Issue: [#50907](https://github.com/rust-lang/rust/issues/50907) + +# Summary +[summary]: #summary + +Extend Rust's pattern matching exhaustiveness checks to cover the integer types: `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, `isize` and `char`. + +```rust +fn matcher_full(x: u8) { + match x { // ok + 0 .. 32 => { /* ... */ } + 32 => { /* ... */ } + 33 ..= 255 => { /* ... */ } + } +} + +fn matcher_incomplete(x: u8) { + match x { //~ ERROR: non-exhaustive patterns: `32u8...255u8` not covered + 0 .. 32 => { /* ... */ } + } +} +``` + +# Motivation +[motivation]: #motivation + +This is viewed essentially as a bug fix: other than the implementational challenges, there is no reason not to perform correct exhaustiveness checking on integer patterns, especially as range patterns are permitted, making it very straightforward to provide patterns covering every single integer. + +This change will mean that Rust correctly performs exhaustiveness checking on all the types that currently compose its type system. + +This feature has already [been implemented](https://github.com/rust-lang/rust/pull/50912) behind the feature flag `exhaustive_integer_patterns`, so this RFC is viewed as a motion to stabilise the feature. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +Exhaustive pattern matching works for integer types, just like any other type. In addition, missing ranges of integers will be reported as errors. + +```rust +fn matcher_full(x: u8) { + match x { // ok + 0 .. 32 => { /* ... */ } + 32 => { /* ... */ } + 33 ..= 255 => { /* ... */ } + } +} + +fn matcher_incomplete(x: u8) { + match x { //~ ERROR: non-exhaustive patterns: `32u8...255u8` not covered + 0 .. 32 => { /* ... */ } + } +} +``` + +More examples may be found in [the file of test cases](https://github.com/rust-lang/rust/pull/50912/files#diff-8809036e5fb5a9a0fcc283431046ef51). + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +The implementation of this features uses interval arithmetic and an extension of the pattern matching exhaustiveness checks as described in [this paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). + +This feature has already [been implemented](https://github.com/rust-lang/rust/pull/50912), so the code there may be used for further reference. The source contains detailed comments about the implementation. + +# Drawbacks +[drawbacks]: #drawbacks + +There is no reason not to do this: it fixes a limitation of the existing pattern exhaustiveness checks. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +This is a straightforward extension of the existing exhaustiveness checks. This is the only sensible design for the feature. + +# Prior art +[prior-art]: #prior-art + +As far as the author is unaware, Rust is the first language to support exhaustive integer pattern matching. At the time of writing, Swift and OCaml, two languages for which this feature could also make sense, do not implement this extension. This is likely because the feature is not simple to implement and the usefulness of this feature appears in specific domains. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +This feature is already implemented and appears to meet expectations for such a feature, as there have been no issues brought up about the implementation or design. + +# Future possibilities +[future-possibilities]: #future-possibilities + +Having added exhaustive pattern matching for integers, all types in Rust for which exhaustive matching is sensible are matched exhaustively. We should aim to ensure this remains the case. However, at present, exhaustive pattern matching in Rust is viewed complete. From 7f79fc10441d80e574a1f866d50a0ce291925c87 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 10 Nov 2018 14:43:51 +0000 Subject: [PATCH 2/6] Add reference to guarded arms Also update examples to not rely on `exclusive_range_pattern`. --- text/0000-exhaustive-integer-pattern-matching.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/text/0000-exhaustive-integer-pattern-matching.md b/text/0000-exhaustive-integer-pattern-matching.md index 90587ff1a04..12a717221d5 100644 --- a/text/0000-exhaustive-integer-pattern-matching.md +++ b/text/0000-exhaustive-integer-pattern-matching.md @@ -11,15 +11,15 @@ Extend Rust's pattern matching exhaustiveness checks to cover the integer types: ```rust fn matcher_full(x: u8) { match x { // ok - 0 .. 32 => { /* ... */ } + 0 ..= 31 => { /* ... */ } 32 => { /* ... */ } 33 ..= 255 => { /* ... */ } } } fn matcher_incomplete(x: u8) { - match x { //~ ERROR: non-exhaustive patterns: `32u8...255u8` not covered - 0 .. 32 => { /* ... */ } + match x { //~ ERROR: non-exhaustive patterns: `32u8..=255u8` not covered + 0 ..= 31 => { /* ... */ } } } ``` @@ -41,21 +41,23 @@ Exhaustive pattern matching works for integer types, just like any other type. I ```rust fn matcher_full(x: u8) { match x { // ok - 0 .. 32 => { /* ... */ } + 0 ..= 31 => { /* ... */ } 32 => { /* ... */ } 33 ..= 255 => { /* ... */ } } } fn matcher_incomplete(x: u8) { - match x { //~ ERROR: non-exhaustive patterns: `32u8...255u8` not covered - 0 .. 32 => { /* ... */ } + match x { //~ ERROR: non-exhaustive patterns: `32u8..=255u8` not covered + 0 ..= 31 => { /* ... */ } } } ``` More examples may be found in [the file of test cases](https://github.com/rust-lang/rust/pull/50912/files#diff-8809036e5fb5a9a0fcc283431046ef51). +Note that guarded arms are ignored for the purpose of exhaustiveness checks, just like with any other type (i.e. arms with `if` conditions are always considered fallible and aren't considered to cover any possibilities). + # Reference-level explanation [reference-level-explanation]: #reference-level-explanation From 17a758c2c16dd20a924b0c26f66b54519d1a50f3 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 10 Nov 2018 14:51:28 +0000 Subject: [PATCH 3/6] Mention valid range for `char` (USV ranges) --- text/0000-exhaustive-integer-pattern-matching.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/text/0000-exhaustive-integer-pattern-matching.md b/text/0000-exhaustive-integer-pattern-matching.md index 12a717221d5..cec34b5479a 100644 --- a/text/0000-exhaustive-integer-pattern-matching.md +++ b/text/0000-exhaustive-integer-pattern-matching.md @@ -54,6 +54,8 @@ fn matcher_incomplete(x: u8) { } ``` +Specifically, for non-`char` integer types, the entire range of values from `{integer}::MIN` to `{integer}::MAX` are considered valid constructors. For `char`, the Unicode Scalar Value (USV) ranges (`\u{0000}..=\u{D7FF}` and `\u{E000}..=\u{10FFFF}`) are considered valid constructors. + More examples may be found in [the file of test cases](https://github.com/rust-lang/rust/pull/50912/files#diff-8809036e5fb5a9a0fcc283431046ef51). Note that guarded arms are ignored for the purpose of exhaustiveness checks, just like with any other type (i.e. arms with `if` conditions are always considered fallible and aren't considered to cover any possibilities). From fb701dc2de3b801019f35cb933eff1649fbda0dc Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 19 Nov 2018 10:19:26 +0000 Subject: [PATCH 4/6] Place `usize` and `isize` matching behind a feature flag --- text/0000-exhaustive-integer-pattern-matching.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/text/0000-exhaustive-integer-pattern-matching.md b/text/0000-exhaustive-integer-pattern-matching.md index cec34b5479a..6c45f1d4d69 100644 --- a/text/0000-exhaustive-integer-pattern-matching.md +++ b/text/0000-exhaustive-integer-pattern-matching.md @@ -6,7 +6,7 @@ # Summary [summary]: #summary -Extend Rust's pattern matching exhaustiveness checks to cover the integer types: `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, `isize` and `char`. +Extend Rust's pattern matching exhaustiveness checks to cover the integer types: `u8`, `u16`, `u32`, `u64`, `u128`, `i8`, `i16`, `i32`, `i64`, `i128` and `char`. ```rust fn matcher_full(x: u8) { @@ -36,7 +36,7 @@ This feature has already [been implemented](https://github.com/rust-lang/rust/pu # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -Exhaustive pattern matching works for integer types, just like any other type. In addition, missing ranges of integers will be reported as errors. +Exhaustive pattern matching works for integer types other than `usize` and `isize`, just like any other type. In addition, missing ranges of integers will be reported as errors. ```rust fn matcher_full(x: u8) { @@ -67,6 +67,8 @@ The implementation of this features uses interval arithmetic and an extension of This feature has already [been implemented](https://github.com/rust-lang/rust/pull/50912), so the code there may be used for further reference. The source contains detailed comments about the implementation. +Exhaustiveness checking for `usize` and `isize` will be placed behind an unstable feature flag, `exhaustive_pointer_size_matching`. + # Drawbacks [drawbacks]: #drawbacks From 46135303146c660f3c5d34484e0ede6295c8f4e7 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 19 Nov 2018 17:32:50 +0000 Subject: [PATCH 5/6] Permit usize/isize matching in theory once open-ended range patterns exist --- text/0000-exhaustive-integer-pattern-matching.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-exhaustive-integer-pattern-matching.md b/text/0000-exhaustive-integer-pattern-matching.md index 6c45f1d4d69..a7cf0edc454 100644 --- a/text/0000-exhaustive-integer-pattern-matching.md +++ b/text/0000-exhaustive-integer-pattern-matching.md @@ -6,7 +6,7 @@ # Summary [summary]: #summary -Extend Rust's pattern matching exhaustiveness checks to cover the integer types: `u8`, `u16`, `u32`, `u64`, `u128`, `i8`, `i16`, `i32`, `i64`, `i128` and `char`. +Extend Rust's pattern matching exhaustiveness checks to cover the integer types: `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, `isize` and `char`. ```rust fn matcher_full(x: u8) { @@ -36,7 +36,7 @@ This feature has already [been implemented](https://github.com/rust-lang/rust/pu # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -Exhaustive pattern matching works for integer types other than `usize` and `isize`, just like any other type. In addition, missing ranges of integers will be reported as errors. +Exhaustive pattern matching works for integer types, just like any other type. In addition, missing ranges of integers will be reported as errors. ```rust fn matcher_full(x: u8) { @@ -67,7 +67,7 @@ The implementation of this features uses interval arithmetic and an extension of This feature has already [been implemented](https://github.com/rust-lang/rust/pull/50912), so the code there may be used for further reference. The source contains detailed comments about the implementation. -Exhaustiveness checking for `usize` and `isize` will be placed behind an unstable feature flag, `exhaustive_pointer_size_matching`. +For `usize` and `isize`, no assumptions about the maximimum value are permitted. To exhaustively match on either pointer-size integer type a wildcard pattern (`_`) must be used (or if [open-ended range patterns are added](https://github.com/rust-lang/rfcs/issues/947), ranges must be open ended [e.g. `0..`]). An unstable feature `precise_pointer_size_matching` will be added to permit matching exactly on pointer-size integer types. # Drawbacks [drawbacks]: #drawbacks From aa06b37654d29bb96fafe628e97d259d18e6b2fb Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 1 Dec 2018 00:07:52 +0100 Subject: [PATCH 6/6] RFC 2591 --- ...ching.md => 2591-exhaustive-integer-pattern-matching.md} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename text/{0000-exhaustive-integer-pattern-matching.md => 2591-exhaustive-integer-pattern-matching.md} (96%) diff --git a/text/0000-exhaustive-integer-pattern-matching.md b/text/2591-exhaustive-integer-pattern-matching.md similarity index 96% rename from text/0000-exhaustive-integer-pattern-matching.md rename to text/2591-exhaustive-integer-pattern-matching.md index a7cf0edc454..9f35df9dc3a 100644 --- a/text/0000-exhaustive-integer-pattern-matching.md +++ b/text/2591-exhaustive-integer-pattern-matching.md @@ -1,7 +1,7 @@ - Feature Name: `exhaustive_integer_patterns` -- Start Date: 10/11/2018 -- RFC PR: -- Rust Issue: [#50907](https://github.com/rust-lang/rust/issues/50907) +- Start Date: 2018-10-11 +- RFC PR: [rust-lang/rfcs#2591](https://github.com/rust-lang/rfcs/pull/2591) +- Rust Issue: [rust-lang/rust#50907](https://github.com/rust-lang/rust/issues/50907) # Summary [summary]: #summary