diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 10b43390eb288..c6f3e22e95f6f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -6,27 +6,25 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; -use crate::builder::matches::{FlatPat, MatchPairTree, TestCase}; +use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase}; impl<'a, 'tcx> Builder<'a, 'tcx> { - /// Builds and returns [`MatchPairTree`] subtrees, one for each pattern in + /// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in /// `subpatterns`, representing the fields of a [`PatKind::Variant`] or /// [`PatKind::Leaf`]. /// /// Used internally by [`MatchPairTree::for_pattern`]. fn field_match_pairs( &mut self, + match_pairs: &mut Vec>, + extra_data: &mut PatternExtraData<'tcx>, place: PlaceBuilder<'tcx>, subpatterns: &[FieldPat<'tcx>], - ) -> Vec> { - subpatterns - .iter() - .map(|fieldpat| { - let place = - place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); - MatchPairTree::for_pattern(place, &fieldpat.pattern, self) - }) - .collect() + ) { + for fieldpat in subpatterns { + let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); + MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data); + } } /// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an @@ -36,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn prefix_slice_suffix( &mut self, match_pairs: &mut Vec>, + extra_data: &mut PatternExtraData<'tcx>, place: &PlaceBuilder<'tcx>, prefix: &[Pat<'tcx>], opt_slice: &Option>>, @@ -56,11 +55,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ((prefix.len() + suffix.len()).try_into().unwrap(), false) }; - match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { + for (idx, subpattern) in prefix.iter().enumerate() { let elem = ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; - MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self) - })); + let place = place.clone_project(elem); + MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + } if let Some(subslice_pat) = opt_slice { let suffix_len = suffix.len() as u64; @@ -69,10 +69,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { to: if exact_size { min_length - suffix_len } else { suffix_len }, from_end: !exact_size, }); - match_pairs.push(MatchPairTree::for_pattern(subslice, subslice_pat, self)); + MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data); } - match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { + for (idx, subpattern) in suffix.iter().rev().enumerate() { let end_offset = (idx + 1) as u64; let elem = ProjectionElem::ConstantIndex { offset: if exact_size { min_length - end_offset } else { end_offset }, @@ -80,19 +80,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { from_end: !exact_size, }; let place = place.clone_project(elem); - MatchPairTree::for_pattern(place, subpattern, self) - })); + MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + } } } impl<'tcx> MatchPairTree<'tcx> { /// Recursively builds a match pair tree for the given pattern and its /// subpatterns. - pub(in crate::builder) fn for_pattern( + pub(super) fn for_pattern( mut place_builder: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>, - ) -> MatchPairTree<'tcx> { + match_pairs: &mut Vec, // Newly-created nodes are added to this vector + extra_data: &mut PatternExtraData<'tcx>, // Bindings/ascriptions are added here + ) { // Force the place type to the pattern's type. // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? if let Some(resolved) = place_builder.resolve_upvar(cx) { @@ -113,64 +115,102 @@ impl<'tcx> MatchPairTree<'tcx> { place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); } + // Place can be none if the pattern refers to a non-captured place in a closure. let place = place_builder.try_to_place(cx); - let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; let mut subpairs = Vec::new(); let test_case = match pattern.kind { - PatKind::Wild | PatKind::Error(_) => default_irrefutable(), + PatKind::Wild | PatKind::Error(_) => None, - PatKind::Or { ref pats } => TestCase::Or { + PatKind::Or { ref pats } => Some(TestCase::Or { pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), - }, + }), PatKind::Range(ref range) => { if range.is_full_range(cx.tcx) == Some(true) { - default_irrefutable() + None } else { - TestCase::Range(Arc::clone(range)) + Some(TestCase::Range(Arc::clone(range))) } } - PatKind::Constant { value } => TestCase::Constant { value }, + PatKind::Constant { value } => Some(TestCase::Constant { value }), PatKind::AscribeUserType { ascription: Ascription { ref annotation, variance }, ref subpattern, .. } => { + MatchPairTree::for_pattern( + place_builder, + subpattern, + cx, + &mut subpairs, + extra_data, + ); + // Apply the type ascription to the value at `match_pair.place` - let ascription = place.map(|source| super::Ascription { - annotation: annotation.clone(), - source, - variance, - }); - - subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx)); - TestCase::Irrefutable { ascription, binding: None } + if let Some(source) = place { + let annotation = annotation.clone(); + extra_data.ascriptions.push(super::Ascription { source, annotation, variance }); + } + + None } PatKind::Binding { mode, var, ref subpattern, .. } => { - let binding = place.map(|source| super::Binding { - span: pattern.span, - source, - var_id: var, - binding_mode: mode, - }); + // In order to please the borrow checker, when lowering a pattern + // like `x @ subpat` we must establish any bindings in `subpat` + // before establishing the binding for `x`. + // + // For example (from #69971): + // + // ```ignore (illustrative) + // struct NonCopyStruct { + // copy_field: u32, + // } + // + // fn foo1(x: NonCopyStruct) { + // let y @ NonCopyStruct { copy_field: z } = x; + // // the above should turn into + // let z = x.copy_field; + // let y = x; + // } + // ``` + // First, recurse into the subpattern, if any. if let Some(subpattern) = subpattern.as_ref() { // this is the `x @ P` case; have to keep matching against `P` now - subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx)); + MatchPairTree::for_pattern( + place_builder, + subpattern, + cx, + &mut subpairs, + extra_data, + ); } - TestCase::Irrefutable { ascription: None, binding } + + // Then push this binding, after any bindings in the subpattern. + if let Some(source) = place { + extra_data.bindings.push(super::Binding { + span: pattern.span, + source, + var_id: var, + binding_mode: mode, + }); + } + + None } PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => { - subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx)); - default_irrefutable() + MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data); + None } PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => { + MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data); + // Apply a type ascription for the inline constant to the value at `match_pair.place` - let ascription = place.map(|source| { + if let Some(source) = place { let span = pattern.span; let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); let args = ty::InlineConstArgs::new( @@ -189,33 +229,47 @@ impl<'tcx> MatchPairTree<'tcx> { span, user_ty: Box::new(user_ty), }; - super::Ascription { annotation, source, variance: ty::Contravariant } - }); + let variance = ty::Contravariant; + extra_data.ascriptions.push(super::Ascription { annotation, source, variance }); + } - subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx)); - TestCase::Irrefutable { ascription, binding: None } + None } PatKind::Array { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); - default_irrefutable() + cx.prefix_slice_suffix( + &mut subpairs, + extra_data, + &place_builder, + prefix, + slice, + suffix, + ); + None } PatKind::Slice { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); + cx.prefix_slice_suffix( + &mut subpairs, + extra_data, + &place_builder, + prefix, + slice, + suffix, + ); if prefix.is_empty() && slice.is_some() && suffix.is_empty() { - default_irrefutable() + None } else { - TestCase::Slice { + Some(TestCase::Slice { len: prefix.len() + suffix.len(), variable_length: slice.is_some(), - } + }) } } PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` - subpairs = cx.field_match_pairs(downcast_place, subpatterns); + cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns); let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { i == variant_index @@ -225,21 +279,23 @@ impl<'tcx> MatchPairTree<'tcx> { .apply_ignore_module(cx.tcx, cx.infcx.typing_env(cx.param_env)) }) && (adt_def.did().is_local() || !adt_def.is_variant_list_non_exhaustive()); - if irrefutable { - default_irrefutable() - } else { - TestCase::Variant { adt_def, variant_index } - } + if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) } } PatKind::Leaf { ref subpatterns } => { - subpairs = cx.field_match_pairs(place_builder, subpatterns); - default_irrefutable() + cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns); + None } PatKind::Deref { ref subpattern } => { - subpairs.push(MatchPairTree::for_pattern(place_builder.deref(), subpattern, cx)); - default_irrefutable() + MatchPairTree::for_pattern( + place_builder.deref(), + subpattern, + cx, + &mut subpairs, + extra_data, + ); + None } PatKind::DerefPattern { ref subpattern, mutability } => { @@ -249,23 +305,32 @@ impl<'tcx> MatchPairTree<'tcx> { Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), pattern.span, ); - subpairs.push(MatchPairTree::for_pattern( + MatchPairTree::for_pattern( PlaceBuilder::from(temp).deref(), subpattern, cx, - )); - TestCase::Deref { temp, mutability } + &mut subpairs, + extra_data, + ); + Some(TestCase::Deref { temp, mutability }) } - PatKind::Never => TestCase::Never, + PatKind::Never => Some(TestCase::Never), }; - MatchPairTree { - place, - test_case, - subpairs, - pattern_ty: pattern.ty, - pattern_span: pattern.span, + if let Some(test_case) = test_case { + // This pattern is refutable, so push a new match-pair node. + match_pairs.push(MatchPairTree { + place: place.expect("refutable patterns should always have a place to inspect"), + test_case, + subpairs, + pattern_ty: pattern.ty, + pattern_span: pattern.span, + }) + } else { + // This pattern is irrefutable, so it doesn't need its own match-pair node. + // Just push its refutable subpatterns instead, if any. + match_pairs.extend(subpairs); } } } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index d05d5b151ff48..b05052a3455ea 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -26,7 +26,6 @@ use crate::builder::{ // helper functions, broken out by category: mod match_pair; -mod simplify; mod test; mod util; @@ -987,18 +986,16 @@ impl<'tcx> PatternExtraData<'tcx> { } /// A pattern in a form suitable for lowering the match tree, with all irrefutable -/// patterns simplified away, and or-patterns sorted to the end. +/// patterns simplified away. /// -/// Here, "flat" indicates that the pattern's match pairs have been recursively -/// simplified by [`Builder::simplify_match_pairs`]. They are not necessarily -/// flat in an absolute sense. +/// Here, "flat" indicates that irrefutable nodes in the pattern tree have been +/// recursively replaced with their refutable subpatterns. They are not +/// necessarily flat in an absolute sense. /// /// Will typically be incorporated into a [`Candidate`]. #[derive(Debug, Clone)] struct FlatPat<'tcx> { /// To match the pattern, all of these must be satisfied... - // Invariant: all the match pairs are recursively simplified. - // Invariant: or-patterns must be sorted to the end. match_pairs: Vec>, extra_data: PatternExtraData<'tcx>, @@ -1008,17 +1005,15 @@ impl<'tcx> FlatPat<'tcx> { /// Creates a `FlatPat` containing a simplified [`MatchPairTree`] list/forest /// for the given pattern. fn new(place: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>) -> Self { - // First, recursively build a tree of match pairs for the given pattern. - let mut match_pairs = vec![MatchPairTree::for_pattern(place, pattern, cx)]; + // Recursively build a tree of match pairs for the given pattern. + let mut match_pairs = vec![]; let mut extra_data = PatternExtraData { span: pattern.span, bindings: Vec::new(), ascriptions: Vec::new(), is_never: pattern.is_never_pattern(), }; - // Recursively remove irrefutable match pairs, while recording their - // bindings/ascriptions, and sort or-patterns after other match pairs. - cx.simplify_match_pairs(&mut match_pairs, &mut extra_data); + MatchPairTree::for_pattern(place, pattern, cx, &mut match_pairs, &mut extra_data); Self { match_pairs, extra_data } } @@ -1055,7 +1050,6 @@ struct Candidate<'tcx> { /// (see [`Builder::test_remaining_match_pairs_after_or`]). /// /// Invariants: - /// - All [`TestCase::Irrefutable`] patterns have been removed by simplification. /// - All or-patterns ([`TestCase::Or`]) have been sorted to the end. match_pairs: Vec>, @@ -1126,7 +1120,7 @@ impl<'tcx> Candidate<'tcx> { /// Incorporates an already-simplified [`FlatPat`] into a new candidate. fn from_flat_pat(flat_pat: FlatPat<'tcx>, has_guard: bool) -> Self { - Candidate { + let mut this = Candidate { match_pairs: flat_pat.match_pairs, extra_data: flat_pat.extra_data, has_guard, @@ -1135,7 +1129,14 @@ impl<'tcx> Candidate<'tcx> { otherwise_block: None, pre_binding_block: None, false_edge_start_block: None, - } + }; + this.sort_match_pairs(); + this + } + + /// Restores the invariant that or-patterns must be sorted to the end. + fn sort_match_pairs(&mut self) { + self.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. })); } /// Returns whether the first match pair of this candidate is an or-pattern. @@ -1227,17 +1228,11 @@ struct Ascription<'tcx> { /// - [`Builder::pick_test_for_match_pair`] (to choose a test) /// - [`Builder::sort_candidate`] (to see how the test interacts with a match pair) /// -/// Two variants are unlike the others and deserve special mention: -/// -/// - [`Self::Irrefutable`] is only used temporarily when building a [`MatchPairTree`]. -/// They are then flattened away by [`Builder::simplify_match_pairs`], with any -/// bindings/ascriptions incorporated into the enclosing [`FlatPat`]. -/// - [`Self::Or`] are not tested directly like the other variants. Instead they -/// participate in or-pattern expansion, where they are transformed into subcandidates. -/// - See [`Builder::expand_and_match_or_candidates`]. +/// Note that or-patterns are not tested directly like the other variants. +/// Instead they participate in or-pattern expansion, where they are transformed into +/// subcandidates. See [`Builder::expand_and_match_or_candidates`]. #[derive(Debug, Clone)] enum TestCase<'tcx> { - Irrefutable { binding: Option>, ascription: Option> }, Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx }, Constant { value: mir::Const<'tcx> }, Range(Arc>), @@ -1261,19 +1256,9 @@ impl<'tcx> TestCase<'tcx> { #[derive(Debug, Clone)] pub(crate) struct MatchPairTree<'tcx> { /// This place... - /// - /// --- - /// This can be `None` if it referred to a non-captured place in a closure. - /// - /// Invariant: Can only be `None` when `test_case` is `Irrefutable`. - /// Therefore this must be `Some(_)` after simplification. - place: Option>, + place: Place<'tcx>, /// ... must pass this test... - /// - /// --- - /// Invariant: after creation and simplification in [`FlatPat::new`], - /// this must not be [`TestCase::Irrefutable`]. test_case: TestCase<'tcx>, /// ... and these subpairs must match. @@ -2091,11 +2076,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Extract the match-pair from the highest priority candidate let match_pair = &candidates[0].match_pairs[0]; let test = self.pick_test_for_match_pair(match_pair); - // Unwrap is ok after simplification. - let match_place = match_pair.place.unwrap(); debug!(?test, ?match_pair); - (match_place, test) + (match_pair.place, test) } /// Given a test, we partition the input candidates into several buckets. diff --git a/compiler/rustc_mir_build/src/builder/matches/simplify.rs b/compiler/rustc_mir_build/src/builder/matches/simplify.rs deleted file mode 100644 index 15c860151dc9e..0000000000000 --- a/compiler/rustc_mir_build/src/builder/matches/simplify.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Simplifying Candidates -//! -//! *Simplifying* a match pair `place @ pattern` means breaking it down -//! into bindings or other, simpler match pairs. For example: -//! -//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]` -//! - `place @ x` can be simplified to `[]` by binding `x` to `place` -//! -//! The `simplify_match_pairs` routine just repeatedly applies these -//! sort of simplifications until there is nothing left to -//! simplify. Match pairs cannot be simplified if they require some -//! sort of test: for example, testing which variant an enum is, or -//! testing a value against a constant. - -use std::mem; - -use tracing::{debug, instrument}; - -use crate::builder::Builder; -use crate::builder::matches::{MatchPairTree, PatternExtraData, TestCase}; - -impl<'a, 'tcx> Builder<'a, 'tcx> { - /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and - /// ascriptions in `extra_data`. - #[instrument(skip(self), level = "debug")] - pub(super) fn simplify_match_pairs( - &mut self, - match_pairs: &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): - // - // struct NonCopyStruct { - // copy_field: u32, - // } - // - // fn foo1(x: NonCopyStruct) { - // let y @ NonCopyStruct { copy_field: z } = x; - // // the above should turn into - // let z = x.copy_field; - // let y = x; - // } - // - // We therefore lower bindings from left-to-right, except we lower the `x` in `x @ 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, extra_data); - if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case { - if let Some(binding) = binding { - extra_data.bindings.push(binding); - } - if let Some(ascription) = ascription { - extra_data.ascriptions.push(ascription); - } - // Simplifiable pattern; we replace it with its already simplified subpairs. - match_pairs.append(&mut match_pair.subpairs); - } else { - // Unsimplifiable pattern; we keep it. - match_pairs.push(match_pair); - } - } - - // Move or-patterns to the end, because they can result in us - // creating additional candidates, so we want to test them as - // late as possible. - match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. })); - debug!(simplified = ?match_pairs, "simplify_match_pairs"); - } -} diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index a7a028bff97f7..e5d61bc9e556a 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -55,12 +55,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Or-patterns are not tested directly; instead they are expanded into subcandidates, // which are then distinguished by testing whatever non-or patterns they contain. TestCase::Or { .. } => bug!("or-patterns should have already been handled"), - - TestCase::Irrefutable { .. } => span_bug!( - match_pair.pattern_span, - "simplifiable pattern found: {:?}", - match_pair.pattern_span - ), }; Test { span: match_pair.pattern_span, kind } @@ -546,11 +540,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // than one, but it'd be very unusual to have two sides that // both require tests; you'd expect one side to be simplified // away.) - let (match_pair_index, match_pair) = candidate - .match_pairs - .iter() - .enumerate() - .find(|&(_, mp)| mp.place == Some(test_place))?; + let (match_pair_index, match_pair) = + candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == test_place)?; // If true, the match pair is completely entailed by its corresponding test // branch, so it can be removed. If false, the match pair is _compatible_ @@ -593,7 +584,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate .match_pairs .iter() - .any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case)) + .any(|mp| mp.place == test_place && is_covering_range(&mp.test_case)) }; if sorted_candidates .get(&TestBranch::Failure) @@ -769,7 +760,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let match_pair = candidate.match_pairs.remove(match_pair_index); candidate.match_pairs.extend(match_pair.subpairs); // Move or-patterns to the end. - candidate.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. })); + candidate.sort_match_pairs(); } ret diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index 589e350a03fc3..ed3b652e4ef5d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -173,14 +173,10 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { // } // ``` // Hence we fake borrow using a deep borrow. - if let Some(place) = match_pair.place { - self.fake_borrow(place, FakeBorrowKind::Deep); - } + self.fake_borrow(match_pair.place, FakeBorrowKind::Deep); } else { // Insert a Shallow borrow of any place that is switched on. - if let Some(place) = match_pair.place { - self.fake_borrow(place, FakeBorrowKind::Shallow); - } + self.fake_borrow(match_pair.place, FakeBorrowKind::Shallow); for subpair in &match_pair.subpairs { self.visit_match_pair(subpair);