diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 9ecbf748d7c..673ff9e86c4 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -238,6 +238,13 @@ pub struct MatchPair<'pat, 'tcx:'pat> { // ... must match this pattern. pattern: &'pat Pattern<'tcx>, + + // HACK(eddyb) This is used to toggle whether a Slice pattern + // has had its length checked. This is only necessary because + // the "rest" part of the pattern right now has type &[T] and + // as such, it requires an Rvalue::Slice to be generated. + // See RFC 495 / issue #23121 for the eventual (proper) solution. + slice_len_checked: bool } #[derive(Clone, Debug, PartialEq)] diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 2c8e1c1ccf6..a3337badf88 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -95,7 +95,18 @@ impl<'a,'tcx> Builder<'a,'tcx> { Err(match_pair) } - PatternKind::Array { ref prefix, ref slice, ref suffix } => { + PatternKind::Range { .. } | + PatternKind::Variant { .. } => { + // cannot simplify, test is required + Err(match_pair) + } + + PatternKind::Slice { .. } if !match_pair.slice_len_checked => { + Err(match_pair) + } + + PatternKind::Array { ref prefix, ref slice, ref suffix } | + PatternKind::Slice { ref prefix, ref slice, ref suffix } => { unpack!(block = self.prefix_suffix_slice(&mut candidate.match_pairs, block, match_pair.lvalue.clone(), @@ -105,13 +116,6 @@ impl<'a,'tcx> Builder<'a,'tcx> { Ok(block) } - PatternKind::Slice { .. } | - PatternKind::Range { .. } | - PatternKind::Variant { .. } => { - // cannot simplify, test is required - Err(match_pair) - } - PatternKind::Leaf { ref subpatterns } => { // tuple struct, match subpats (if any) candidate.match_pairs diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 4e3a69bf745..113084f8ccd 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -75,7 +75,8 @@ impl<'a,'tcx> Builder<'a,'tcx> { } } - PatternKind::Slice { ref prefix, ref slice, ref suffix } => { + PatternKind::Slice { ref prefix, ref slice, ref suffix } + if !match_pair.slice_len_checked => { let len = prefix.len() + suffix.len(); let op = if slice.is_some() { BinOp::Ge @@ -89,6 +90,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { } PatternKind::Array { .. } | + PatternKind::Slice { .. } | PatternKind::Wild | PatternKind::Binding { .. } | PatternKind::Leaf { .. } | @@ -413,9 +415,26 @@ impl<'a,'tcx> Builder<'a,'tcx> { } } - TestKind::Eq { .. } | - TestKind::Range { .. } | + // If we are performing a length check, then this + // informs slice patterns, but nothing else. TestKind::Len { .. } => { + let pattern_test = self.test(&match_pair); + match *match_pair.pattern.kind { + PatternKind::Slice { .. } if pattern_test.kind == test.kind => { + let mut new_candidate = candidate.clone(); + + // Set up the MatchKind to simplify this like an array. + new_candidate.match_pairs[match_pair_index] + .slice_len_checked = true; + resulting_candidates[0].push(new_candidate); + true + } + _ => false + } + } + + TestKind::Eq { .. } | + TestKind::Range { .. } => { // These are all binary tests. // // FIXME(#29623) we can be more clever here diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index c295ed168ba..d9b90fff784 100644 --- a/src/librustc_mir/build/matches/util.rs +++ b/src/librustc_mir/build/matches/util.rs @@ -118,6 +118,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { MatchPair { lvalue: lvalue, pattern: pattern, + slice_len_checked: false, } } }