Rollup merge of #122221 - Nadrieril:patextradata, r=oli-obk
match lowering: define a convenient struct Small refactor PR: `bindings` and `ascriptions` always come together so I made a struct for them. I'll have one or two fields to add to it in a later PR as well.
This commit is contained in:
commit
163573a368
@ -506,13 +506,13 @@ fn bind_pattern(
|
||||
traverse_candidate(
|
||||
candidate,
|
||||
&mut Vec::new(),
|
||||
&mut |leaf_candidate, parent_bindings| {
|
||||
&mut |leaf_candidate, parent_data| {
|
||||
if let Some(arm) = arm {
|
||||
self.clear_top_scope(arm.scope);
|
||||
}
|
||||
let binding_end = self.bind_and_guard_matched_candidate(
|
||||
leaf_candidate,
|
||||
parent_bindings,
|
||||
parent_data,
|
||||
fake_borrow_temps,
|
||||
scrutinee_span,
|
||||
arm_match_scope,
|
||||
@ -524,12 +524,12 @@ fn bind_pattern(
|
||||
}
|
||||
self.cfg.goto(binding_end, outer_source_info, target_block);
|
||||
},
|
||||
|inner_candidate, parent_bindings| {
|
||||
parent_bindings.push((inner_candidate.bindings, inner_candidate.ascriptions));
|
||||
|inner_candidate, parent_data| {
|
||||
parent_data.push(inner_candidate.extra_data);
|
||||
inner_candidate.subcandidates.into_iter()
|
||||
},
|
||||
|parent_bindings| {
|
||||
parent_bindings.pop();
|
||||
|parent_data| {
|
||||
parent_data.pop();
|
||||
},
|
||||
);
|
||||
|
||||
@ -651,7 +651,7 @@ pub(crate) fn place_into_pattern(
|
||||
if set_match_place {
|
||||
let mut next = Some(&candidate);
|
||||
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);
|
||||
// `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
|
||||
@ -924,22 +924,35 @@ pub(super) fn visit_primary_bindings(
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
struct FlatPat<'pat, 'tcx> {
|
||||
struct PatternExtraData<'tcx> {
|
||||
/// [`Span`] of the original pattern.
|
||||
span: Span,
|
||||
|
||||
/// Bindings that must be established.
|
||||
bindings: Vec<Binding<'tcx>>,
|
||||
|
||||
/// Types that must be asserted.
|
||||
ascriptions: Vec<Ascription<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> PatternExtraData<'tcx> {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.bindings.is_empty() && self.ascriptions.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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...
|
||||
// Invariant: all the `MatchPair`s are recursively simplified.
|
||||
// Invariant: or-patterns must be sorted to the end.
|
||||
match_pairs: Vec<MatchPair<'pat, 'tcx>>,
|
||||
|
||||
/// ...these bindings established...
|
||||
bindings: Vec<Binding<'tcx>>,
|
||||
|
||||
/// ...and these types asserted.
|
||||
ascriptions: Vec<Ascription<'tcx>>,
|
||||
extra_data: PatternExtraData<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx, 'pat> FlatPat<'pat, 'tcx> {
|
||||
@ -948,43 +961,38 @@ fn new(
|
||||
pattern: &'pat Pat<'tcx>,
|
||||
cx: &mut Builder<'_, 'tcx>,
|
||||
) -> Self {
|
||||
let mut match_pairs = vec![MatchPair::new(place, pattern, cx)];
|
||||
let mut bindings = Vec::new();
|
||||
let mut ascriptions = Vec::new();
|
||||
|
||||
cx.simplify_match_pairs(&mut match_pairs, &mut bindings, &mut ascriptions);
|
||||
|
||||
FlatPat { span: pattern.span, match_pairs, bindings, ascriptions }
|
||||
let mut flat_pat = FlatPat {
|
||||
match_pairs: vec![MatchPair::new(place, pattern, cx)],
|
||||
extra_data: PatternExtraData {
|
||||
span: pattern.span,
|
||||
bindings: Vec::new(),
|
||||
ascriptions: Vec::new(),
|
||||
},
|
||||
};
|
||||
cx.simplify_match_pairs(&mut flat_pat.match_pairs, &mut flat_pat.extra_data);
|
||||
flat_pat
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Candidate<'pat, 'tcx> {
|
||||
/// [`Span`] of the original pattern that gave rise to this candidate.
|
||||
span: Span,
|
||||
|
||||
/// Whether this `Candidate` has a guard.
|
||||
has_guard: bool,
|
||||
|
||||
/// All of these must be satisfied...
|
||||
/// For the candidate to match, all of these must be satisfied...
|
||||
// Invariant: all the `MatchPair`s are recursively simplified.
|
||||
// Invariant: or-patterns must be sorted at the end.
|
||||
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...
|
||||
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>,
|
||||
|
||||
/// If the candidate matches, bindings and ascriptions must be established.
|
||||
extra_data: PatternExtraData<'tcx>,
|
||||
|
||||
/// The block before the `bindings` have been established.
|
||||
pre_binding_block: Option<BasicBlock>,
|
||||
/// The pre-binding block of the next candidate.
|
||||
@ -1003,10 +1011,8 @@ fn new(
|
||||
|
||||
fn from_flat_pat(flat_pat: FlatPat<'pat, 'tcx>, has_guard: bool) -> Self {
|
||||
Candidate {
|
||||
span: flat_pat.span,
|
||||
match_pairs: flat_pat.match_pairs,
|
||||
bindings: flat_pat.bindings,
|
||||
ascriptions: flat_pat.ascriptions,
|
||||
extra_data: flat_pat.extra_data,
|
||||
has_guard,
|
||||
subcandidates: Vec::new(),
|
||||
otherwise_block: None,
|
||||
@ -1518,9 +1524,8 @@ fn merge_trivial_subcandidates(
|
||||
self.merge_trivial_subcandidates(subcandidate, source_info);
|
||||
|
||||
// FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
|
||||
can_merge &= subcandidate.subcandidates.is_empty()
|
||||
&& subcandidate.bindings.is_empty()
|
||||
&& subcandidate.ascriptions.is_empty();
|
||||
can_merge &=
|
||||
subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty();
|
||||
}
|
||||
|
||||
if can_merge {
|
||||
@ -1943,7 +1948,7 @@ pub(crate) fn lower_let_expr(
|
||||
fn bind_and_guard_matched_candidate<'pat>(
|
||||
&mut self,
|
||||
candidate: Candidate<'pat, 'tcx>,
|
||||
parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)],
|
||||
parent_data: &[PatternExtraData<'tcx>],
|
||||
fake_borrows: &[(Place<'tcx>, Local)],
|
||||
scrutinee_span: Span,
|
||||
arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
|
||||
@ -1954,7 +1959,7 @@ fn bind_and_guard_matched_candidate<'pat>(
|
||||
|
||||
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();
|
||||
|
||||
@ -1971,11 +1976,11 @@ fn bind_and_guard_matched_candidate<'pat>(
|
||||
|
||||
self.ascribe_types(
|
||||
block,
|
||||
parent_bindings
|
||||
parent_data
|
||||
.iter()
|
||||
.flat_map(|(_, ascriptions)| ascriptions)
|
||||
.flat_map(|d| &d.ascriptions)
|
||||
.cloned()
|
||||
.chain(candidate.ascriptions),
|
||||
.chain(candidate.extra_data.ascriptions),
|
||||
);
|
||||
|
||||
// rust-lang/rust#27282: The `autoref` business deserves some
|
||||
@ -2063,10 +2068,8 @@ fn bind_and_guard_matched_candidate<'pat>(
|
||||
&& let Some(guard) = arm.guard
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
let bindings = parent_bindings
|
||||
.iter()
|
||||
.flat_map(|(bindings, _)| bindings)
|
||||
.chain(&candidate.bindings);
|
||||
let bindings =
|
||||
parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings);
|
||||
|
||||
self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone());
|
||||
let guard_frame = GuardFrame {
|
||||
@ -2144,10 +2147,10 @@ fn bind_and_guard_matched_candidate<'pat>(
|
||||
// ```
|
||||
//
|
||||
// and that is clearly not correct.
|
||||
let by_value_bindings = parent_bindings
|
||||
let by_value_bindings = parent_data
|
||||
.iter()
|
||||
.flat_map(|(bindings, _)| bindings)
|
||||
.chain(&candidate.bindings)
|
||||
.flat_map(|d| &d.bindings)
|
||||
.chain(&candidate.extra_data.bindings)
|
||||
.filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue));
|
||||
// Read all of the by reference bindings to ensure that the
|
||||
// place they refer to can't be modified by the guard.
|
||||
@ -2172,10 +2175,7 @@ fn bind_and_guard_matched_candidate<'pat>(
|
||||
self.bind_matched_candidate_for_arm_body(
|
||||
block,
|
||||
schedule_drops,
|
||||
parent_bindings
|
||||
.iter()
|
||||
.flat_map(|(bindings, _)| bindings)
|
||||
.chain(&candidate.bindings),
|
||||
parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings),
|
||||
storages_alive,
|
||||
);
|
||||
block
|
||||
|
@ -12,20 +12,19 @@
|
||||
//! sort of test: for example, testing which variant an enum is, or
|
||||
//! 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 std::mem;
|
||||
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// 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")]
|
||||
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>>,
|
||||
extra_data: &mut PatternExtraData<'tcx>,
|
||||
) {
|
||||
// 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):
|
||||
@ -45,17 +44,13 @@ pub(super) fn simplify_match_pairs<'pat>(
|
||||
// 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.
|
||||
for mut match_pair in mem::take(match_pairs) {
|
||||
self.simplify_match_pairs(
|
||||
&mut match_pair.subpairs,
|
||||
candidate_bindings,
|
||||
candidate_ascriptions,
|
||||
);
|
||||
self.simplify_match_pairs(&mut match_pair.subpairs, extra_data);
|
||||
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
|
||||
if let Some(binding) = binding {
|
||||
candidate_bindings.push(binding);
|
||||
extra_data.bindings.push(binding);
|
||||
}
|
||||
if let Some(ascription) = ascription {
|
||||
candidate_ascriptions.push(ascription);
|
||||
extra_data.ascriptions.push(ascription);
|
||||
}
|
||||
// Simplifiable pattern; we replace it with its already simplified subpairs.
|
||||
match_pairs.append(&mut match_pair.subpairs);
|
||||
|
@ -280,7 +280,7 @@ pub(super) fn collect_fake_borrows(
|
||||
}
|
||||
|
||||
fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) {
|
||||
for binding in &candidate.bindings {
|
||||
for binding in &candidate.extra_data.bindings {
|
||||
self.visit_binding(binding);
|
||||
}
|
||||
for match_pair in &candidate.match_pairs {
|
||||
@ -289,7 +289,7 @@ fn visit_candidate(&mut self, candidate: &Candidate<'_, '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);
|
||||
}
|
||||
for match_pair in &flat_pat.match_pairs {
|
||||
|
Loading…
Reference in New Issue
Block a user