From e86c82296f26454d7451d64586062b59c9b62d22 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 21:38:24 +0100 Subject: [PATCH] Make `simplify_candidate` more general Because we will soon need to apply it to match pairs that aren't directly in a candidate. --- .../rustc_mir_build/src/build/matches/mod.rs | 9 +- .../src/build/matches/simplify.rs | 95 ++++++++++--------- 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index b35a0c3c671..bb307089f1c 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1168,7 +1168,11 @@ 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(candidate); + self.simplify_match_pairs( + &mut candidate.match_pairs, + &mut candidate.bindings, + &mut candidate.ascriptions, + ); if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = &*candidate.match_pairs { @@ -1181,7 +1185,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // } // // only generates a single switch. - candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats); + candidate.subcandidates = + self.create_or_subcandidates(place, pats, candidate.has_guard); candidate.match_pairs.pop(); split_or_candidate = true; } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a74b664441a..040d38c109b 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,10 +22,15 @@ use rustc_middle::ty; use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { - /// Simplify a candidate so that all match pairs require a test. - #[instrument(skip(self, candidate), level = "debug")] - pub(super) fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) { - debug!("{candidate:#?}"); + /// 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, + 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): // @@ -53,25 +58,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // bindings in iter 2: [6, 7] // // final bindings: [6, 7, 4, 5, 1, 2, 3] - let mut accumulated_bindings = mem::take(&mut candidate.bindings); + let mut accumulated_bindings = mem::take(candidate_bindings); // Repeatedly simplify match pairs until fixed point is reached loop { let mut changed = false; - for match_pair in mem::take(&mut candidate.match_pairs) { - match self.simplify_match_pair(match_pair, candidate) { + for match_pair in mem::take(match_pairs) { + match self.simplify_match_pair( + match_pair, + candidate_bindings, + candidate_ascriptions, + match_pairs, + ) { Ok(()) => { changed = true; } Err(match_pair) => { - candidate.match_pairs.push(match_pair); + 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. @@ -79,14 +89,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - // Store computed bindings back in `candidate`. - mem::swap(&mut candidate.bindings, &mut accumulated_bindings); + // Store computed bindings back in `candidate_bindings`. + mem::swap(candidate_bindings, &mut accumulated_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.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); - debug!(simplified = ?candidate, "simplify_candidate"); + 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, @@ -94,19 +104,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// `pats`. 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); + self.simplify_match_pairs( + &mut candidate.match_pairs, + &mut candidate.bindings, + &mut candidate.ascriptions, + ); if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] = &*candidate.match_pairs { - candidate.subcandidates = self.create_or_subcandidates(&candidate, place, pats); + candidate.subcandidates = + self.create_or_subcandidates(place, pats, candidate.has_guard); candidate.match_pairs.pop(); } candidate @@ -122,7 +137,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 Vec>, ) -> Result<(), MatchPair<'pat, 'tcx>> { match match_pair.pattern.kind { PatKind::AscribeUserType { @@ -131,14 +148,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { // 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)); + match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); Ok(()) } @@ -158,7 +175,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, @@ -168,7 +185,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(()) @@ -211,13 +228,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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)); + match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); Ok(()) } @@ -233,13 +250,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) @@ -260,9 +271,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) @@ -270,25 +279,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(()) }