From 5cc4352bc4f9789d7243e79684b2943d3d9ad450 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 27 Dec 2019 13:39:43 +0000 Subject: [PATCH] Implement general or-patterns in `match` expressions --- src/librustc_mir_build/build/matches/mod.rs | 394 ++++++++++++++---- .../build/matches/simplify.rs | 58 ++- src/librustc_mir_build/build/matches/test.rs | 6 +- src/librustc_mir_build/hair/mod.rs | 11 - 4 files changed, 381 insertions(+), 88 deletions(-) diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs index a060c8fd2a2..4ac3ced17db 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/src/librustc_mir_build/build/matches/mod.rs @@ -26,7 +26,9 @@ 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::>(); + arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::>(); let fake_borrow_temps = self.lower_match_tree(block, scrutinee_span, match_has_guard, candidates); @@ -145,27 +147,25 @@ fn create_match_candidates<'pat>( &mut self, scrutinee: &Place<'tcx>, arms: &'pat [Arm<'tcx>], - ) -> Vec<(&'pat Arm<'tcx>, Vec>)> { + ) -> 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 @@ fn lower_match_tree<'pat>( 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 @@ fn lower_match_arms( destination: &Place<'tcx>, scrutinee_place: Place<'tcx>, scrutinee_span: Span, - arm_candidates: Vec<(&'_ Arm<'tcx>, Vec>)>, + arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, outer_source_info: SourceInfo, fake_borrow_temps: Vec<(Place<'tcx>, Local)>, ) -> BlockAnd<()> { @@ -238,8 +242,8 @@ fn lower_match_arms( 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 @@ fn lower_match_arms( 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 @@ fn lower_match_arms( fn bind_pattern( &mut self, outer_source_info: SourceInfo, - mut candidates: Vec>, + 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 @@ pub(super) fn expr_into_pattern( 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 @@ pub(super) fn expr_into_pattern( 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 @@ pub(super) fn visit_bindings( } } 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 @@ pub(super) fn visit_bindings( #[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>, - // ...and these types asserted... + /// ...and these types asserted... ascriptions: Vec>, - // ...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>, + + /// ...and the guard must be evaluated, if false branch to Block... otherwise_block: Option, - // ...and the blocks for add false edges between candidates + /// ...and the blocks for add false edges between candidates pre_binding_block: Option, next_candidate_pre_binding_block: Option, } +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>, + I: Iterator, +{ + 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 @@ fn match_candidates<'pat>( // 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, + candidates: &mut [&mut Candidate<_, 'tcx>], + fake_borrows: &mut Option>>, + ) { // 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 @@ fn match_candidates<'pat>( } // 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 @@ fn select_matched_candidates( !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 @@ fn select_matched_candidates( 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 @@ fn select_matched_candidates( 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 @@ fn select_matched_candidates( 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, + fake_borrows: &mut Option>>, + ) { + 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>>, + ) { + 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>, Vec>)], guard: Option<(&Guard<'tcx>, region::Scope)>, fake_borrows: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, @@ -1281,7 +1506,13 @@ fn bind_and_guard_matched_candidate<'pat>( 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 @@ fn bind_and_guard_matched_candidate<'pat>( // 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 @@ fn bind_and_guard_matched_candidate<'pat>( // ``` // // 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 @@ fn bind_and_guard_matched_candidate<'pat>( 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>, + ) where + 'tcx: 'b, + { for ascription in ascriptions { let source_info = self.source_info(ascription.span); @@ -1498,14 +1745,21 @@ fn ascribe_types(&mut self, block: BasicBlock, ascriptions: &[Ascription<'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>, + ) 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 diff --git a/src/librustc_mir_build/build/matches/simplify.rs b/src/librustc_mir_build/build/matches/simplify.rs index 77bbce2d37a..3a806ab6bff 100644 --- a/src/librustc_mir_build/build/matches/simplify.rs +++ b/src/librustc_mir_build/build/matches/simplify.rs @@ -16,18 +16,40 @@ 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> { + 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 diff --git a/src/librustc_mir_build/build/matches/test.rs b/src/librustc_mir_build/build/matches/test.rs index 1f97f5f1b72..ff95f162257 100644 --- a/src/librustc_mir_build/build/matches/test.rs +++ b/src/librustc_mir_build/build/matches/test.rs @@ -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 { .. } diff --git a/src/librustc_mir_build/hair/mod.rs b/src/librustc_mir_build/hair/mod.rs index 0f2c76152ed..cb93ba7c925 100644 --- a/src/librustc_mir_build/hair/mod.rs +++ b/src/librustc_mir_build/hair/mod.rs @@ -315,17 +315,6 @@ 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>), -- 2.44.0