1
Fork 0

Make simplify_candidate more general

Because we will soon need to apply it to match pairs that aren't
directly in a candidate.
This commit is contained in:
Nadrieril 2024-01-21 21:38:24 +01:00
parent bafad5a737
commit e86c82296f
2 changed files with 56 additions and 48 deletions

View file

@ -1168,7 +1168,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// be a switch or pattern comparison. // be a switch or pattern comparison.
let mut split_or_candidate = false; let mut split_or_candidate = false;
for candidate in &mut *candidates { 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, .. }] = if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] =
&*candidate.match_pairs &*candidate.match_pairs
{ {
@ -1181,7 +1185,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// } // }
// //
// only generates a single switch. // 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(); candidate.match_pairs.pop();
split_or_candidate = true; split_or_candidate = true;
} }

View file

@ -6,7 +6,7 @@
//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]` //! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
//! - `place @ x` can be simplified to `[]` by binding `x` to `place` //! - `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 //! sort of simplifications until there is nothing left to
//! simplify. Match pairs cannot be simplified if they require some //! simplify. Match pairs cannot be simplified if they require some
//! sort of test: for example, testing which variant an enum is, or //! sort of test: for example, testing which variant an enum is, or
@ -22,10 +22,15 @@ use rustc_middle::ty;
use std::mem; use std::mem;
impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Simplify a candidate so that all match pairs require a test. /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and
#[instrument(skip(self, candidate), level = "debug")] /// ascriptions in the provided `Vec`s.
pub(super) fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) { #[instrument(skip(self), level = "debug")]
debug!("{candidate:#?}"); pub(super) fn simplify_match_pairs<'pat>(
&mut self,
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
candidate_bindings: &mut Vec<Binding<'tcx>>,
candidate_ascriptions: &mut Vec<Ascription<'tcx>>,
) {
// In order to please the borrow checker, in a pattern like `x @ pat` we must lower the // 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): // bindings in `pat` before `x`. E.g. (#69971):
// //
@ -53,25 +58,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// bindings in iter 2: [6, 7] // bindings in iter 2: [6, 7]
// //
// final bindings: [6, 7, 4, 5, 1, 2, 3] // 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 // Repeatedly simplify match pairs until fixed point is reached
loop { loop {
let mut changed = false; let mut changed = false;
for match_pair in mem::take(&mut candidate.match_pairs) { for match_pair in mem::take(match_pairs) {
match self.simplify_match_pair(match_pair, candidate) { match self.simplify_match_pair(
match_pair,
candidate_bindings,
candidate_ascriptions,
match_pairs,
) {
Ok(()) => { Ok(()) => {
changed = true; changed = true;
} }
Err(match_pair) => { Err(match_pair) => {
candidate.match_pairs.push(match_pair); match_pairs.push(match_pair);
} }
} }
} }
// This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings // This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings
candidate.bindings.extend_from_slice(&accumulated_bindings); candidate_bindings.extend_from_slice(&accumulated_bindings);
mem::swap(&mut candidate.bindings, &mut accumulated_bindings); mem::swap(candidate_bindings, &mut accumulated_bindings);
candidate.bindings.clear(); candidate_bindings.clear();
if !changed { if !changed {
// If we were not able to simplify anymore, done. // 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`. // Store computed bindings back in `candidate_bindings`.
mem::swap(&mut candidate.bindings, &mut accumulated_bindings); mem::swap(candidate_bindings, &mut accumulated_bindings);
// Move or-patterns to the end, because they can result in us // Move or-patterns to the end, because they can result in us
// creating additional candidates, so we want to test them as // creating additional candidates, so we want to test them as
// late as possible. // late as possible.
candidate.match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
debug!(simplified = ?candidate, "simplify_candidate"); debug!(simplified = ?match_pairs, "simplify_match_pairs");
} }
/// Given `candidate` that has a single or-pattern for its 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`. /// `pats`.
pub(super) fn create_or_subcandidates<'pat>( pub(super) fn create_or_subcandidates<'pat>(
&mut self, &mut self,
candidate: &Candidate<'pat, 'tcx>,
place: &PlaceBuilder<'tcx>, place: &PlaceBuilder<'tcx>,
pats: &'pat [Box<Pat<'tcx>>], pats: &'pat [Box<Pat<'tcx>>],
has_guard: bool,
) -> Vec<Candidate<'pat, 'tcx>> { ) -> Vec<Candidate<'pat, 'tcx>> {
pats.iter() pats.iter()
.map(|box pat| { .map(|box pat| {
let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard, self); let mut candidate = Candidate::new(place.clone(), pat, has_guard, self);
self.simplify_candidate(&mut 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, .. }] = if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] =
&*candidate.match_pairs &*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.match_pairs.pop();
} }
candidate candidate
@ -122,7 +137,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn simplify_match_pair<'pat>( fn simplify_match_pair<'pat>(
&mut self, &mut self,
match_pair: MatchPair<'pat, 'tcx>, match_pair: MatchPair<'pat, 'tcx>,
candidate: &mut Candidate<'pat, 'tcx>, bindings: &mut Vec<Binding<'tcx>>,
ascriptions: &mut Vec<Ascription<'tcx>>,
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
) -> Result<(), MatchPair<'pat, 'tcx>> { ) -> Result<(), MatchPair<'pat, 'tcx>> {
match match_pair.pattern.kind { match match_pair.pattern.kind {
PatKind::AscribeUserType { PatKind::AscribeUserType {
@ -131,14 +148,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} => { } => {
// Apply the type ascription to the value at `match_pair.place` // Apply the type ascription to the value at `match_pair.place`
if let Some(source) = match_pair.place.try_to_place(self) { if let Some(source) = match_pair.place.try_to_place(self) {
candidate.ascriptions.push(Ascription { ascriptions.push(Ascription {
annotation: annotation.clone(), annotation: annotation.clone(),
source, source,
variance, variance,
}); });
} }
candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self)); match_pairs.push(MatchPair::new(match_pair.place, subpattern, self));
Ok(()) Ok(())
} }
@ -158,7 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
is_primary: _, is_primary: _,
} => { } => {
if let Some(source) = match_pair.place.try_to_place(self) { if let Some(source) = match_pair.place.try_to_place(self) {
candidate.bindings.push(Binding { bindings.push(Binding {
span: match_pair.pattern.span, span: match_pair.pattern.span,
source, source,
var_id: var, var_id: var,
@ -168,7 +185,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if let Some(subpattern) = subpattern.as_ref() { if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now // 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(()) Ok(())
@ -211,13 +228,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span, span,
user_ty: Box::new(user_ty), user_ty: Box::new(user_ty),
}; };
candidate.ascriptions.push(Ascription { ascriptions.push(Ascription {
annotation, annotation,
source, source,
variance: ty::Contravariant, 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(()) Ok(())
} }
@ -233,13 +250,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatKind::Slice { ref prefix, ref slice, ref suffix } => { PatKind::Slice { ref prefix, ref slice, ref suffix } => {
if prefix.is_empty() && slice.is_some() && suffix.is_empty() { if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
// irrefutable // irrefutable
self.prefix_slice_suffix( self.prefix_slice_suffix(match_pairs, &match_pair.place, prefix, slice, suffix);
&mut candidate.match_pairs,
&match_pair.place,
prefix,
slice,
suffix,
);
Ok(()) Ok(())
} else { } else {
Err(match_pair) Err(match_pair)
@ -260,9 +271,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|| !adt_def.is_variant_list_non_exhaustive()); || !adt_def.is_variant_list_non_exhaustive());
if irrefutable { if irrefutable {
let place_builder = match_pair.place.downcast(adt_def, variant_index); 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(()) Ok(())
} else { } else {
Err(match_pair) Err(match_pair)
@ -270,25 +279,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
PatKind::Array { ref prefix, ref slice, ref suffix } => { PatKind::Array { ref prefix, ref slice, ref suffix } => {
self.prefix_slice_suffix( self.prefix_slice_suffix(match_pairs, &match_pair.place, prefix, slice, suffix);
&mut candidate.match_pairs,
&match_pair.place,
prefix,
slice,
suffix,
);
Ok(()) Ok(())
} }
PatKind::Leaf { ref subpatterns } => { PatKind::Leaf { ref subpatterns } => {
// tuple struct, match subpats (if any) // 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(()) Ok(())
} }
PatKind::Deref { ref subpattern } => { PatKind::Deref { ref subpattern } => {
let place_builder = match_pair.place.deref(); 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(()) Ok(())
} }