1
Fork 0

Factor out non-branch-related pattern data

This commit is contained in:
Nadrieril 2024-03-09 01:45:34 +01:00
parent 42825768b1
commit 7843e46f17
3 changed files with 61 additions and 71 deletions

View file

@ -506,13 +506,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
traverse_candidate( traverse_candidate(
candidate, candidate,
&mut Vec::new(), &mut Vec::new(),
&mut |leaf_candidate, parent_bindings| { &mut |leaf_candidate, parent_data| {
if let Some(arm) = arm { if let Some(arm) = arm {
self.clear_top_scope(arm.scope); self.clear_top_scope(arm.scope);
} }
let binding_end = self.bind_and_guard_matched_candidate( let binding_end = self.bind_and_guard_matched_candidate(
leaf_candidate, leaf_candidate,
parent_bindings, parent_data,
fake_borrow_temps, fake_borrow_temps,
scrutinee_span, scrutinee_span,
arm_match_scope, arm_match_scope,
@ -524,12 +524,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
self.cfg.goto(binding_end, outer_source_info, target_block); self.cfg.goto(binding_end, outer_source_info, target_block);
}, },
|inner_candidate, parent_bindings| { |inner_candidate, parent_data| {
parent_bindings.push((inner_candidate.bindings, inner_candidate.ascriptions)); parent_data.push(inner_candidate.extra_data);
inner_candidate.subcandidates.into_iter() inner_candidate.subcandidates.into_iter()
}, },
|parent_bindings| { |parent_data| {
parent_bindings.pop(); parent_data.pop();
}, },
); );
@ -651,7 +651,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if set_match_place { if set_match_place {
let mut next = Some(&candidate); let mut next = Some(&candidate);
while let Some(candidate_ref) = next.take() { while let Some(candidate_ref) = next.take() {
for binding in &candidate_ref.bindings { for binding in &candidate_ref.extra_data.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard); let local = self.var_local_id(binding.var_id, OutsideGuard);
// `try_to_place` may fail if it is unable to resolve the given // `try_to_place` may fail if it is unable to resolve the given
// `PlaceBuilder` inside a closure. In this case, we don't want to include // `PlaceBuilder` inside a closure. In this case, we don't want to include
@ -924,22 +924,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
} }
/// A pattern in a form suitable for generating code. /// Data extracted from a pattern that doesn't affect which branch is taken. Collected during
/// pattern simplification and not mutated later.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct FlatPat<'pat, 'tcx> { struct PatternExtraData<'tcx> {
/// [`Span`] of the original pattern. /// [`Span`] of the original pattern.
span: Span, span: Span,
/// Bindings that must be established.
bindings: Vec<Binding<'tcx>>,
/// Types that must be asserted.
ascriptions: Vec<Ascription<'tcx>>,
}
/// A pattern in a form suitable for generating code.
#[derive(Debug, Clone)]
struct FlatPat<'pat, 'tcx> {
/// To match the pattern, all of these must be satisfied... /// To match the pattern, all of these must be satisfied...
// Invariant: all the `MatchPair`s are recursively simplified. // Invariant: all the `MatchPair`s are recursively simplified.
// Invariant: or-patterns must be sorted to the end. // Invariant: or-patterns must be sorted to the end.
match_pairs: Vec<MatchPair<'pat, 'tcx>>, match_pairs: Vec<MatchPair<'pat, 'tcx>>,
/// ...these bindings established... extra_data: PatternExtraData<'tcx>,
bindings: Vec<Binding<'tcx>>,
/// ...and these types asserted.
ascriptions: Vec<Ascription<'tcx>>,
} }
impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { impl<'tcx, 'pat> FlatPat<'pat, 'tcx> {
@ -948,43 +955,38 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> {
pattern: &'pat Pat<'tcx>, pattern: &'pat Pat<'tcx>,
cx: &mut Builder<'_, 'tcx>, cx: &mut Builder<'_, 'tcx>,
) -> Self { ) -> Self {
let mut match_pairs = vec![MatchPair::new(place, pattern, cx)]; let mut flat_pat = FlatPat {
let mut bindings = Vec::new(); match_pairs: vec![MatchPair::new(place, pattern, cx)],
let mut ascriptions = Vec::new(); extra_data: PatternExtraData {
span: pattern.span,
cx.simplify_match_pairs(&mut match_pairs, &mut bindings, &mut ascriptions); bindings: Vec::new(),
ascriptions: Vec::new(),
FlatPat { span: pattern.span, match_pairs, bindings, ascriptions } },
};
cx.simplify_match_pairs(&mut flat_pat.match_pairs, &mut flat_pat.extra_data);
flat_pat
} }
} }
#[derive(Debug)] #[derive(Debug)]
struct Candidate<'pat, 'tcx> { struct Candidate<'pat, 'tcx> {
/// [`Span`] of the original pattern that gave rise to this candidate. /// For the candidate to match, &ll of these must be satisfied...
span: Span,
/// Whether this `Candidate` has a guard.
has_guard: bool,
/// All of these must be satisfied...
// Invariant: all the `MatchPair`s are recursively simplified. // Invariant: all the `MatchPair`s are recursively simplified.
// Invariant: or-patterns must be sorted at the end. // Invariant: or-patterns must be sorted at the end.
match_pairs: Vec<MatchPair<'pat, 'tcx>>, match_pairs: Vec<MatchPair<'pat, 'tcx>>,
/// ...these bindings established...
// Invariant: not mutated after candidate creation.
bindings: Vec<Binding<'tcx>>,
/// ...and these types asserted...
// Invariant: not mutated after candidate creation.
ascriptions: Vec<Ascription<'tcx>>,
/// ...and if this is non-empty, one of these subcandidates also has to match... /// ...and if this is non-empty, one of these subcandidates also has to match...
subcandidates: Vec<Candidate<'pat, 'tcx>>, subcandidates: Vec<Candidate<'pat, 'tcx>>,
/// ...and the guard must be evaluated; if it's `false` then branch to `otherwise_block`. /// ...and the guard must be evaluated if there is one.
has_guard: bool,
/// If the guard is `false` then branch to `otherwise_block`.
otherwise_block: Option<BasicBlock>, otherwise_block: Option<BasicBlock>,
/// If the candidate matches, bindings and ascriptions must be established.
extra_data: PatternExtraData<'tcx>,
/// The block before the `bindings` have been established. /// The block before the `bindings` have been established.
pre_binding_block: Option<BasicBlock>, pre_binding_block: Option<BasicBlock>,
/// The pre-binding block of the next candidate. /// The pre-binding block of the next candidate.
@ -1003,10 +1005,8 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
fn from_flat_pat(flat_pat: FlatPat<'pat, 'tcx>, has_guard: bool) -> Self { fn from_flat_pat(flat_pat: FlatPat<'pat, 'tcx>, has_guard: bool) -> Self {
Candidate { Candidate {
span: flat_pat.span,
match_pairs: flat_pat.match_pairs, match_pairs: flat_pat.match_pairs,
bindings: flat_pat.bindings, extra_data: flat_pat.extra_data,
ascriptions: flat_pat.ascriptions,
has_guard, has_guard,
subcandidates: Vec::new(), subcandidates: Vec::new(),
otherwise_block: None, otherwise_block: None,
@ -1519,8 +1519,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// FIXME(or_patterns; matthewjasper) Try to be more aggressive here. // FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
can_merge &= subcandidate.subcandidates.is_empty() can_merge &= subcandidate.subcandidates.is_empty()
&& subcandidate.bindings.is_empty() && subcandidate.extra_data.bindings.is_empty()
&& subcandidate.ascriptions.is_empty(); && subcandidate.extra_data.ascriptions.is_empty();
} }
if can_merge { if can_merge {
@ -1943,7 +1943,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn bind_and_guard_matched_candidate<'pat>( fn bind_and_guard_matched_candidate<'pat>(
&mut self, &mut self,
candidate: Candidate<'pat, 'tcx>, candidate: Candidate<'pat, 'tcx>,
parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)], parent_data: &[PatternExtraData<'tcx>],
fake_borrows: &[(Place<'tcx>, Local)], fake_borrows: &[(Place<'tcx>, Local)],
scrutinee_span: Span, scrutinee_span: Span,
arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
@ -1954,7 +1954,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug_assert!(candidate.match_pairs.is_empty()); debug_assert!(candidate.match_pairs.is_empty());
let candidate_source_info = self.source_info(candidate.span); let candidate_source_info = self.source_info(candidate.extra_data.span);
let mut block = candidate.pre_binding_block.unwrap(); let mut block = candidate.pre_binding_block.unwrap();
@ -1971,11 +1971,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.ascribe_types( self.ascribe_types(
block, block,
parent_bindings parent_data
.iter() .iter()
.flat_map(|(_, ascriptions)| ascriptions) .flat_map(|d| &d.ascriptions)
.cloned() .cloned()
.chain(candidate.ascriptions), .chain(candidate.extra_data.ascriptions),
); );
// rust-lang/rust#27282: The `autoref` business deserves some // rust-lang/rust#27282: The `autoref` business deserves some
@ -2063,10 +2063,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&& let Some(guard) = arm.guard && let Some(guard) = arm.guard
{ {
let tcx = self.tcx; let tcx = self.tcx;
let bindings = parent_bindings let bindings =
.iter() parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings);
.flat_map(|(bindings, _)| bindings)
.chain(&candidate.bindings);
self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone()); self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone());
let guard_frame = GuardFrame { let guard_frame = GuardFrame {
@ -2144,10 +2142,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// ``` // ```
// //
// and that is clearly not correct. // and that is clearly not correct.
let by_value_bindings = parent_bindings let by_value_bindings = parent_data
.iter() .iter()
.flat_map(|(bindings, _)| bindings) .flat_map(|d| &d.bindings)
.chain(&candidate.bindings) .chain(&candidate.extra_data.bindings)
.filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue)); .filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue));
// Read all of the by reference bindings to ensure that the // Read all of the by reference bindings to ensure that the
// place they refer to can't be modified by the guard. // place they refer to can't be modified by the guard.
@ -2172,10 +2170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.bind_matched_candidate_for_arm_body( self.bind_matched_candidate_for_arm_body(
block, block,
schedule_drops, schedule_drops,
parent_bindings parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings),
.iter()
.flat_map(|(bindings, _)| bindings)
.chain(&candidate.bindings),
storages_alive, storages_alive,
); );
block block

View file

@ -12,20 +12,19 @@
//! sort of test: for example, testing which variant an enum is, or //! sort of test: for example, testing which variant an enum is, or
//! testing a value against a constant. //! testing a value against a constant.
use crate::build::matches::{Ascription, Binding, Candidate, FlatPat, MatchPair, TestCase}; use crate::build::matches::{Candidate, FlatPat, MatchPair, PatternExtraData, TestCase};
use crate::build::Builder; use crate::build::Builder;
use std::mem; use std::mem;
impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Simplify a list of match pairs so they all require a test. Stores relevant bindings and /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and
/// ascriptions in the provided `Vec`s. /// ascriptions in `extra_data`.
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub(super) fn simplify_match_pairs<'pat>( pub(super) fn simplify_match_pairs<'pat>(
&mut self, &mut self,
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>, match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
candidate_bindings: &mut Vec<Binding<'tcx>>, extra_data: &mut PatternExtraData<'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):
@ -45,17 +44,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// after any bindings in `pat`. This doesn't work for or-patterns: the current structure of // after any bindings in `pat`. This doesn't work for or-patterns: the current structure of
// match lowering forces us to lower bindings inside or-patterns last. // match lowering forces us to lower bindings inside or-patterns last.
for mut match_pair in mem::take(match_pairs) { for mut match_pair in mem::take(match_pairs) {
self.simplify_match_pairs( self.simplify_match_pairs(&mut match_pair.subpairs, extra_data);
&mut match_pair.subpairs,
candidate_bindings,
candidate_ascriptions,
);
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case { if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
if let Some(binding) = binding { if let Some(binding) = binding {
candidate_bindings.push(binding); extra_data.bindings.push(binding);
} }
if let Some(ascription) = ascription { if let Some(ascription) = ascription {
candidate_ascriptions.push(ascription); extra_data.ascriptions.push(ascription);
} }
// Simplifiable pattern; we replace it with its already simplified subpairs. // Simplifiable pattern; we replace it with its already simplified subpairs.
match_pairs.append(&mut match_pair.subpairs); match_pairs.append(&mut match_pair.subpairs);

View file

@ -280,7 +280,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
} }
fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) { fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) {
for binding in &candidate.bindings { for binding in &candidate.extra_data.bindings {
self.visit_binding(binding); self.visit_binding(binding);
} }
for match_pair in &candidate.match_pairs { for match_pair in &candidate.match_pairs {
@ -289,7 +289,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
} }
fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) { fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) {
for binding in &flat_pat.bindings { for binding in &flat_pat.extra_data.bindings {
self.visit_binding(binding); self.visit_binding(binding);
} }
for match_pair in &flat_pat.match_pairs { for match_pair in &flat_pat.match_pairs {