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:
parent
bafad5a737
commit
e86c82296f
2 changed files with 56 additions and 48 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue