Implement general or-patterns in match expressions

This commit is contained in:
Matthew Jasper 2019-12-27 13:39:43 +00:00
parent 64eab7750b
commit 5cc4352bc4
4 changed files with 381 additions and 88 deletions

View File

@ -26,7 +26,9 @@ mod simplify;
mod test;
mod util;
use std::borrow::Borrow;
use std::convert::TryFrom;
use std::mem;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Generates MIR for a `match` expression.
@ -95,7 +97,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let match_has_guard = arms.iter().any(|arm| arm.guard.is_some());
let candidates =
arm_candidates.iter_mut().flat_map(|(_, candidates)| candidates).collect::<Vec<_>>();
arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
let fake_borrow_temps =
self.lower_match_tree(block, scrutinee_span, match_has_guard, candidates);
@ -145,27 +147,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self,
scrutinee: &Place<'tcx>,
arms: &'pat [Arm<'tcx>],
) -> Vec<(&'pat Arm<'tcx>, Vec<Candidate<'pat, 'tcx>>)> {
) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)> {
// Assemble a list of candidates: there is one candidate per pattern,
// which means there may be more than one candidate *per arm*.
arms.iter()
.map(|arm| {
let arm_has_guard = arm.guard.is_some();
let arm_candidates: Vec<_> = arm
.top_pats_hack()
.iter()
.map(|pattern| Candidate {
span: pattern.span,
has_guard: arm_has_guard,
match_pairs: smallvec![MatchPair::new(*scrutinee, pattern)],
bindings: vec![],
ascriptions: vec![],
otherwise_block: None,
pre_binding_block: None,
next_candidate_pre_binding_block: None,
})
.collect();
(arm, arm_candidates)
let arm_candidate = Candidate {
span: arm.pattern.span,
match_pairs: smallvec![MatchPair::new(*scrutinee, &arm.pattern),],
bindings: vec![],
ascriptions: vec![],
has_guard: arm_has_guard,
needs_otherwise_block: arm_has_guard,
otherwise_block: None,
pre_binding_block: None,
next_candidate_pre_binding_block: None,
subcandidates: vec![],
};
(arm, arm_candidate)
})
.collect()
}
@ -205,11 +205,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable);
}
let mut next_prebinding_block = None;
let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None;
for candidate in candidates.iter_mut().rev() {
candidate.next_candidate_pre_binding_block = next_prebinding_block;
next_prebinding_block = candidate.pre_binding_block;
for candidate in candidates.into_iter() {
candidate.visit_leaves(|leaf_candidate| {
if let Some(ref mut prev) = previous_candidate {
prev.next_candidate_pre_binding_block = leaf_candidate.pre_binding_block;
}
previous_candidate = Some(leaf_candidate);
});
}
if let Some(ref borrows) = fake_borrows {
@ -230,7 +234,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
destination: &Place<'tcx>,
scrutinee_place: Place<'tcx>,
scrutinee_span: Span,
arm_candidates: Vec<(&'_ Arm<'tcx>, Vec<Candidate<'_, 'tcx>>)>,
arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
outer_source_info: SourceInfo,
fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
) -> BlockAnd<()> {
@ -238,8 +242,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let arm_end_blocks: Vec<_> = arm_candidates
.into_iter()
.map(|(arm, candidates)| {
debug!("lowering arm {:?}\ncanidates = {:?}", arm, candidates);
.map(|(arm, candidate)| {
debug!("lowering arm {:?}\ncanidate = {:?}", arm, candidate);
let arm_source_info = self.source_info(arm.span);
let arm_scope = (arm.scope, arm_source_info);
@ -248,14 +252,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let scope = this.declare_bindings(
None,
arm.span,
&arm.top_pats_hack()[0],
&arm.pattern,
ArmHasGuard(arm.guard.is_some()),
Some((Some(&scrutinee_place), scrutinee_span)),
);
let arm_block = this.bind_pattern(
outer_source_info,
candidates,
candidate,
arm.guard.as_ref().map(|g| (g, match_scope)),
&fake_borrow_temps,
scrutinee_span,
@ -289,35 +293,52 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn bind_pattern(
&mut self,
outer_source_info: SourceInfo,
mut candidates: Vec<Candidate<'_, 'tcx>>,
candidate: Candidate<'_, 'tcx>,
guard: Option<(&Guard<'tcx>, region::Scope)>,
fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
scrutinee_span: Span,
arm_scope: region::Scope,
) -> BasicBlock {
if candidates.len() == 1 {
if candidate.subcandidates.is_empty() {
// Avoid generating another `BasicBlock` when we only have one
// candidate.
self.bind_and_guard_matched_candidate(
candidates.pop().unwrap(),
candidate,
&[],
guard,
fake_borrow_temps,
scrutinee_span,
)
} else {
let arm_block = self.cfg.start_new_block();
for candidate in candidates {
// Avoid scheduling drops multiple times.
self.clear_top_scope(arm_scope);
let binding_end = self.bind_and_guard_matched_candidate(
candidate,
guard,
fake_borrow_temps,
scrutinee_span,
);
self.cfg.goto(binding_end, outer_source_info, arm_block);
}
arm_block
let target_block = self.cfg.start_new_block();
// We keep a stack of all of the bindings and type asciptions
// from the the parent candidates that we visit, that also need to
// be bound for each candidate.
traverse_candidate(
candidate,
&mut Vec::new(),
&mut |leaf_candidate, parent_bindings| {
self.clear_top_scope(arm_scope);
let binding_end = self.bind_and_guard_matched_candidate(
leaf_candidate,
parent_bindings,
guard,
&fake_borrow_temps,
scrutinee_span,
);
self.cfg.goto(binding_end, outer_source_info, target_block);
},
|inner_candidate, parent_bindings| {
parent_bindings.push((inner_candidate.bindings, inner_candidate.ascriptions));
inner_candidate.subcandidates.into_iter()
},
|parent_bindings| {
parent_bindings.pop();
},
);
target_block
}
}
@ -427,6 +448,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let mut candidate = Candidate {
span: irrefutable_pat.span,
has_guard: false,
needs_otherwise_block: false,
match_pairs: smallvec![MatchPair::new(*initializer, &irrefutable_pat)],
bindings: vec![],
ascriptions: vec![],
@ -435,6 +457,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
otherwise_block: None,
pre_binding_block: None,
next_candidate_pre_binding_block: None,
subcandidates: vec![],
};
// Simplify the candidate. Since the pattern is irrefutable, this should
@ -632,9 +655,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
PatKind::Or { ref pats } => {
for pat in pats {
self.visit_bindings(&pat, pattern_user_ty.clone(), f);
}
self.visit_bindings(&pats[0], pattern_user_ty.clone(), f);
}
}
}
@ -642,28 +663,72 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
#[derive(Debug)]
crate struct Candidate<'pat, 'tcx> {
// span of the original pattern that gave rise to this candidate
/// `Span` of the original pattern that gave rise to this candidate
span: Span,
/// This `Candidate` has a guard.
has_guard: bool,
// all of these must be satisfied...
/// This `Candidate` needs and otherwise block, either because it has a
/// guard or it has subcandidates.
needs_otherwise_block: bool,
/// All of these must be satisfied...
match_pairs: SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
// ...these bindings established...
/// ...these bindings established...
bindings: Vec<Binding<'tcx>>,
// ...and these types asserted...
/// ...and these types asserted...
ascriptions: Vec<Ascription<'tcx>>,
// ...and the guard must be evaluated, if false branch to Block...
/// ... and if this is non-empty, one of these subcandidates also has to match ...
subcandidates: Vec<Candidate<'pat, 'tcx>>,
/// ...and the guard must be evaluated, if false branch to Block...
otherwise_block: Option<BasicBlock>,
// ...and the blocks for add false edges between candidates
/// ...and the blocks for add false edges between candidates
pre_binding_block: Option<BasicBlock>,
next_candidate_pre_binding_block: Option<BasicBlock>,
}
impl Candidate<'_, '_> {
/// Visit the leaf candidates (those with no subcandidates) contained in
/// this candidate.
fn visit_leaves<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) {
traverse_candidate(
self,
&mut (),
&mut move |c, _| visit_leaf(c),
move |c, _| c.subcandidates.iter_mut(),
|_| {},
);
}
}
/// A depth-first traversal of the `Candidate` and all of its recursive
/// subcandidates.
fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>(
candidate: C,
context: &mut T,
visit_leaf: &mut impl FnMut(C, &mut T),
get_children: impl Copy + Fn(C, &mut T) -> I,
complete_children: impl Copy + Fn(&mut T),
) where
C: Borrow<Candidate<'pat, 'tcx>>,
I: Iterator<Item = C>,
{
if candidate.borrow().subcandidates.is_empty() {
visit_leaf(candidate, context)
} else {
for child in get_children(candidate, context) {
traverse_candidate(child, context, visit_leaf, get_children, complete_children);
}
complete_children(context)
}
}
#[derive(Clone, Debug)]
struct Binding<'tcx> {
span: Span,
@ -793,10 +858,45 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Start by simplifying candidates. Once this process is complete, all
// the match pairs which remain require some form of test, whether it
// be a switch or pattern comparison.
let mut split_or_candidate = false;
for candidate in &mut *candidates {
self.simplify_candidate(candidate);
split_or_candidate |= self.simplify_candidate(candidate);
}
if split_or_candidate {
// At least one of the candidates has been split into subcandidates.
// We need to change the candidate list to include those.
let mut new_candidates = Vec::new();
for candidate in candidates {
candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate));
}
self.match_simplified_candidates(
span,
start_block,
otherwise_block,
&mut *new_candidates,
fake_borrows,
);
} else {
self.match_simplified_candidates(
span,
start_block,
otherwise_block,
candidates,
fake_borrows,
);
};
}
fn match_simplified_candidates(
&mut self,
span: Span,
start_block: BasicBlock,
otherwise_block: &mut Option<BasicBlock>,
candidates: &mut [&mut Candidate<_, 'tcx>],
fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
) {
// The candidates are sorted by priority. Check to see whether the
// higher priority candidates (and hence at the front of the slice)
// have satisfied all their match pairs.
@ -835,7 +935,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
// Test for the remaining candidates.
self.test_candidates(span, unmatched_candidates, block, otherwise_block, fake_borrows);
self.test_candidates_with_or(
span,
unmatched_candidates,
block,
otherwise_block,
fake_borrows,
);
}
/// Link up matched candidates. For example, if we have something like
@ -866,6 +972,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
!matched_candidates.is_empty(),
"select_matched_candidates called with no candidates",
);
debug_assert!(
matched_candidates.iter().all(|c| c.subcandidates.is_empty()),
"subcandidates should be empty in select_matched_candidates",
);
// Insert a borrows of prefixes of places that are bound and are
// behind a dereference projection.
@ -902,7 +1012,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let fully_matched_with_guard = matched_candidates
.iter()
.position(|c| !c.has_guard)
.position(|c| !c.needs_otherwise_block)
.unwrap_or(matched_candidates.len() - 1);
let (reachable_candidates, unreachable_candidates) =
@ -914,7 +1024,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
assert!(candidate.otherwise_block.is_none());
assert!(candidate.pre_binding_block.is_none());
candidate.pre_binding_block = Some(next_prebinding);
if candidate.has_guard {
if candidate.needs_otherwise_block {
next_prebinding = self.cfg.start_new_block();
candidate.otherwise_block = Some(next_prebinding);
}
@ -932,6 +1042,120 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
reachable_candidates.last_mut().unwrap().otherwise_block
}
fn test_candidates_with_or(
&mut self,
span: Span,
candidates: &mut [&mut Candidate<'_, 'tcx>],
block: BasicBlock,
otherwise_block: &mut Option<BasicBlock>,
fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
) {
let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap();
if let PatKind::Or { .. } = *first_candidate.match_pairs[0].pattern.kind {
let match_pairs = mem::take(&mut first_candidate.match_pairs);
first_candidate.needs_otherwise_block = true;
first_candidate.pre_binding_block = Some(block);
// We sort or-patterns to the end in `simplify_candidate`, so all
// the remaining match pairs are or-patterns.
for match_pair in match_pairs {
if let PatKind::Or { ref pats } = *match_pair.pattern.kind {
let or_span = match_pair.pattern.span;
let place = &match_pair.place;
first_candidate.visit_leaves(|leaf_candidate| {
self.test_or_pattern(leaf_candidate, pats, or_span, place, fake_borrows);
});
} else {
bug!("Or patterns should have been sorted to the end");
}
}
let remainder_start =
first_candidate.otherwise_block.unwrap_or_else(|| self.cfg.start_new_block());
self.match_candidates(
span,
remainder_start,
otherwise_block,
remaining_candidates,
fake_borrows,
)
} else {
self.test_candidates(span, candidates, block, otherwise_block, fake_borrows)
}
}
fn test_or_pattern<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
pats: &'pat [Pat<'tcx>],
or_span: Span,
place: &Place<'tcx>,
fake_borrows: &mut Option<FxHashSet<Place<'tcx>>>,
) {
debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats);
let mut or_candidates: Vec<_> = pats
.iter()
.map(|pat| {
let new_match_pair = smallvec![MatchPair { pattern: pat, place: place.clone() }];
Candidate {
span: pat.span,
has_guard: candidate.has_guard,
needs_otherwise_block: candidate.needs_otherwise_block,
match_pairs: new_match_pair,
bindings: Vec::new(),
ascriptions: Vec::new(),
otherwise_block: None,
pre_binding_block: None,
next_candidate_pre_binding_block: None,
subcandidates: Vec::new(),
}
})
.collect();
let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect();
self.match_candidates(
or_span,
candidate.pre_binding_block.unwrap(),
&mut candidate.otherwise_block,
&mut or_candidate_refs,
fake_borrows,
);
candidate.subcandidates = or_candidates;
self.merge_trivial_subcandidates(candidate, self.source_info(or_span));
}
/// Try to merge all of the subcandidates of the given candidate into one.
/// This avoids exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`.
fn merge_trivial_subcandidates(
&mut self,
candidate: &mut Candidate<'_, 'tcx>,
source_info: SourceInfo,
) {
if candidate.subcandidates.is_empty() {
return;
}
let mut can_merge = !candidate.has_guard;
// Not `Iterator::all` because we don't want to short-circuit.
for subcandidate in &mut candidate.subcandidates {
self.merge_trivial_subcandidates(subcandidate, source_info);
// FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
can_merge &= subcandidate.subcandidates.is_empty()
&& subcandidate.bindings.is_empty()
&& subcandidate.ascriptions.is_empty();
}
if can_merge {
let any_matches = self.cfg.start_new_block();
for subcandidate in mem::take(&mut candidate.subcandidates) {
let or_block = subcandidate.pre_binding_block.unwrap();
self.cfg.goto(or_block, source_info, any_matches);
}
candidate.pre_binding_block = Some(any_matches);
}
}
/// This is the most subtle part of the matching algorithm. At
/// this point, the input candidates have been fully simplified,
/// and so we know that all remaining match-pairs require some
@ -1258,6 +1482,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn bind_and_guard_matched_candidate<'pat>(
&mut self,
candidate: Candidate<'pat, 'tcx>,
parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)],
guard: Option<(&Guard<'tcx>, region::Scope)>,
fake_borrows: &Vec<(Place<'tcx>, Local)>,
scrutinee_span: Span,
@ -1281,7 +1506,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block = fresh_block;
}
self.ascribe_types(block, &candidate.ascriptions);
self.ascribe_types(
block,
parent_bindings
.iter()
.flat_map(|(_, ascriptions)| ascriptions)
.chain(&candidate.ascriptions),
);
// rust-lang/rust#27282: The `autoref` business deserves some
// explanation here.
@ -1365,14 +1596,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// reference to that.
if let Some((guard, region_scope)) = guard {
let tcx = self.hir.tcx();
let bindings = parent_bindings
.iter()
.flat_map(|(bindings, _)| bindings)
.chain(&candidate.bindings);
self.bind_matched_candidate_for_guard(block, &candidate.bindings);
self.bind_matched_candidate_for_guard(block, bindings.clone());
let guard_frame = GuardFrame {
locals: candidate
.bindings
.iter()
.map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode))
.collect(),
locals: bindings.map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)).collect(),
};
debug!("entering guard building context: {:?}", guard_frame);
self.guard_context.push(guard_frame);
@ -1446,9 +1677,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// ```
//
// and that is clearly not correct.
let by_value_bindings = candidate.bindings.iter().filter(|binding| {
if let BindingMode::ByValue = binding.binding_mode { true } else { false }
});
let by_value_bindings =
parent_bindings
.iter()
.flat_map(|(bindings, _)| bindings)
.chain(&candidate.bindings)
.filter(|binding| {
if let BindingMode::ByValue = binding.binding_mode { true } else { false }
});
// Read all of the by reference bindings to ensure that the
// place they refer to can't be modified by the guard.
for binding in by_value_bindings.clone() {
@ -1460,18 +1696,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
post_guard_block
} else {
assert!(candidate.otherwise_block.is_none());
// (Here, it is not too early to bind the matched
// candidate on `block`, because there is no guard result
// that we have to inspect before we bind them.)
self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
self.bind_matched_candidate_for_arm_body(
block,
parent_bindings
.iter()
.flat_map(|(bindings, _)| bindings)
.chain(&candidate.bindings),
);
block
}
}
/// Append `AscribeUserType` statements onto the end of `block`
/// for each ascription
fn ascribe_types(&mut self, block: BasicBlock, ascriptions: &[Ascription<'tcx>]) {
fn ascribe_types<'b>(
&mut self,
block: BasicBlock,
ascriptions: impl IntoIterator<Item = &'b Ascription<'tcx>>,
) where
'tcx: 'b,
{
for ascription in ascriptions {
let source_info = self.source_info(ascription.span);
@ -1498,14 +1745,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
fn bind_matched_candidate_for_guard(&mut self, block: BasicBlock, bindings: &[Binding<'tcx>]) {
debug!("bind_matched_candidate_for_guard(block={:?}, bindings={:?})", block, bindings);
fn bind_matched_candidate_for_guard<'b>(
&mut self,
block: BasicBlock,
bindings: impl IntoIterator<Item = &'b Binding<'tcx>>,
) where
'tcx: 'b,
{
debug!("bind_matched_candidate_for_guard(block={:?})", block);
// Assign each of the bindings. Since we are binding for a
// guard expression, this will never trigger moves out of the
// candidate.
let re_erased = self.hir.tcx().lifetimes.re_erased;
for binding in bindings {
debug!("bind_matched_candidate_for_guard(binding={:?})", binding);
let source_info = self.source_info(binding.span);
// For each pattern ident P of type T, `ref_for_guard` is

View File

@ -16,18 +16,40 @@ use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
use crate::build::Builder;
use crate::hair::{self, *};
use rustc::mir::interpret::truncate;
use rustc::mir::Place;
use rustc::ty;
use rustc::ty::layout::{Integer, IntegerExt, Size};
use rustc_attr::{SignedInt, UnsignedInt};
use rustc_hir::RangeEnd;
use smallvec::smallvec;
use std::mem;
impl<'a, 'tcx> Builder<'a, 'tcx> {
crate fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) {
/// Simplify a candidate so that all match pairs require a test.
///
/// This method will also split a candidate where the only match-pair is an
/// or-pattern into multiple candidates. This is so that
///
/// match x {
/// 0 | 1 => { ... },
/// 2 | 3 => { ... },
/// }
///
/// only generates a single switch. If this happens this method returns
/// `true`.
crate fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) -> bool {
// repeatedly simplify match pairs until fixed point is reached
loop {
let match_pairs = mem::take(&mut candidate.match_pairs);
if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, ref place }] =
*match_pairs
{
candidate.subcandidates = self.create_or_subcanidates(candidate, place, pats);
return true;
}
let mut changed = false;
for match_pair in match_pairs {
match self.simplify_match_pair(match_pair, candidate) {
@ -40,11 +62,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
if !changed {
return; // if we were not able to simplify any, done.
// Move or-patterns to the end, because they can result in us
// creating additional candidates, so we want to test them as
// late as possible.
candidate
.match_pairs
.sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. }));
return false; // if we were not able to simplify any, done.
}
}
}
fn create_or_subcanidates<'pat>(
&mut self,
candidate: &Candidate<'pat, 'tcx>,
place: &Place<'tcx>,
pats: &'pat [Pat<'tcx>],
) -> Vec<Candidate<'pat, 'tcx>> {
pats.iter()
.map(|pat| {
let mut candidate = Candidate {
span: pat.span,
has_guard: candidate.has_guard,
needs_otherwise_block: candidate.needs_otherwise_block,
match_pairs: smallvec![MatchPair { place: place.clone(), pattern: pat }],
bindings: vec![],
ascriptions: vec![],
subcandidates: vec![],
otherwise_block: None,
pre_binding_block: None,
next_candidate_pre_binding_block: None,
};
self.simplify_candidate(&mut candidate);
candidate
})
.collect()
}
/// Tries to simplify `match_pair`, returning `Ok(())` if
/// successful. If successful, new match pairs and bindings will
/// have been pushed into the candidate. If no simplification is

View File

@ -70,11 +70,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
PatKind::Or { .. } => self
.hir
.tcx()
.sess
.span_fatal(match_pair.pattern.span, "or-patterns are not fully implemented yet"),
PatKind::Or { .. } => bug!("or-patterns should have already been handled"),
PatKind::AscribeUserType { .. }
| PatKind::Array { .. }

View File

@ -315,17 +315,6 @@ crate struct Arm<'tcx> {
crate span: Span,
}
impl<'tcx> Arm<'tcx> {
// HACK(or_patterns; Centril | dlrobertson): Remove this and
// correctly handle each case in which this method is used.
crate fn top_pats_hack(&self) -> &[Pat<'tcx>] {
match &*self.pattern.kind {
PatKind::Or { pats } => pats,
_ => std::slice::from_ref(&self.pattern),
}
}
}
#[derive(Clone, Debug)]
crate enum Guard<'tcx> {
If(ExprRef<'tcx>),