diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 35f5a6bfac5..309fd3bf09e 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -22,8 +22,6 @@ use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Pos, Span}; use rustc_target::abi::VariantIdx; -use smallvec::{smallvec, SmallVec}; - // helper functions, broken out by category: mod simplify; mod test; @@ -949,12 +947,16 @@ struct Candidate<'pat, 'tcx> { has_guard: bool, /// All of these must be satisfied... - match_pairs: SmallVec<[MatchPair<'pat, 'tcx>; 1]>, + // Invariant: all the `MatchPair`s are recursively simplified. + // Invariant: or-patterns must be sorted at the end. + match_pairs: Vec>, /// ...these bindings established... + // Invariant: not mutated outside `Candidate::new()`. bindings: Vec>, /// ...and these types asserted... + // Invariant: not mutated outside `Candidate::new()`. ascriptions: Vec>, /// ...and if this is non-empty, one of these subcandidates also has to match... @@ -974,19 +976,27 @@ fn new( place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, has_guard: bool, - cx: &Builder<'_, 'tcx>, + cx: &mut Builder<'_, 'tcx>, ) -> Self { - Candidate { + let mut candidate = Candidate { span: pattern.span, has_guard, - match_pairs: smallvec![MatchPair::new(place, pattern, cx)], + match_pairs: vec![MatchPair::new(place, pattern, cx)], bindings: Vec::new(), ascriptions: Vec::new(), subcandidates: Vec::new(), otherwise_block: None, pre_binding_block: None, next_candidate_pre_binding_block: None, - } + }; + + cx.simplify_match_pairs( + &mut candidate.match_pairs, + &mut candidate.bindings, + &mut candidate.ascriptions, + ); + + candidate } /// Visit the leaf candidates (those with no subcandidates) contained in @@ -1042,13 +1052,18 @@ struct Ascription<'tcx> { variance: ty::Variance, } -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) struct MatchPair<'pat, 'tcx> { - // this place... + // This place... place: PlaceBuilder<'tcx>, // ... must match this pattern. + // Invariant: after creation and simplification in `Candidate::new()`, all match pairs must be + // simplified, i.e. require a test. pattern: &'pat Pat<'tcx>, + + /// Precomputed sub-match pairs of `pattern`. + subpairs: Vec, } /// See [`Test`] for more. @@ -1165,12 +1180,25 @@ fn match_candidates<'pat>( candidates: &mut [&mut Candidate<'pat, 'tcx>], fake_borrows: &mut Option>>, ) { - // 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 { - split_or_candidate |= self.simplify_candidate(candidate); + if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = + &*candidate.match_pairs + { + // Split a candidate in which 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. + candidate.subcandidates = + self.create_or_subcandidates(place, pats, candidate.has_guard); + candidate.match_pairs.pop(); + split_or_candidate = true; + } } ensure_sufficient_stack(|| { diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index dba8e8b6499..83922dce327 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -6,7 +6,7 @@ //! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]` //! - `place @ x` can be simplified to `[]` by binding `x` to `place` //! -//! The `simplify_candidate` routine just repeatedly applies these +//! The `simplify_match_pairs` routine just repeatedly applies these //! sort of simplifications until there is nothing left to //! simplify. Match pairs cannot be simplified if they require some //! sort of test: for example, testing which variant an enum is, or @@ -22,25 +22,15 @@ use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { - /// Simplify a candidate so that all match pairs require a test. - /// - /// This method will also split a candidate, in which 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`. - #[instrument(skip(self, candidate), level = "debug")] - pub(super) fn simplify_candidate<'pat>( + /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and + /// ascriptions in the provided `Vec`s. + #[instrument(skip(self), level = "debug")] + pub(super) fn simplify_match_pairs<'pat>( &mut self, - candidate: &mut Candidate<'pat, 'tcx>, - ) -> bool { - debug!("{candidate:#?}"); + match_pairs: &mut Vec>, + candidate_bindings: &mut Vec>, + candidate_ascriptions: &mut Vec>, + ) { // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the // bindings in `pat` before `x`. E.g. (#69971): // @@ -68,105 +58,96 @@ pub(super) fn simplify_candidate<'pat>( // bindings in iter 2: [6, 7] // // final bindings: [6, 7, 4, 5, 1, 2, 3] - let mut accumulated_bindings = mem::take(&mut candidate.bindings); - // Repeatedly simplify match pairs until fixed point is reached + let mut accumulated_bindings = mem::take(candidate_bindings); + let mut simplified_match_pairs = Vec::new(); + // Repeatedly simplify match pairs until we're left with only unsimplifiable ones. loop { - let mut changed = false; - for match_pair in mem::take(&mut candidate.match_pairs) { - match self.simplify_match_pair(match_pair, candidate) { - Ok(()) => { - changed = true; - } - Err(match_pair) => { - candidate.match_pairs.push(match_pair); - } + for match_pair in mem::take(match_pairs) { + if let Err(match_pair) = self.simplify_match_pair( + match_pair, + candidate_bindings, + candidate_ascriptions, + match_pairs, + ) { + simplified_match_pairs.push(match_pair); } } // This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings - candidate.bindings.extend_from_slice(&accumulated_bindings); - mem::swap(&mut candidate.bindings, &mut accumulated_bindings); - candidate.bindings.clear(); + candidate_bindings.extend_from_slice(&accumulated_bindings); + mem::swap(candidate_bindings, &mut accumulated_bindings); + candidate_bindings.clear(); - if !changed { - // If we were not able to simplify anymore, done. + if match_pairs.is_empty() { break; } } - // Store computed bindings back in `candidate`. - mem::swap(&mut candidate.bindings, &mut accumulated_bindings); - - let did_expand_or = - if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = - &*candidate.match_pairs - { - candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats); - candidate.match_pairs.clear(); - true - } else { - false - }; + // Store computed bindings back in `candidate_bindings`. + mem::swap(candidate_bindings, &mut accumulated_bindings); + // Store simplified match pairs back in `match_pairs`. + mem::swap(match_pairs, &mut simplified_match_pairs); // 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 { .. })); - debug!(simplified = ?candidate, "simplify_candidate"); - - did_expand_or + match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); + debug!(simplified = ?match_pairs, "simplify_match_pairs"); } - /// Given `candidate` that has a single or-pattern for its match-pairs, - /// creates a fresh candidate for each of its input subpatterns passed via - /// `pats`. - fn create_or_subcandidates<'pat>( + /// Create a new candidate for each pattern in `pats`, and recursively simplify tje + /// single-or-pattern case. + pub(super) fn create_or_subcandidates<'pat>( &mut self, - candidate: &Candidate<'pat, 'tcx>, place: &PlaceBuilder<'tcx>, pats: &'pat [Box>], + has_guard: bool, ) -> Vec> { pats.iter() .map(|box pat| { - let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard, self); - self.simplify_candidate(&mut candidate); + let mut candidate = Candidate::new(place.clone(), pat, has_guard, self); + if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = + &*candidate.match_pairs + { + candidate.subcandidates = + self.create_or_subcandidates(place, pats, candidate.has_guard); + candidate.match_pairs.pop(); + } 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 - /// possible, `Err` is returned and no changes are made to - /// candidate. + /// Tries to simplify `match_pair`, returning `Ok(())` if successful. If successful, new match + /// pairs and bindings will have been pushed into the respective `Vec`s. If no simplification is + /// possible, `Err` is returned. fn simplify_match_pair<'pat>( &mut self, - match_pair: MatchPair<'pat, 'tcx>, - candidate: &mut Candidate<'pat, 'tcx>, + mut match_pair: MatchPair<'pat, 'tcx>, + bindings: &mut Vec>, + ascriptions: &mut Vec>, + match_pairs: &mut Vec>, ) -> Result<(), MatchPair<'pat, 'tcx>> { match match_pair.pattern.kind { + PatKind::Leaf { .. } + | PatKind::Deref { .. } + | PatKind::Array { .. } + | PatKind::Never + | PatKind::Wild + | PatKind::Error(_) => {} + PatKind::AscribeUserType { - ref subpattern, ascription: thir::Ascription { ref annotation, variance }, + .. } => { // Apply the type ascription to the value at `match_pair.place` if let Some(source) = match_pair.place.try_to_place(self) { - candidate.ascriptions.push(Ascription { + ascriptions.push(Ascription { annotation: annotation.clone(), source, variance, }); } - - candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); - - Ok(()) - } - - PatKind::Wild | PatKind::Error(_) => { - // nothing left to do - Ok(()) } PatKind::Binding { @@ -175,35 +156,17 @@ fn simplify_match_pair<'pat>( mode, var, ty: _, - ref subpattern, + subpattern: _, is_primary: _, } => { if let Some(source) = match_pair.place.try_to_place(self) { - candidate.bindings.push(Binding { + bindings.push(Binding { span: match_pair.pattern.span, source, var_id: var, binding_mode: mode, }); } - - if let Some(subpattern) = subpattern.as_ref() { - // this is the `x @ P` case; have to keep matching against `P` now - candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); - } - - Ok(()) - } - - PatKind::Never => { - // A never pattern acts like a load from the place. - // FIXME(never_patterns): load from the place - Ok(()) - } - - PatKind::Constant { .. } => { - // FIXME normalize patterns when possible - Err(match_pair) } PatKind::InlineConstant { subpattern: ref pattern, def } => { @@ -232,42 +195,33 @@ fn simplify_match_pair<'pat>( span, user_ty: Box::new(user_ty), }; - candidate.ascriptions.push(Ascription { + ascriptions.push(Ascription { annotation, source, variance: ty::Contravariant, }); } - candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); + } - Ok(()) + PatKind::Constant { .. } => { + // FIXME normalize patterns when possible + return Err(match_pair); } PatKind::Range(ref range) => { - if let Some(true) = range.is_full_range(self.tcx) { - // Irrefutable pattern match. - return Ok(()); + if range.is_full_range(self.tcx) != Some(true) { + return Err(match_pair); } - Err(match_pair) } PatKind::Slice { ref prefix, ref slice, ref suffix } => { - if prefix.is_empty() && slice.is_some() && suffix.is_empty() { - // irrefutable - self.prefix_slice_suffix( - &mut candidate.match_pairs, - &match_pair.place, - prefix, - slice, - suffix, - ); - Ok(()) - } else { - Err(match_pair) + if !(prefix.is_empty() && slice.is_some() && suffix.is_empty()) { + self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions); + return Err(match_pair); } } - PatKind::Variant { adt_def, args, variant_index, ref subpatterns } => { + PatKind::Variant { adt_def, args, variant_index, subpatterns: _ } => { let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { i == variant_index || { (self.tcx.features().exhaustive_patterns @@ -279,41 +233,17 @@ fn simplify_match_pair<'pat>( } }) && (adt_def.did().is_local() || !adt_def.is_variant_list_non_exhaustive()); - if irrefutable { - let place_builder = match_pair.place.downcast(adt_def, variant_index); - candidate - .match_pairs - .extend(self.field_match_pairs(place_builder, subpatterns)); - Ok(()) - } else { - Err(match_pair) + if !irrefutable { + self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions); + return Err(match_pair); } } - PatKind::Array { ref prefix, ref slice, ref suffix } => { - self.prefix_slice_suffix( - &mut candidate.match_pairs, - &match_pair.place, - prefix, - slice, - suffix, - ); - Ok(()) - } - - PatKind::Leaf { ref subpatterns } => { - // tuple struct, match subpats (if any) - candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns)); - Ok(()) - } - - PatKind::Deref { ref subpattern } => { - let place_builder = match_pair.place.deref(); - candidate.match_pairs.push(MatchPair::new(place_builder, subpattern, self)); - Ok(()) - } - - PatKind::Or { .. } => Err(match_pair), + PatKind::Or { .. } => return Err(match_pair), } + + // Simplifiable pattern; we replace it with its subpairs. + match_pairs.append(&mut match_pair.subpairs); + Ok(()) } } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 990be30b2d6..ae9ebe7170b 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -590,25 +590,22 @@ pub(super) fn sort_candidate<'pat>( let (match_pair_index, match_pair) = candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?; - match (&test.kind, &match_pair.pattern.kind) { + let fully_matched; + let ret = match (&test.kind, &match_pair.pattern.kind) { // If we are performing a variant switch, then this // informs variant patterns, but nothing else. ( &TestKind::Switch { adt_def: tested_adt_def, .. }, - &PatKind::Variant { adt_def, variant_index, ref subpatterns, .. }, + &PatKind::Variant { adt_def, variant_index, .. }, ) => { assert_eq!(adt_def, tested_adt_def); - self.candidate_after_variant_switch( - match_pair_index, - adt_def, - variant_index, - subpatterns, - candidate, - ); + fully_matched = true; Some(variant_index.as_usize()) } - - (&TestKind::Switch { .. }, _) => None, + (&TestKind::Switch { .. }, _) => { + fully_matched = false; + None + } // If we are performing a switch over integers, then this informs integer // equality, but nothing else. @@ -618,12 +615,12 @@ pub(super) fn sort_candidate<'pat>( (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Constant { value }) if is_switch_ty(match_pair.pattern.ty) => { + fully_matched = true; let index = options.get_index_of(value).unwrap(); - self.candidate_without_match_pair(match_pair_index, candidate); Some(index) } - (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Range(range)) => { + fully_matched = false; let not_contained = self.values_not_contained_in_range(&*range, options).unwrap_or(false); @@ -633,8 +630,10 @@ pub(super) fn sort_candidate<'pat>( options.len() }) } - - (&TestKind::SwitchInt { .. }, _) => None, + (&TestKind::SwitchInt { .. }, _) => { + fully_matched = false; + None + } ( &TestKind::Len { len: test_len, op: BinOp::Eq }, @@ -645,34 +644,30 @@ pub(super) fn sort_candidate<'pat>( (Ordering::Equal, &None) => { // on true, min_len = len = $actual_length, // on false, len != $actual_length - self.candidate_after_slice_test( - match_pair_index, - candidate, - prefix, - slice, - suffix, - ); + fully_matched = true; Some(0) } (Ordering::Less, _) => { // test_len < pat_len. If $actual_len = test_len, // then $actual_len < pat_len and we don't have // enough elements. + fully_matched = false; Some(1) } (Ordering::Equal | Ordering::Greater, &Some(_)) => { // This can match both if $actual_len = test_len >= pat_len, // and if $actual_len > test_len. We can't advance. + fully_matched = false; None } (Ordering::Greater, &None) => { // test_len != pat_len, so if $actual_len = test_len, then // $actual_len != pat_len. + fully_matched = false; Some(1) } } } - ( &TestKind::Len { len: test_len, op: BinOp::Ge }, PatKind::Slice { prefix, slice, suffix }, @@ -683,29 +678,26 @@ pub(super) fn sort_candidate<'pat>( (Ordering::Equal, &Some(_)) => { // $actual_len >= test_len = pat_len, // so we can match. - self.candidate_after_slice_test( - match_pair_index, - candidate, - prefix, - slice, - suffix, - ); + fully_matched = true; Some(0) } (Ordering::Less, _) | (Ordering::Equal, &None) => { // test_len <= pat_len. If $actual_len < test_len, // then it is also < pat_len, so the test passing is // necessary (but insufficient). + fully_matched = false; Some(0) } (Ordering::Greater, &None) => { // test_len > pat_len. If $actual_len >= test_len > pat_len, // then we know we won't have a match. + fully_matched = false; Some(1) } (Ordering::Greater, &Some(_)) => { // test_len < pat_len, and is therefore less // strict. This can still go both ways. + fully_matched = false; None } } @@ -713,16 +705,17 @@ pub(super) fn sort_candidate<'pat>( (TestKind::Range(test), PatKind::Range(pat)) => { if test == pat { - self.candidate_without_match_pair(match_pair_index, candidate); - return Some(0); + fully_matched = true; + Some(0) + } else { + fully_matched = false; + // If the testing range does not overlap with pattern range, + // the pattern can be matched only if this test fails. + if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None } } - - // If the testing range does not overlap with pattern range, - // the pattern can be matched only if this test fails. - if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None } } - (TestKind::Range(range), &PatKind::Constant { value }) => { + fully_matched = false; if !range.contains(value, self.tcx, self.param_env)? { // `value` is not contained in the testing range, // so `value` can be matched only if this test fails. @@ -731,8 +724,10 @@ pub(super) fn sort_candidate<'pat>( None } } - - (&TestKind::Range { .. }, _) => None, + (&TestKind::Range { .. }, _) => { + fully_matched = false; + None + } (&TestKind::Eq { .. } | &TestKind::Len { .. }, _) => { // The call to `self.test(&match_pair)` below is not actually used to generate any @@ -751,64 +746,26 @@ pub(super) fn sort_candidate<'pat>( // FIXME(#29623) we can be more clever here let pattern_test = self.test(match_pair); if pattern_test.kind == test.kind { - self.candidate_without_match_pair(match_pair_index, candidate); + fully_matched = true; Some(0) } else { + fully_matched = false; None } } + }; + + if fully_matched { + // Replace the match pair by its sub-pairs. + let match_pair = candidate.match_pairs.remove(match_pair_index); + candidate.match_pairs.extend(match_pair.subpairs); + // Move or-patterns to the end. + candidate + .match_pairs + .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); } - } - fn candidate_without_match_pair( - &mut self, - match_pair_index: usize, - candidate: &mut Candidate<'_, 'tcx>, - ) { - candidate.match_pairs.remove(match_pair_index); - } - - fn candidate_after_slice_test<'pat>( - &mut self, - match_pair_index: usize, - candidate: &mut Candidate<'pat, 'tcx>, - prefix: &'pat [Box>], - opt_slice: &'pat Option>>, - suffix: &'pat [Box>], - ) { - let removed_place = candidate.match_pairs.remove(match_pair_index).place; - self.prefix_slice_suffix( - &mut candidate.match_pairs, - &removed_place, - prefix, - opt_slice, - suffix, - ); - } - - fn candidate_after_variant_switch<'pat>( - &mut self, - match_pair_index: usize, - adt_def: ty::AdtDef<'tcx>, - variant_index: VariantIdx, - subpatterns: &'pat [FieldPat<'tcx>], - candidate: &mut Candidate<'pat, 'tcx>, - ) { - let match_pair = candidate.match_pairs.remove(match_pair_index); - - // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, - // we want to create a set of derived match-patterns like - // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. - let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)` - let consequent_match_pairs = subpatterns.iter().map(|subpattern| { - // e.g., `(x as Variant).0` - let place = downcast_place - .clone_project(PlaceElem::Field(subpattern.field, subpattern.pattern.ty)); - // e.g., `(x as Variant).0 @ P1` - MatchPair::new(place, &subpattern.pattern, self) - }); - - candidate.match_pairs.extend(consequent_match_pairs); + ret } fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! { diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index c34105174ef..e42d764147c 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -6,7 +6,6 @@ use rustc_middle::thir::*; use rustc_middle::ty; use rustc_middle::ty::TypeVisitableExt; -use smallvec::SmallVec; impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn field_match_pairs<'pat>( @@ -26,7 +25,7 @@ pub(crate) fn field_match_pairs<'pat>( pub(crate) fn prefix_slice_suffix<'pat>( &mut self, - match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, + match_pairs: &mut Vec>, place: &PlaceBuilder<'tcx>, prefix: &'pat [Box>], opt_slice: &'pat Option>>, @@ -97,7 +96,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { pub(in crate::build) fn new( mut place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, - cx: &Builder<'_, 'tcx>, + cx: &mut Builder<'_, 'tcx>, ) -> MatchPair<'pat, 'tcx> { // Force the place type to the pattern's type. // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? @@ -117,6 +116,51 @@ pub(in crate::build) fn new( if may_need_cast { place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); } - MatchPair { place, pattern } + + let mut subpairs = Vec::new(); + match pattern.kind { + PatKind::Constant { .. } + | PatKind::Range(_) + | PatKind::Or { .. } + | PatKind::Never + | PatKind::Wild + | PatKind::Error(_) => {} + + PatKind::AscribeUserType { ref subpattern, .. } => { + subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); + } + + PatKind::Binding { ref subpattern, .. } => { + if let Some(subpattern) = subpattern.as_ref() { + // this is the `x @ P` case; have to keep matching against `P` now + subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); + } + } + + PatKind::InlineConstant { subpattern: ref pattern, .. } => { + subpairs.push(MatchPair::new(place.clone(), pattern, cx)); + } + + PatKind::Slice { ref prefix, ref slice, ref suffix } + | PatKind::Array { ref prefix, ref slice, ref suffix } => { + cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix); + } + + PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { + let downcast_place = place.clone().downcast(adt_def, variant_index); // `(x as Variant)` + subpairs = cx.field_match_pairs(downcast_place, subpatterns); + } + + PatKind::Leaf { ref subpatterns } => { + subpairs = cx.field_match_pairs(place.clone(), subpatterns); + } + + PatKind::Deref { ref subpattern } => { + let place_builder = place.clone().deref(); + subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + } + } + + MatchPair { place, pattern, subpairs } } } diff --git a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir index 596dcef85fd..ea5cd55b560 100644 --- a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir @@ -19,7 +19,8 @@ fn match_tuple(_1: (u32, bool, Option, u32)) -> u32 { bb0: { PlaceMention(_1); - switchInt((_1.0: u32)) -> [1: bb2, 4: bb2, otherwise: bb1]; + _2 = discriminant((_1.2: std::option::Option)); + switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; } bb1: { @@ -28,12 +29,11 @@ fn match_tuple(_1: (u32, bool, Option, u32)) -> u32 { } bb2: { - _2 = discriminant((_1.2: std::option::Option)); - switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb1]; + switchInt((((_1.2: std::option::Option) as Some).0: i32)) -> [1: bb3, 8: bb3, otherwise: bb1]; } bb3: { - switchInt((((_1.2: std::option::Option) as Some).0: i32)) -> [1: bb4, 8: bb4, otherwise: bb1]; + switchInt((_1.0: u32)) -> [1: bb4, 4: bb4, otherwise: bb1]; } bb4: {