diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 396782d45d289..edd527286264a 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -65,7 +65,7 @@ pub(crate) enum PlaceBase { /// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a /// place by pushing more and more projections onto the end, and then convert the final set into a -/// place using the `into_place` method. +/// place using the `to_place` method. /// /// This is used internally when building a place for an expression like `a.b.c`. The fields `b` /// and `c` can be progressively pushed onto the place builder that is created when converting `a`. @@ -167,59 +167,54 @@ fn find_capture_matching_projections<'a, 'tcx>( }) } -/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the -/// `PlaceBuilder` now starts from `PlaceBase::Local`. -/// -/// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found. +/// Takes an upvar place and tries to resolve it into a `PlaceBuilder` +/// with `PlaceBase::Local` #[instrument(level = "trace", skip(cx), ret)] fn to_upvars_resolved_place_builder<'tcx>( - from_builder: PlaceBuilder<'tcx>, cx: &Builder<'_, 'tcx>, -) -> Result, PlaceBuilder<'tcx>> { - match from_builder.base { - PlaceBase::Local(_) => Ok(from_builder), - PlaceBase::Upvar { var_hir_id, closure_def_id } => { - let Some((capture_index, capture)) = - find_capture_matching_projections( - &cx.upvars, - var_hir_id, - &from_builder.projection, - ) else { - let closure_span = cx.tcx.def_span(closure_def_id); - if !enable_precise_capture(cx.tcx, closure_span) { - bug!( - "No associated capture found for {:?}[{:#?}] even though \ - capture_disjoint_fields isn't enabled", - var_hir_id, - from_builder.projection - ) - } else { - debug!( - "No associated capture found for {:?}[{:#?}]", - var_hir_id, from_builder.projection, - ); - } - return Err(from_builder); - }; + var_hir_id: LocalVarId, + closure_def_id: LocalDefId, + projection: &[PlaceElem<'tcx>], +) -> Option> { + let Some((capture_index, capture)) = + find_capture_matching_projections( + &cx.upvars, + var_hir_id, + &projection, + ) else { + let closure_span = cx.tcx.def_span(closure_def_id); + if !enable_precise_capture(cx.tcx, closure_span) { + bug!( + "No associated capture found for {:?}[{:#?}] even though \ + capture_disjoint_fields isn't enabled", + var_hir_id, + projection + ) + } else { + debug!( + "No associated capture found for {:?}[{:#?}]", + var_hir_id, projection, + ); + } + return None; + }; - // Access the capture by accessing the field within the Closure struct. - let capture_info = &cx.upvars[capture_index]; + // Access the capture by accessing the field within the Closure struct. + let capture_info = &cx.upvars[capture_index]; - let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place); + let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place); - // We used some of the projections to build the capture itself, - // now we apply the remaining to the upvar resolved place. - trace!(?capture.captured_place, ?from_builder.projection); - let remaining_projections = strip_prefix( - capture.captured_place.place.base_ty, - from_builder.projection, - &capture.captured_place.place.projections, - ); - upvar_resolved_place_builder.projection.extend(remaining_projections); + // We used some of the projections to build the capture itself, + // now we apply the remaining to the upvar resolved place. + trace!(?capture.captured_place, ?projection); + let remaining_projections = strip_prefix( + capture.captured_place.place.base_ty, + projection, + &capture.captured_place.place.projections, + ); + upvar_resolved_place_builder.projection.extend(remaining_projections); - Ok(upvar_resolved_place_builder) - } - } + Some(upvar_resolved_place_builder) } /// Returns projections remaining after stripping an initial prefix of HIR @@ -228,13 +223,14 @@ fn to_upvars_resolved_place_builder<'tcx>( /// Supports only HIR projection kinds that represent a path that might be /// captured by a closure or a generator, i.e., an `Index` or a `Subslice` /// projection kinds are unsupported. -fn strip_prefix<'tcx>( +fn strip_prefix<'a, 'tcx>( mut base_ty: Ty<'tcx>, - projections: Vec>, + projections: &'a [PlaceElem<'tcx>], prefix_projections: &[HirProjection<'tcx>], -) -> impl Iterator> { +) -> impl Iterator> + 'a { let mut iter = projections - .into_iter() + .iter() + .copied() // Filter out opaque casts, they are unnecessary in the prefix. .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..))); for projection in prefix_projections { @@ -258,21 +254,21 @@ fn strip_prefix<'tcx>( } impl<'tcx> PlaceBuilder<'tcx> { - pub(in crate::build) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> { - if let PlaceBase::Local(local) = self.base { - Place { local, projection: cx.tcx.intern_place_elems(&self.projection) } - } else { - self.expect_upvars_resolved(cx).into_place(cx) - } + pub(in crate::build) fn to_place(&self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> { + self.try_to_place(cx).unwrap() } - fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> { - to_upvars_resolved_place_builder(self, cx).unwrap() + /// Creates a `Place` or returns `None` if an upvar cannot be resolved + pub(in crate::build) fn try_to_place(&self, cx: &Builder<'_, 'tcx>) -> Option> { + let resolved = self.resolve_upvar(cx); + let builder = resolved.as_ref().unwrap_or(self); + let PlaceBase::Local(local) = builder.base else { return None }; + let projection = cx.tcx.intern_place_elems(&builder.projection); + Some(Place { local, projection }) } /// Attempts to resolve the `PlaceBuilder`. - /// On success, it will return the resolved `PlaceBuilder`. - /// On failure, it will return itself. + /// Returns `None` if this is not an upvar. /// /// Upvars resolve may fail for a `PlaceBuilder` when attempting to /// resolve a disjoint field whose root variable is not captured @@ -281,11 +277,14 @@ impl<'tcx> PlaceBuilder<'tcx> { /// not captured. This can happen because the final mir that will be /// generated doesn't require a read for this place. Failures will only /// happen inside closures. - pub(in crate::build) fn try_upvars_resolved( - self, + pub(in crate::build) fn resolve_upvar( + &self, cx: &Builder<'_, 'tcx>, - ) -> Result, PlaceBuilder<'tcx>> { - to_upvars_resolved_place_builder(self, cx) + ) -> Option> { + let PlaceBase::Upvar { var_hir_id, closure_def_id } = self.base else { + return None; + }; + to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &self.projection) } pub(crate) fn base(&self) -> PlaceBase { @@ -316,6 +315,14 @@ impl<'tcx> PlaceBuilder<'tcx> { self.projection.push(elem); self } + + /// Same as `.clone().project(..)` but more efficient + pub(crate) fn clone_project(&self, elem: PlaceElem<'tcx>) -> Self { + Self { + base: self.base, + projection: Vec::from_iter(self.projection.iter().copied().chain([elem])), + } + } } impl<'tcx> From for PlaceBuilder<'tcx> { @@ -355,7 +362,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd> { let place_builder = unpack!(block = self.as_place_builder(block, expr)); - block.and(place_builder.into_place(self)) + block.and(place_builder.to_place(self)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -379,7 +386,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd> { let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); - block.and(place_builder.into_place(self)) + block.and(place_builder.to_place(self)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -474,7 +481,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: expr.ty, }); - let place = place_builder.clone().into_place(this); + let place = place_builder.to_place(this); this.cfg.push( block, Statement { @@ -599,7 +606,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let is_outermost_index = fake_borrow_temps.is_none(); let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps); - let mut base_place = + let base_place = unpack!(block = self.expr_as_place(block, base, mutability, Some(fake_borrow_temps),)); // Making this a *fresh* temporary means we do not have to worry about @@ -607,14 +614,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // The "retagging" transformation (for Stacked Borrows) relies on this. let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not,)); - block = self.bounds_check(block, base_place.clone(), idx, expr_span, source_info); + block = self.bounds_check(block, &base_place, idx, expr_span, source_info); if is_outermost_index { self.read_fake_borrows(block, fake_borrow_temps, source_info) } else { - base_place = base_place.expect_upvars_resolved(self); self.add_fake_borrows_of_base( - &base_place, + base_place.to_place(self), block, fake_borrow_temps, expr_span, @@ -628,7 +634,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bounds_check( &mut self, block: BasicBlock, - slice: PlaceBuilder<'tcx>, + slice: &PlaceBuilder<'tcx>, index: Local, expr_span: Span, source_info: SourceInfo, @@ -640,7 +646,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let lt = self.temp(bool_ty, expr_span); // len = len(slice) - self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.into_place(self))); + self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.to_place(self))); // lt = idx < len self.cfg.push_assign( block, @@ -658,19 +664,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn add_fake_borrows_of_base( &mut self, - base_place: &PlaceBuilder<'tcx>, + base_place: Place<'tcx>, block: BasicBlock, fake_borrow_temps: &mut Vec, expr_span: Span, source_info: SourceInfo, ) { let tcx = self.tcx; - let local = match base_place.base { - PlaceBase::Local(local) => local, - PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar"), - }; - let place_ty = Place::ty_from(local, &base_place.projection, &self.local_decls, tcx); + let place_ty = base_place.ty(&self.local_decls, tcx); if let ty::Slice(_) = place_ty.ty.kind() { // We need to create fake borrows to ensure that the bounds // check that we just did stays valid. Since we can't assign to @@ -680,7 +682,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match elem { ProjectionElem::Deref => { let fake_borrow_deref_ty = Place::ty_from( - local, + base_place.local, &base_place.projection[..idx], &self.local_decls, tcx, @@ -698,14 +700,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Ref( tcx.lifetimes.re_erased, BorrowKind::Shallow, - Place { local, projection }, + Place { local: base_place.local, projection }, ), ); fake_borrow_temps.push(fake_borrow_temp); } ProjectionElem::Index(_) => { let index_ty = Place::ty_from( - local, + base_place.local, &base_place.projection[..idx], &self.local_decls, tcx, diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 5c82fb1ddc0d5..0814793f27790 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -369,8 +369,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place_builder = unpack!(block = this.as_place_builder(block, &this.thir[*thir_place])); - if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this) { - let mir_place = place_builder_resolved.into_place(this); + if let Some(mir_place) = place_builder.try_to_place(this) { this.cfg.push_fake_read( block, this.source_info(this.tcx.hir().span(*hir_id)), @@ -661,7 +660,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // by the parent itself. The mutability of the current capture // is same as that of the capture in the parent closure. PlaceBase::Upvar { .. } => { - let enclosing_upvars_resolved = arg_place_builder.clone().into_place(this); + let enclosing_upvars_resolved = arg_place_builder.to_place(this); match enclosing_upvars_resolved.as_ref() { PlaceRef { @@ -698,7 +697,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, }; - let arg_place = arg_place_builder.into_place(this); + let arg_place = arg_place_builder.to_place(this); this.cfg.push_assign( block, diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 33e4fa58399e2..218a26e62797d 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -358,10 +358,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|(n, ty)| match fields_map.get(&n) { Some(v) => v.clone(), None => { - let place_builder = place_builder.clone(); - this.consume_by_copy_or_move( - place_builder.field(n, *ty).into_place(this), - ) + let place = place_builder.clone_project(PlaceElem::Field(n, *ty)); + this.consume_by_copy_or_move(place.to_place(this)) } }) .collect() diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 802704d6ca77d..691cbee2c7319 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -169,7 +169,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scrutinee_place = unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,)); - let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms); + let mut arm_candidates = self.create_match_candidates(&scrutinee_place, &arms); let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard); let mut candidates = @@ -221,8 +221,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cause_matched_place = FakeReadCause::ForMatchedPlace(None); let source_info = self.source_info(scrutinee_span); - if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) { - let scrutinee_place = scrutinee_builder.into_place(self); + if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place); } @@ -232,7 +231,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Create the initial `Candidate`s for a `match` expression. fn create_match_candidates<'pat>( &mut self, - scrutinee: PlaceBuilder<'tcx>, + scrutinee: &PlaceBuilder<'tcx>, arms: &'pat [ArmId], ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)> where @@ -335,7 +334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arm_scope = (arm.scope, arm_source_info); let match_scope = self.local_scope(); self.in_scope(arm_scope, arm.lint_level, |this| { - // `try_upvars_resolved` 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 // a scrutinee place. `scrutinee_place_builder` will fail to be resolved // if the only match arm is a wildcard (`_`). @@ -346,14 +345,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // match foo { _ => () }; // }; // ``` - let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None; - let scrutinee_place: Place<'tcx>; - if let Ok(scrutinee_builder) = - scrutinee_place_builder.clone().try_upvars_resolved(this) - { - scrutinee_place = scrutinee_builder.into_place(this); - opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span)); - } + let scrutinee_place = scrutinee_place_builder.try_to_place(this); + let opt_scrutinee_place = + scrutinee_place.as_ref().map(|place| (Some(place), scrutinee_span)); let scope = this.declare_bindings( None, arm.span, @@ -592,7 +586,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { while let Some(next) = { for binding in &candidate_ref.bindings { let local = self.var_local_id(binding.var_id, OutsideGuard); - // `try_upvars_resolved` 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 // a scrutinee place. `scrutinee_place_builder` will fail for destructured // assignments. This is because a closure only captures the precise places @@ -606,9 +600,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // let (v1, v2) = foo; // }; // ``` - if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) { - let place = match_pair_resolved.into_place(self); - + if let Some(place) = initializer.try_to_place(self) { let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, )))) = self.local_decls[local].local_info else { @@ -1345,7 +1337,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { bug!("Or-patterns should have been sorted to the end"); }; let or_span = match_pair.pattern.span; - let place = match_pair.place; first_candidate.visit_leaves(|leaf_candidate| { self.test_or_pattern( @@ -1353,7 +1344,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut otherwise, pats, or_span, - place.clone(), + &match_pair.place, fake_borrows, ); }); @@ -1381,7 +1372,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise: &mut Option, pats: &'pat [Box>], or_span: Span, - place: PlaceBuilder<'tcx>, + place: &PlaceBuilder<'tcx>, fake_borrows: &mut Option>>, ) { debug!("candidate={:#?}\npats={:#?}", candidate, pats); @@ -1599,10 +1590,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } // Insert a Shallow borrow of any places that is switched on. - if let Some(fb) = fake_borrows && let Ok(match_place_resolved) = - match_place.clone().try_upvars_resolved(self) + if let Some(fb) = fake_borrows + && let Some(resolved_place) = match_place.try_to_place(self) { - let resolved_place = match_place_resolved.into_place(self); fb.insert(resolved_place); } @@ -1621,7 +1611,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // encounter a candidate where the test is not relevant; at // that point, we stop sorting. while let Some(candidate) = candidates.first_mut() { - let Some(idx) = self.sort_candidate(&match_place.clone(), &test, candidate) else { + let Some(idx) = self.sort_candidate(&match_place, &test, candidate) else { break; }; let (candidate, rest) = candidates.split_first_mut().unwrap(); @@ -1690,7 +1680,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { target_blocks }; - self.perform_test(span, scrutinee_span, block, match_place, &test, make_target_blocks); + self.perform_test(span, scrutinee_span, block, &match_place, &test, make_target_blocks); } /// Determine the fake borrows that are needed from a set of places that @@ -1796,12 +1786,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { false, &mut [&mut guard_candidate, &mut otherwise_candidate], ); - let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None; - let expr_place: Place<'tcx>; - if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) { - expr_place = expr_builder.into_place(self); - opt_expr_place = Some((Some(&expr_place), expr_span)); - } + let expr_place = expr_place_builder.try_to_place(self); + let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); self.break_for_else(otherwise_post_guard_block, else_target, self.source_info(expr_span)); diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index caf27eb39d7d4..f6b1955fdec4d 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -73,8 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { { existing_bindings.extend_from_slice(&new_bindings); mem::swap(&mut candidate.bindings, &mut existing_bindings); - candidate.subcandidates = - self.create_or_subcandidates(candidate, place.clone(), pats); + candidate.subcandidates = self.create_or_subcandidates(candidate, &place, pats); return true; } @@ -127,7 +126,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn create_or_subcandidates<'pat>( &mut self, candidate: &Candidate<'pat, 'tcx>, - place: PlaceBuilder<'tcx>, + place: &PlaceBuilder<'tcx>, pats: &'pat [Box>], ) -> Vec> { pats.iter() @@ -156,10 +155,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascription: thir::Ascription { ref annotation, variance }, } => { // Apply the type ascription to the value at `match_pair.place`, which is the - if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) { + if let Some(source) = match_pair.place.try_to_place(self) { candidate.ascriptions.push(Ascription { annotation: annotation.clone(), - source: place_resolved.into_place(self), + source, variance, }); } @@ -183,10 +182,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref subpattern, is_primary: _, } => { - if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) { + if let Some(source) = match_pair.place.try_to_place(self) { candidate.bindings.push(Binding { span: match_pair.pattern.span, - source: place_resolved.into_place(self), + source, var_id: var, binding_mode: mode, }); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index a62cfecf78b78..58513bde2aa2a 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -150,11 +150,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_start_span: Span, scrutinee_span: Span, block: BasicBlock, - place_builder: PlaceBuilder<'tcx>, + place_builder: &PlaceBuilder<'tcx>, test: &Test<'tcx>, make_target_blocks: impl FnOnce(&mut Self) -> Vec, ) { - let place = place_builder.into_place(self); + let place = place_builder.to_place(self); let place_ty = place.ty(&self.local_decls, self.tcx); debug!(?place, ?place_ty,); @@ -760,7 +760,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)` let consequent_match_pairs = subpatterns.iter().map(|subpattern| { // e.g., `(x as Variant).0` - let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty); + let place = downcast_place + .clone_project(PlaceElem::Field(subpattern.field, subpattern.pattern.ty)); // e.g., `(x as Variant).0 @ P1` MatchPair::new(place, &subpattern.pattern, self) }); diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index b854ba47f8f61..bd435f9ab0095 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -18,7 +18,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { subpatterns .iter() .map(|fieldpat| { - let place = place.clone().field(fieldpat.field, fieldpat.pattern.ty); + let place = + place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); MatchPair::new(place, &fieldpat.pattern, self) }) .collect() @@ -33,26 +34,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { suffix: &'pat [Box>], ) { let tcx = self.tcx; - let (min_length, exact_size) = - if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) { - match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() { - ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), - _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), - } - } else { - ((prefix.len() + suffix.len()).try_into().unwrap(), false) - }; + let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { + match place_resolved.ty(&self.local_decls, tcx).ty.kind() { + ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), + _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), + } + } else { + ((prefix.len() + suffix.len()).try_into().unwrap(), false) + }; match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { let elem = ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; - let place = place.clone().project(elem); - MatchPair::new(place, subpattern, self) + MatchPair::new(place.clone_project(elem), subpattern, self) })); if let Some(subslice_pat) = opt_slice { let suffix_len = suffix.len() as u64; - let subslice = place.clone().project(ProjectionElem::Subslice { + let subslice = place.clone_project(PlaceElem::Subslice { from: prefix.len() as u64, to: if exact_size { min_length - suffix_len } else { suffix_len }, from_end: !exact_size, @@ -67,7 +66,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { min_length, from_end: !exact_size, }; - let place = place.clone().project(elem); + let place = place.clone_project(elem); MatchPair::new(place, subpattern, self) })); } @@ -97,15 +96,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { pub(in crate::build) fn new( - place: PlaceBuilder<'tcx>, + mut place: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, cx: &Builder<'_, 'tcx>, ) -> MatchPair<'pat, 'tcx> { // Force the place type to the pattern's type. // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? - let mut place = match place.try_upvars_resolved(cx) { - Ok(val) | Err(val) => val, - }; + if let Some(resolved) = place.resolve_upvar(cx) { + place = resolved; + } // Only add the OpaqueCast projection if the given place is an opaque type and the // expected type from the pattern is not.