Factor out non-branch-related pattern data
This commit is contained in:
parent
42825768b1
commit
7843e46f17
3 changed files with 61 additions and 71 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue