From 7843e46f1793d9712220064c505a0aa8a483cd71 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 9 Mar 2024 01:45:34 +0100 Subject: [PATCH 1/2] Factor out non-branch-related pattern data --- .../rustc_mir_build/src/build/matches/mod.rs | 111 +++++++++--------- .../src/build/matches/simplify.rs | 17 +-- .../rustc_mir_build/src/build/matches/util.rs | 4 +- 3 files changed, 61 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 31591983101f3..cdb82f50b34aa 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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,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)] -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>, +} + +/// 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 +955,38 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { 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, &ll 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 +1005,8 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { 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, @@ -1519,8 +1519,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // FIXME(or_patterns; matthewjasper) Try to be more aggressive here. can_merge &= subcandidate.subcandidates.is_empty() - && subcandidate.bindings.is_empty() - && subcandidate.ascriptions.is_empty(); + && subcandidate.extra_data.bindings.is_empty() + && subcandidate.extra_data.ascriptions.is_empty(); } if can_merge { @@ -1943,7 +1943,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 +1954,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 +1971,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 +2063,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { && 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 +2142,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // // 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 +2170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 a3fccb7c31955..97b94a0b362af 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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 2351f69a9141f..d0d49c13f133d 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 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, '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); } 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>) { - 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 { From 594cf1de61d9cf6e4d095f7d7ab19f8f5999ef72 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 9 Mar 2024 15:28:26 +0100 Subject: [PATCH 2/2] review --- compiler/rustc_mir_build/src/build/matches/mod.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index cdb82f50b34aa..48c3ee1ba0ff3 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -938,6 +938,12 @@ struct PatternExtraData<'tcx> { 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> { @@ -970,7 +976,7 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { #[derive(Debug)] struct Candidate<'pat, 'tcx> { - /// For the candidate to match, &ll 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>, @@ -1518,9 +1524,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.merge_trivial_subcandidates(subcandidate, source_info); // FIXME(or_patterns; matthewjasper) Try to be more aggressive here. - can_merge &= subcandidate.subcandidates.is_empty() - && subcandidate.extra_data.bindings.is_empty() - && subcandidate.extra_data.ascriptions.is_empty(); + can_merge &= + subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty(); } if can_merge {