Skip to content

Exhaustive integer matching #50912

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 47 commits into from
Aug 22, 2018
Merged
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e3357d9
Implement interval checking
varkor May 19, 2018
b3d2baf
Give correct suggestions
varkor May 19, 2018
384db4f
Add support for all integer types
varkor May 19, 2018
ed5a4d5
Add feature gate and refactor
varkor May 19, 2018
b8702a0
Add feature gate test
varkor May 19, 2018
121fa8d
Fix handling of signed integers
varkor May 20, 2018
7476ba4
Add semi-exhaustive tests for exhaustiveness
varkor May 20, 2018
9778a81
Improve macros with reduced repetition
varkor May 20, 2018
a20cb10
Require just the Unicode Scalar Values to be matched for a char
varkor May 21, 2018
7f72030
Fix range splitting
varkor May 21, 2018
c00fd8f
Refactor interval conditions
varkor May 21, 2018
7695bd0
Use bit operators for min_max_ty
varkor May 21, 2018
a553fa7
Fix integer overflow
varkor May 22, 2018
8389972
Add singleton patterns to test
varkor May 22, 2018
f4af3b0
Refactor to remove explicit integer type matching
varkor May 22, 2018
a9f2c5a
Fix sign conversion arithmetic errors
varkor May 23, 2018
effb3d0
Improve the comments
varkor May 23, 2018
c388c11
Special-case (RangeEnd::Included, Ordering::Equal) in lower_pattern_u…
varkor May 23, 2018
97a032e
Simplify bitwise operations
varkor May 24, 2018
be12b24
Fix print_miri_value for signed integers
varkor May 24, 2018
72cc4bd
Inline encode and decode methods
varkor May 24, 2018
1aa7494
Introduce signed_bias method
varkor May 24, 2018
732d638
Replace ... with ..= in suggestions
varkor May 25, 2018
6c21a03
Refactor after miri api changes
varkor May 25, 2018
d27c21c
Refactor for less allocation
varkor May 28, 2018
07064de
No longer return value_constructors for all_constructors
varkor May 29, 2018
25ba911
Add guarded arms to tests
varkor Jun 2, 2018
af366b0
Refactor condition
varkor Jun 22, 2018
bfc0807
Add some comments
varkor Aug 12, 2018
4aa929c
Move witnesses inside push_wild_constructor
varkor Aug 12, 2018
5959a35
Move logic from push_wild_constructor to apply_constructor
varkor Aug 12, 2018
bfc8ce3
Add a test for integer products
varkor Aug 12, 2018
99754ad
Some reformatting
varkor Aug 12, 2018
400cb14
Add a summary of the algorithm to the file
varkor Aug 13, 2018
9e9e023
More formatting improvements
varkor Aug 13, 2018
527cccb
Add some more compound exhaustiveness tests
varkor Aug 14, 2018
e9c8361
Add equivalence class splitting for range constructors
varkor Aug 14, 2018
1dbc781
Handle equivalence classes of length-1 ranges
varkor Aug 14, 2018
0383539
Fix handling of floating-point ranges
varkor Aug 14, 2018
798b9ff
Tweak comments
varkor Aug 19, 2018
87463c3
Improve some comments
varkor Aug 20, 2018
6e8a625
Remove pattern consideration from split_grouped_constructors
varkor Aug 20, 2018
c421af9
Add assertion to constructor_intersects_pattern
varkor Aug 20, 2018
61b6363
Add more detail to the split_grouped_constructors comment
varkor Aug 20, 2018
6a957e1
Add a test case for u128::MAX - 1
varkor Aug 21, 2018
dec5563
Use a boundary method instead of an endpoint method for split_grouped…
varkor Aug 21, 2018
6971c5d
Add some extra edge case tests
varkor Aug 21, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor condition
  • Loading branch information
varkor committed Aug 16, 2018
commit af366b0eb86eb7111150b4143167440532e09520
58 changes: 27 additions & 31 deletions src/librustc_mir/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use arena::TypedArena;
use std::cmp::{self, Ordering};
use std::fmt;
use std::iter::{FromIterator, IntoIterator};
use std::ops::RangeInclusive;

pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
-> &'a Pattern<'tcx>
Expand Down Expand Up @@ -274,7 +275,7 @@ impl<'tcx> Constructor<'tcx> {
}
}

#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum Usefulness<'tcx> {
Useful,
UsefulWithWitness(Vec<Witness<'tcx>>),
Expand All @@ -290,7 +291,7 @@ impl<'tcx> Usefulness<'tcx> {
}
}

#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum WitnessPreference {
ConstructWitness,
LeaveOutWitness
Expand All @@ -303,7 +304,7 @@ struct PatternContext<'tcx> {
}

/// A stack of patterns in reverse order of construction
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Witness<'tcx>(Vec<Pattern<'tcx>>);

impl<'tcx> Witness<'tcx> {
Expand Down Expand Up @@ -418,10 +419,6 @@ impl<'tcx> Witness<'tcx> {
/// but is instead bounded by the maximum fixed length of slice patterns in
/// the column of patterns being analyzed.
///
/// This intentionally does not list ConstantValue specializations for
/// non-booleans, because we currently assume that there is always a
/// "non-standard constant" that matches. See issue #12483.
///
/// We make sure to omit constructors that are statically impossible. eg for
/// Option<!> we do not include Some(_) in the returned list of constructors.
fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
Expand Down Expand Up @@ -530,7 +527,7 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
// `[true, ..]`
// `[.., false]`
// Then any slice of length ≥1 that matches one of these two
// patterns can be be trivially turned to a slice of any
// patterns can be trivially turned to a slice of any
// other length ≥1 that matches them and vice-versa - for
// but the slice from length 2 `[false, true]` that matches neither
// of these patterns can't be turned to a slice from length 1 that
Expand Down Expand Up @@ -823,33 +820,32 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
// as patterns in the `match` expression, but did not.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code: extract this to a function?

let mut missing_ctors = vec![];
Copy link
Contributor

@arielb1 arielb1 Jul 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe extract this to a separate function? this is ok

for req_ctor in &all_ctors {
if consider_value_constructors {
let mut refined_ctors = vec![req_ctor.clone()];
for used_ctor in &used_ctors {
// Refine the required constructors for the type by subtracting
// the range defined by the current constructor pattern.
refined_ctors = match IntRange::from_ctor(cx.tcx, used_ctor) {
Some(interval) => interval.subtract_from(cx.tcx, refined_ctors),
None => refined_ctors,
};
// If the constructor patterns that have been considered so far
// already cover the entire range of values, then we the
// constructor is not missing, and we can move on to the next one.
if refined_ctors.is_empty() {
break;
let mut refined_ctors = vec![req_ctor.clone()];
for used_ctor in &used_ctors {
if used_ctor == req_ctor {
// If a constructor appears in a `match` arm, we can
// eliminate it straight away.
refined_ctors = vec![]
} else if exhaustive_integer_patterns {
if let Some(interval) = IntRange::from_ctor(cx.tcx, used_ctor) {
// Refine the required constructors for the type by subtracting
// the range defined by the current constructor pattern.
refined_ctors = interval.subtract_from(cx.tcx, refined_ctors);
}
}
// If a constructor has not been matched, then it is missing.
// We add `refined_ctors` instead of `req_ctor`, because then we can
// provide more detailed error information about precisely which
// ranges have been omitted.
missing_ctors.extend(refined_ctors);
} else {
// A constructor is missing if it never appears in a `match` arm.
if !used_ctors.iter().any(|used_ctor| used_ctor == req_ctor) {
missing_ctors.push(req_ctor.clone());

// If the constructor patterns that have been considered so far
// already cover the entire range of values, then we the
// constructor is not missing, and we can move on to the next one.
if refined_ctors.is_empty() {
break;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these codepaths could be unified - that is, in the other path, if exhaustive_integer_patterns is false or IntRange::from_ctor returns None, also try ==.
I doubt consider_value_constructors is needed at all, given those changes.

}
// If a constructor has not been matched, then it is missing.
// We add `refined_ctors` instead of `req_ctor`, because then we can
// provide more detailed error information about precisely which
// ranges have been omitted.
missing_ctors.extend(refined_ctors);
}

// `missing_ctors` is the set of constructors from the same type as the
Expand Down