diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 31591983101..48c3ee1ba0f 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -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>, + + /// Types that must be asserted. + ascriptions: Vec>, +} + +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>, - /// ...these bindings established... - bindings: Vec>, - - /// ...and these types asserted. - ascriptions: Vec>, + 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>, - /// ...these bindings established... - // Invariant: not mutated after candidate creation. - bindings: Vec>, - - /// ...and these types asserted... - // Invariant: not mutated after candidate creation. - ascriptions: Vec>, - /// ...and if this is non-empty, one of these subcandidates also has to match... subcandidates: Vec>, - /// ...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, + /// 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, /// 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>, Vec>)], + 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 diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a3fccb7c319..97b94a0b362 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -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>, - candidate_bindings: &mut Vec>, - candidate_ascriptions: &mut Vec>, + 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); diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 2351f69a914..d0d49c13f13 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -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 {