+ 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);
+ }
+ }
+