From e9bffdec751ece410f7e836454c90783cff498cd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 07:51:13 +0100 Subject: [PATCH 1/5] Pass Candidate exploded to simplify --- .../rustc_mir_build/src/build/matches/mod.rs | 8 +- .../src/build/matches/simplify.rs | 117 +++++++++++------- 2 files changed, 76 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 906b3205ca75d..26fa9d18c9183 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1172,7 +1172,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // be a switch or pattern comparison. let mut split_or_candidate = false; for candidate in &mut *candidates { - split_or_candidate |= self.simplify_candidate(candidate); + split_or_candidate |= self.simplify_candidate( + &mut candidate.bindings, + &mut candidate.ascriptions, + &mut candidate.match_pairs, + &mut candidate.subcandidates, + candidate.has_guard, + ); } 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 a7f6f4873e383..6ecdb0b706d20 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -16,6 +16,7 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Ascription, Binding, Candidate, MatchPair}; use crate::build::Builder; use rustc_middle::thir::{self, *}; +use smallvec::SmallVec; use std::mem; @@ -33,13 +34,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// only generates a single switch. If this happens this method returns /// `true`. - #[instrument(skip(self, candidate), level = "debug")] + #[instrument(skip(self), level = "debug")] pub(super) fn simplify_candidate<'pat>( &mut self, - candidate: &mut Candidate<'pat, 'tcx>, + bindings: &mut Vec>, + ascriptions: &mut Vec>, + match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, + subcandidates: &mut Vec>, + has_guard: bool, ) -> bool { + self.simplify_candidate_inner(bindings, ascriptions, match_pairs); + + if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = + &**match_pairs + { + *subcandidates = self.create_or_subcandidates(place, pats, has_guard); + match_pairs.pop(); + return true; + } + + false + } + + #[instrument(skip(self), level = "debug")] + pub(super) fn simplify_candidate_inner<'pat>( + &mut self, + candidate_bindings: &mut Vec>, + candidate_ascriptions: &mut Vec>, + candidate_match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, + ) { // repeatedly simplify match pairs until fixed point is reached - debug!("{candidate:#?}"); // existing_bindings and new_bindings exists to keep the semantics in order. // Reversing the binding order for bindings after `@` changes the binding order in places @@ -59,28 +83,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // binding in iter 2: [6, 7] // // final binding: [1, 2, 3, 6, 7, 4, 5] - let mut existing_bindings = mem::take(&mut candidate.bindings); + let mut existing_bindings = mem::take(candidate_bindings); let mut new_bindings = Vec::new(); loop { - let match_pairs = mem::take(&mut candidate.match_pairs); + let mut match_pairs = mem::take(candidate_match_pairs); - if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = - &*match_pairs + if let [MatchPair { pattern: Pat { kind: PatKind::Or { .. }, .. }, .. }] = &*match_pairs { existing_bindings.extend_from_slice(&new_bindings); - mem::swap(&mut candidate.bindings, &mut existing_bindings); - candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats); - return true; + mem::swap(candidate_bindings, &mut existing_bindings); + mem::swap(candidate_match_pairs, &mut match_pairs); + return; } let mut changed = false; for match_pair in match_pairs { - match self.simplify_match_pair(match_pair, candidate) { + match self.simplify_match_pair( + match_pair, + candidate_bindings, + candidate_ascriptions, + candidate_match_pairs, + ) { Ok(()) => { changed = true; } Err(match_pair) => { - candidate.match_pairs.push(match_pair); + candidate_match_pairs.push(match_pair); } } } @@ -97,21 +125,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // let z = x.copy_field; // let y = x; // } - candidate.bindings.extend_from_slice(&new_bindings); - mem::swap(&mut candidate.bindings, &mut new_bindings); - candidate.bindings.clear(); + candidate_bindings.extend_from_slice(&new_bindings); + mem::swap(candidate_bindings, &mut new_bindings); + candidate_bindings.clear(); if !changed { existing_bindings.extend_from_slice(&new_bindings); - mem::swap(&mut candidate.bindings, &mut existing_bindings); + mem::swap(candidate_bindings, &mut existing_bindings); // 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 + candidate_match_pairs .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); - debug!(simplified = ?candidate, "simplify_candidate"); - return false; // if we were not able to simplify any, done. + debug!(simplified = ?candidate_match_pairs, "simplify_candidate"); + return; // if we were not able to simplify any, done. } } } @@ -121,14 +148,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// `pats`. 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); + self.simplify_candidate( + &mut candidate.bindings, + &mut candidate.ascriptions, + &mut candidate.match_pairs, + &mut candidate.subcandidates, + candidate.has_guard, + ); candidate }) .collect() @@ -142,7 +175,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn simplify_match_pair<'pat>( &mut self, match_pair: MatchPair<'pat, 'tcx>, - candidate: &mut Candidate<'pat, 'tcx>, + bindings: &mut Vec>, + ascriptions: &mut Vec>, + match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, ) -> Result<(), MatchPair<'pat, 'tcx>> { match match_pair.pattern.kind { PatKind::AscribeUserType { @@ -151,14 +186,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { // Apply the type ascription to the value at `match_pair.place`, which is the 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)); + match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); Ok(()) } @@ -178,7 +213,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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, @@ -188,7 +223,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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)); + match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); } Ok(()) @@ -206,7 +241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::InlineConstant { subpattern: ref pattern, def: _ } => { - candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); + match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); Ok(()) } @@ -222,13 +257,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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, - ); + self.prefix_slice_suffix(match_pairs, &match_pair.place, prefix, slice, suffix); Ok(()) } else { Err(match_pair) @@ -248,9 +277,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { || !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)); + match_pairs.extend(self.field_match_pairs(place_builder, subpatterns)); Ok(()) } else { Err(match_pair) @@ -258,25 +285,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::Array { ref prefix, ref slice, ref suffix } => { - self.prefix_slice_suffix( - &mut candidate.match_pairs, - &match_pair.place, - prefix, - slice, - suffix, - ); + self.prefix_slice_suffix(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)); + 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)); + match_pairs.push(MatchPair::new(place_builder, subpattern, self)); Ok(()) } From 4689da3d54c1ecb338e7b093143485aca77bc09d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 08:00:31 +0100 Subject: [PATCH 2/5] Switch to Vec of MatchPairs Because I'm about to make MatchPair recursive, which I can't do with SmallVec, and I need to share code between the two. --- compiler/rustc_mir_build/src/build/matches/mod.rs | 6 ++---- compiler/rustc_mir_build/src/build/matches/simplify.rs | 8 +++----- compiler/rustc_mir_build/src/build/matches/util.rs | 3 +-- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 26fa9d18c9183..ae134389b4239 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_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; 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; @@ -951,7 +949,7 @@ struct Candidate<'pat, 'tcx> { has_guard: bool, /// All of these must be satisfied... - match_pairs: SmallVec<[MatchPair<'pat, 'tcx>; 1]>, + match_pairs: Vec>, /// ...these bindings established... bindings: Vec>, @@ -981,7 +979,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { 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(), diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 6ecdb0b706d20..8e5f5238a651d 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -16,8 +16,6 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Ascription, Binding, Candidate, MatchPair}; use crate::build::Builder; use rustc_middle::thir::{self, *}; -use smallvec::SmallVec; - use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -39,7 +37,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, bindings: &mut Vec>, ascriptions: &mut Vec>, - match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, + match_pairs: &mut Vec>, subcandidates: &mut Vec>, has_guard: bool, ) -> bool { @@ -61,7 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate_bindings: &mut Vec>, candidate_ascriptions: &mut Vec>, - candidate_match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, + candidate_match_pairs: &mut Vec>, ) { // repeatedly simplify match pairs until fixed point is reached @@ -177,7 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pair: MatchPair<'pat, 'tcx>, bindings: &mut Vec>, ascriptions: &mut Vec>, - match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, + match_pairs: &mut Vec>, ) -> Result<(), MatchPair<'pat, 'tcx>> { match match_pair.pattern.kind { PatKind::AscribeUserType { diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index c34105174ef2a..5eb853989d0c1 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::mir::*; 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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>>, From 8c1b72052e3dd85c07b1160ba35501ad4a5b882e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 08:18:57 +0100 Subject: [PATCH 3/5] Unroll --- .../rustc_mir_build/src/build/matches/mod.rs | 26 +++++++++-- .../src/build/matches/simplify.rs | 46 ++++--------------- 2 files changed, 32 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index ae134389b4239..121d88cc8f7a6 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1170,13 +1170,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // be a switch or pattern comparison. let mut split_or_candidate = false; for candidate in &mut *candidates { - split_or_candidate |= self.simplify_candidate( + self.simplify_candidate( &mut candidate.bindings, &mut candidate.ascriptions, &mut candidate.match_pairs, - &mut candidate.subcandidates, - candidate.has_guard, ); + + split_or_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(); + true + } else { + false + } + }; } 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 8e5f5238a651d..b3a2adbc4554c 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -20,42 +20,8 @@ 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), level = "debug")] pub(super) fn simplify_candidate<'pat>( - &mut self, - bindings: &mut Vec>, - ascriptions: &mut Vec>, - match_pairs: &mut Vec>, - subcandidates: &mut Vec>, - has_guard: bool, - ) -> bool { - self.simplify_candidate_inner(bindings, ascriptions, match_pairs); - - if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = - &**match_pairs - { - *subcandidates = self.create_or_subcandidates(place, pats, has_guard); - match_pairs.pop(); - return true; - } - - false - } - - #[instrument(skip(self), level = "debug")] - pub(super) fn simplify_candidate_inner<'pat>( &mut self, candidate_bindings: &mut Vec>, candidate_ascriptions: &mut Vec>, @@ -144,7 +110,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// 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>( + pub(super) fn create_or_subcandidates<'pat>( &mut self, place: &PlaceBuilder<'tcx>, pats: &'pat [Box>], @@ -157,9 +123,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut candidate.bindings, &mut candidate.ascriptions, &mut candidate.match_pairs, - &mut candidate.subcandidates, - candidate.has_guard, ); + + 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() From 65ad1b8cf7ce0f84b09bbdc59540254c2d5c6cdf Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 08:33:02 +0100 Subject: [PATCH 4/5] Eagerly simplify --- .../rustc_mir_build/src/build/matches/mod.rs | 27 +++--- .../src/build/matches/simplify.rs | 33 +++++-- .../rustc_mir_build/src/build/matches/test.rs | 86 +++---------------- .../rustc_mir_build/src/build/matches/util.rs | 2 +- 4 files changed, 53 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 121d88cc8f7a6..4054854204aaa 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -974,9 +974,9 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { 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: vec![MatchPair::new(place, pattern, cx)], @@ -986,7 +986,15 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { otherwise_block: None, pre_binding_block: None, next_candidate_pre_binding_block: None, - } + }; + + cx.simplify_candidate( + &mut candidate.bindings, + &mut candidate.ascriptions, + &mut candidate.match_pairs, + ); + + candidate } /// Visit the leaf candidates (those with no subcandidates) contained in @@ -1042,13 +1050,16 @@ 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. pattern: &'pat Pat<'tcx>, + + /// Precomputed sub-match pairs. + subpairs: Vec, } /// See [`Test`] for more. @@ -1170,12 +1181,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // be a switch or pattern comparison. let mut split_or_candidate = false; for candidate in &mut *candidates { - self.simplify_candidate( - &mut candidate.bindings, - &mut candidate.ascriptions, - &mut candidate.match_pairs, - ); - split_or_candidate |= { if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = &*candidate.match_pairs diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index b3a2adbc4554c..5191a23689206 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -15,6 +15,7 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Ascription, Binding, Candidate, MatchPair}; use crate::build::Builder; +use rustc_middle::mir::PlaceElem; use rustc_middle::thir::{self, *}; use std::mem; @@ -119,12 +120,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pats.iter() .map(|box pat| { let mut candidate = Candidate::new(place.clone(), pat, has_guard, self); - self.simplify_candidate( - &mut candidate.bindings, - &mut candidate.ascriptions, - &mut candidate.match_pairs, - ); - if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = &*candidate.match_pairs { @@ -144,7 +139,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// candidate. fn simplify_match_pair<'pat>( &mut self, - match_pair: MatchPair<'pat, 'tcx>, + mut match_pair: MatchPair<'pat, 'tcx>, bindings: &mut Vec>, ascriptions: &mut Vec>, match_pairs: &mut Vec>, @@ -230,6 +225,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.prefix_slice_suffix(match_pairs, &match_pair.place, prefix, slice, suffix); Ok(()) } else { + self.prefix_slice_suffix( + &mut match_pair.subpairs, + &match_pair.place, + prefix, + slice, + suffix, + ); + self.simplify_candidate(bindings, ascriptions, &mut match_pair.subpairs); Err(match_pair) } } @@ -250,6 +253,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pairs.extend(self.field_match_pairs(place_builder, subpatterns)); Ok(()) } else { + // 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.clone().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) + }); + + match_pair.subpairs.extend(consequent_match_pairs); + self.simplify_candidate(bindings, ascriptions, &mut match_pair.subpairs); Err(match_pair) } } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 990be30b2d68c..12d790ed0c23a 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -595,16 +595,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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, - ); + let match_pair = candidate.match_pairs.remove(match_pair_index); + candidate.match_pairs.extend(match_pair.subpairs); Some(variant_index.as_usize()) } @@ -619,7 +614,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if is_switch_ty(match_pair.pattern.ty) => { let index = options.get_index_of(value).unwrap(); - self.candidate_without_match_pair(match_pair_index, candidate); + candidate.match_pairs.remove(match_pair_index); Some(index) } @@ -645,13 +640,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (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, - ); + let match_pair = candidate.match_pairs.remove(match_pair_index); + candidate.match_pairs.extend(match_pair.subpairs); Some(0) } (Ordering::Less, _) => { @@ -683,13 +673,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (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, - ); + let match_pair = candidate.match_pairs.remove(match_pair_index); + candidate.match_pairs.extend(match_pair.subpairs); Some(0) } (Ordering::Less, _) | (Ordering::Equal, &None) => { @@ -713,7 +698,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (TestKind::Range(test), PatKind::Range(pat)) => { if test == pat { - self.candidate_without_match_pair(match_pair_index, candidate); + candidate.match_pairs.remove(match_pair_index); return Some(0); } @@ -751,7 +736,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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); + candidate.match_pairs.remove(match_pair_index); Some(0) } else { None @@ -760,57 +745,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - 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); - } - fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! { span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern) } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 5eb853989d0c1..a426f2593fa28 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -116,6 +116,6 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { if may_need_cast { place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); } - MatchPair { place, pattern } + MatchPair { place, pattern, subpairs: Vec::new() } } } From b005fea6c061988bdbd34e35a6a2207fc5a2616e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 08:39:43 +0100 Subject: [PATCH 5/5] comment --- compiler/rustc_mir_build/src/build/matches/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 4054854204aaa..ac7f9bfc89891 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -949,12 +949,15 @@ struct Candidate<'pat, 'tcx> { has_guard: bool, /// All of these must be satisfied... + // Invariant: all the `MatchPair`s are recursively simplified. match_pairs: Vec>, /// ...these bindings established... + // Invariant: not mutated during match tree construction. bindings: Vec>, /// ...and these types asserted... + // Invariant: not mutated during match tree construction. ascriptions: Vec>, /// ...and if this is non-empty, one of these subcandidates also has to match... @@ -1056,6 +1059,7 @@ pub(crate) struct MatchPair<'pat, 'tcx> { place: PlaceBuilder<'tcx>, // ... must match this pattern. + // Invariant: this pattern must be simplified, i.e. requires a test. pattern: &'pat Pat<'tcx>, /// Precomputed sub-match pairs.