- Feature Name: one_sided_match_ranges
- Start Date: 2015-02-15
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)
Allow inclusive ranges in match patterns that are bounded on only one side,
analogous to the RangeTo
and RangeFrom
exclusive ranges used in expressions.
Also have the compiler check whether integer patterns exhaust all possible values, so that providing an unreachable match arm for certain integer match expressions is no longer necessary (or in fact allowed).
This clears up a minor wart that adds some confusion and perceived complexity to
the language. Allowed range patterns include i..j
, ..j
, i..
, and simply
..
. However, match pattern ranges can only have the form i...j
.
Furthermore, even if the patterns in a match statement are provably exhaustive,
the reference compiler currently requires a catch-all _
pattern, which in
such cases is actually unreachable.
A more speculative use case relates to the future addition of dependent types
(or at least types that depend on integer constants, as [T; N]
arrays already
do). For such types, match patterns could be useful for expressing bounds on
constant parameters in types, in a way that's limited enough to inform coherence
checks and allow for specialization of impls.
Just as the match pattern i...j
matches numbers between i
and j
(inclusive), i...
will match all numbers greater than or equal to i
, and
...j
will match all numbers less than or equal to j
. This capability is
extended to char
as well, under the same ordering used for match patterns now.
Additionally, exhaustiveness checks will be performed for patterns that match
integers and char
, as opposed to the current implementation, which requires
the last arm of such match patterns to be a blanket match.
Consider the following example:
let error_code: u8 = do_something();
match error_code {
0 => Success,
1 | 3 => Failure,
2...255 => Error,
_ => unreachable!(),
}
Assuming that all referenced items have been defined, the above code is legal today.
Under this proposal, this code would need to be adjusted to the following, since the compiler would verify that these possibilities exhaust the entire allowed range of integers:
let error_code: u8 = do_something();
match error_code {
0 => Success,
1 | 3 => Failure,
2...255 => Error,
}
Since 255
is the maximum representable value for u8
, the following would be
equivalent:
let error_code: u8 = do_something();
match error_code {
0 => Success,
1 | 3 => Failure,
2... => Error,
}
A set of patterns will be considered to exhaustively cover an integer type if
all possible values for that type are covered. A set of patterns will be
considered to exhaustively cover char
if all valid char
values (that is, all
Unicode Scalar Values) are covered.
Floating point values will benefit from the new syntax (e.g. ...1.0f32
will be
an allowed pattern), but will not be subject to the changes in exhaustiveness
checking. The main rationale for this inconsistency is that floating-point
numbers have much more complex, and in some cases even platform-dependent,
semantics.
An prototype implementation of an algorithm that can perform most of the work for the exhaustiveness check is here. This is sufficient to check whether a series of ranges cover all allowed values of an integer type.
Finally, note that pattern guards will interact with exhaustiveness checks in
the same way as they do now. Namely, the compiler will check to see if a match
arm with a pattern guard is reachable, but will otherwise disregard it during
exhaustiveness checks. This means that the pattern 2...
will not always be
equivalent to the pattern x if x >= 2
.
Since more match arms can be proven unreachable, some code that currently compiles may be broken. However, such match expressions are probably rare.
Pattern syntax will become slightly more complex.
The current behavior is only a mild nuisance right now, so keeping it is definitely an option.
We could avoid breaking existing code by accepting match expressions with unreachable arms in some cases. In the examples above, the match expression that is allowed today would still be allowed, but the new expressions would also be allowed.
The new syntax and the change to exhaustiveness checks are independent features. They are included together mainly because the new syntax would make it easier to write exhaustive matches without using wildcards.
N/A