Skip to content

Commit c80e77f

Browse files
authored
Rollup merge of #145695 - cjgillot:place-elem-map, r=oli-obk,lcnr
Introduce ProjectionElem::try_map. Small utility function useful to manipulate MIR place projections.
2 parents 77f980f + e5bd01b commit c80e77f

File tree

6 files changed

+66
-93
lines changed

6 files changed

+66
-93
lines changed

compiler/rustc_middle/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#![feature(try_trait_v2_residual)]
6161
#![feature(try_trait_v2_yeet)]
6262
#![feature(type_alias_impl_trait)]
63+
#![feature(unwrap_infallible)]
6364
#![feature(yeet_expr)]
6465
#![recursion_limit = "256"]
6566
// tidy-alphabetical-end

compiler/rustc_middle/src/mir/statement.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,11 @@ impl<'tcx> PlaceTy<'tcx> {
160160
/// Convenience wrapper around `projection_ty_core` for `PlaceElem`,
161161
/// where we can just use the `Ty` that is already stored inline on
162162
/// field projection elems.
163-
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
163+
pub fn projection_ty<V: ::std::fmt::Debug>(
164+
self,
165+
tcx: TyCtxt<'tcx>,
166+
elem: ProjectionElem<V, Ty<'tcx>>,
167+
) -> PlaceTy<'tcx> {
164168
self.projection_ty_core(tcx, &elem, |ty| ty, |_, _, _, ty| ty, |ty| ty)
165169
}
166170

@@ -290,6 +294,36 @@ impl<V, T> ProjectionElem<V, T> {
290294
Self::UnwrapUnsafeBinder(..) => false,
291295
}
292296
}
297+
298+
/// Returns the `ProjectionKind` associated to this projection.
299+
pub fn kind(self) -> ProjectionKind {
300+
self.try_map(|_| Some(()), |_| ()).unwrap()
301+
}
302+
303+
/// Apply functions to types and values in this projection and return the result.
304+
pub fn try_map<V2, T2>(
305+
self,
306+
v: impl FnOnce(V) -> Option<V2>,
307+
t: impl FnOnce(T) -> T2,
308+
) -> Option<ProjectionElem<V2, T2>> {
309+
Some(match self {
310+
ProjectionElem::Deref => ProjectionElem::Deref,
311+
ProjectionElem::Downcast(name, read_variant) => {
312+
ProjectionElem::Downcast(name, read_variant)
313+
}
314+
ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, t(ty)),
315+
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
316+
ProjectionElem::ConstantIndex { offset, min_length, from_end }
317+
}
318+
ProjectionElem::Subslice { from, to, from_end } => {
319+
ProjectionElem::Subslice { from, to, from_end }
320+
}
321+
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(t(ty)),
322+
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(t(ty)),
323+
ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(t(ty)),
324+
ProjectionElem::Index(val) => ProjectionElem::Index(v(val)?),
325+
})
326+
}
293327
}
294328

295329
/// Alias for projections as they appear in `UserTypeProjection`, where we

compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs

Lines changed: 0 additions & 38 deletions
This file was deleted.

compiler/rustc_mir_dataflow/src/move_paths/builder.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use rustc_middle::{bug, span_bug};
77
use smallvec::{SmallVec, smallvec};
88
use tracing::debug;
99

10-
use super::abs_domain::Lift;
1110
use super::{
1211
Init, InitIndex, InitKind, InitLocation, LocationMap, LookupResult, MoveData, MoveOut,
1312
MoveOutIndex, MovePath, MovePathIndex, MovePathLookup,
@@ -241,7 +240,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
241240
if union_path.is_none() {
242241
// inlined from add_move_path because of a borrowck conflict with the iterator
243242
base =
244-
*data.rev_lookup.projections.entry((base, elem.lift())).or_insert_with(|| {
243+
*data.rev_lookup.projections.entry((base, elem.kind())).or_insert_with(|| {
245244
new_move_path(
246245
&mut data.move_paths,
247246
&mut data.path_map,
@@ -272,7 +271,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
272271
tcx,
273272
..
274273
} = self;
275-
*rev_lookup.projections.entry((base, elem.lift())).or_insert_with(move || {
274+
*rev_lookup.projections.entry((base, elem.kind())).or_insert_with(move || {
276275
new_move_path(move_paths, path_map, init_path_map, Some(base), mk_place(*tcx))
277276
})
278277
}

compiler/rustc_mir_dataflow/src/move_paths/mod.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
//! The move-analysis portion of borrowck needs to work in an abstract domain of lifted `Place`s.
2+
//! Most of the `Place` variants fall into a one-to-one mapping between the concrete and abstract
3+
//! (e.g., a field projection on a local variable, `x.field`, has the same meaning in both
4+
//! domains). In other words, all field projections for the same field on the same local do not
5+
//! have meaningfully different types if ever. Indexed projections are the exception: `a[x]` needs
6+
//! to be treated as mapping to the same move path as `a[y]` as well as `a[13]`, etc. So we map
7+
//! these `x`/`y` values to `()`.
8+
//!
9+
//! (In theory, the analysis could be extended to work with sets of paths, so that `a[0]` and
10+
//! `a[13]` could be kept distinct, while `a[x]` would still overlap them both. But that is not
11+
//! what this representation does today.)
12+
113
use std::fmt;
214
use std::ops::{Index, IndexMut};
315

@@ -8,11 +20,8 @@ use rustc_middle::ty::{Ty, TyCtxt};
820
use rustc_span::Span;
921
use smallvec::SmallVec;
1022

11-
use self::abs_domain::Lift;
1223
use crate::un_derefer::UnDerefer;
1324

14-
mod abs_domain;
15-
1625
rustc_index::newtype_index! {
1726
#[orderable]
1827
#[debug_format = "mp{}"]
@@ -324,7 +333,7 @@ impl<'tcx> MovePathLookup<'tcx> {
324333
};
325334

326335
for (_, elem) in self.un_derefer.iter_projections(place) {
327-
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
336+
if let Some(&subpath) = self.projections.get(&(result, elem.kind())) {
328337
result = subpath;
329338
} else {
330339
return LookupResult::Parent(Some(result));

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 15 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -447,26 +447,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
447447

448448
Projection(base, elem) => {
449449
let base = self.evaluated[base].as_ref()?;
450-
let elem = match elem {
451-
ProjectionElem::Deref => ProjectionElem::Deref,
452-
ProjectionElem::Downcast(name, read_variant) => {
453-
ProjectionElem::Downcast(name, read_variant)
454-
}
455-
ProjectionElem::Field(f, ()) => ProjectionElem::Field(f, ty.ty),
456-
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
457-
ProjectionElem::ConstantIndex { offset, min_length, from_end }
458-
}
459-
ProjectionElem::Subslice { from, to, from_end } => {
460-
ProjectionElem::Subslice { from, to, from_end }
461-
}
462-
ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty.ty),
463-
ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty.ty),
464-
ProjectionElem::UnwrapUnsafeBinder(()) => {
465-
ProjectionElem::UnwrapUnsafeBinder(ty.ty)
466-
}
467-
// This should have been replaced by a `ConstantIndex` earlier.
468-
ProjectionElem::Index(_) => return None,
469-
};
450+
// `Index` by constants should have been replaced by `ConstantIndex` by
451+
// `simplify_place_projection`.
452+
let elem = elem.try_map(|_| None, |()| ty.ty)?;
470453
self.ecx.project(base, elem).discard_err()?
471454
}
472455
Address { place, kind: _, provenance: _ } => {
@@ -476,13 +459,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
476459
let local = self.locals[place.local]?;
477460
let pointer = self.evaluated[local].as_ref()?;
478461
let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?;
479-
for proj in place.projection.iter().skip(1) {
480-
// We have no call stack to associate a local with a value, so we cannot
481-
// interpret indexing.
482-
if matches!(proj, ProjectionElem::Index(_)) {
483-
return None;
484-
}
485-
mplace = self.ecx.project(&mplace, proj).discard_err()?;
462+
for elem in place.projection.iter().skip(1) {
463+
// `Index` by constants should have been replaced by `ConstantIndex` by
464+
// `simplify_place_projection`.
465+
let elem = elem.try_map(|_| None, |ty| ty)?;
466+
mplace = self.ecx.project(&mplace, elem).discard_err()?;
486467
}
487468
let pointer = mplace.to_ref(&self.ecx);
488469
ImmTy::from_immediate(pointer, ty).into()
@@ -902,27 +883,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
902883
proj: ProjectionElem<VnIndex, ()>,
903884
loc: Location,
904885
) -> Option<PlaceElem<'tcx>> {
905-
Some(match proj {
906-
ProjectionElem::Deref => ProjectionElem::Deref,
907-
ProjectionElem::Field(idx, ()) => ProjectionElem::Field(idx, ty),
908-
ProjectionElem::Index(idx) => {
909-
let Some(local) = self.try_as_local(idx, loc) else {
910-
return None;
911-
};
886+
proj.try_map(
887+
|value| {
888+
let local = self.try_as_local(value, loc)?;
912889
self.reused_locals.insert(local);
913-
ProjectionElem::Index(local)
914-
}
915-
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
916-
ProjectionElem::ConstantIndex { offset, min_length, from_end }
917-
}
918-
ProjectionElem::Subslice { from, to, from_end } => {
919-
ProjectionElem::Subslice { from, to, from_end }
920-
}
921-
ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
922-
ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty),
923-
ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty),
924-
ProjectionElem::UnwrapUnsafeBinder(()) => ProjectionElem::UnwrapUnsafeBinder(ty),
925-
})
890+
Some(local)
891+
},
892+
|()| ty,
893+
)
926894
}
927895

928896
fn simplify_aggregate_to_copy(

0 commit comments

Comments
 (0)