Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use non-ascribed type as field's type in mir #103880

Merged
merged 12 commits into from
Dec 16, 2022
Prev Previous commit
Next Next commit
use no type in ProjectionElem::Field for PlaceBuilder::UpVar
  • Loading branch information
b-naber committed Nov 23, 2022
commit 9061ffba8ceb6a3a927aff15b570f9bd4247862a
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1517,7 +1517,7 @@ impl<'tcx> StatementKind<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Places

impl<V, T> ProjectionElem<V, T> {
impl<V, T, U> ProjectionElem<V, T, U> {
/// Returns `true` if the target of this projection may refer to a different region of memory
/// than the base.
fn is_indirect(&self) -> bool {
Expand Down Expand Up @@ -1546,7 +1546,7 @@ impl<V, T> ProjectionElem<V, T> {

/// Alias for projections as they appear in `UserTypeProjection`, where we
/// need neither the `V` parameter for `Index` nor the `T` for `Field`.
pub type ProjectionKind = ProjectionElem<(), ()>;
pub type ProjectionKind = ProjectionElem<(), (), ()>;

rustc_index::newtype_index! {
/// A [newtype'd][wrapper] index type in the MIR [control-flow graph][CFG]
Expand Down
32 changes: 28 additions & 4 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -877,9 +877,9 @@ pub struct Place<'tcx> {

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub enum ProjectionElem<V, T> {
pub enum ProjectionElem<V, T1, T2> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point it might be worth documenting what these types mean? Their names are not exactly descriptive.

Deref,
Field(Field, T),
Field(Field, T1),
/// Index into a slice/array.
///
/// Note that this does not also dereference, and so it does not exactly correspond to slice
Expand Down Expand Up @@ -935,12 +935,36 @@ pub enum ProjectionElem<V, T> {

/// Like an explicit cast from an opaque type to a concrete type, but without
/// requiring an intermediate variable.
OpaqueCast(T),
OpaqueCast(T2),
}

/// Alias for projections as they appear in places, where the base is a place
/// and the index is a local.
pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>, Ty<'tcx>>;

/// Alias for projections that appear in `PlaceBuilder::UpVar`, for which
/// we cannot provide any field types.
pub type UpvarProjectionElem<'tcx> = ProjectionElem<Local, (), Ty<'tcx>>;

impl<'tcx> From<PlaceElem<'tcx>> for UpvarProjectionElem<'tcx> {
fn from(elem: PlaceElem<'tcx>) -> Self {
match elem {
ProjectionElem::Deref => ProjectionElem::Deref,
ProjectionElem::Field(field, _) => ProjectionElem::Field(field, ()),
ProjectionElem::Index(v) => ProjectionElem::Index(v),
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
ProjectionElem::ConstantIndex { offset, min_length, from_end }
}
ProjectionElem::Subslice { from, to, from_end } => {
ProjectionElem::Subslice { from, to, from_end }
}
ProjectionElem::Downcast(opt_sym, variant_idx) => {
ProjectionElem::Downcast(opt_sym, variant_idx)
}
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
}
}
}

///////////////////////////////////////////////////////////////////////////
// Operands
Expand Down
15 changes: 8 additions & 7 deletions compiler/rustc_middle/src/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ impl<'tcx> PlaceTy<'tcx> {
/// `place_ty.field_ty(tcx, f)` computes the type at a given field
/// of a record or enum-variant. (Most clients of `PlaceTy` can
/// instead just extract the relevant type directly from their
/// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do
/// not carry a `Ty` for `T`.)
/// `PlaceElem`, but some instances of `ProjectionElem<V, T1, T2>` do
/// not carry a `Ty` for `T1` or `T2`.)
///
/// Note that the resulting type has not been normalized.
pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> {
Expand Down Expand Up @@ -64,17 +64,18 @@ impl<'tcx> PlaceTy<'tcx> {
/// `Ty` or downcast variant corresponding to that projection.
/// The `handle_field` callback must map a `Field` to its `Ty`,
/// (which should be trivial when `T` = `Ty`).
pub fn projection_ty_core<V, T>(
pub fn projection_ty_core<V, T1, T2>(
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>,
mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>,
mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>,
elem: &ProjectionElem<V, T1, T2>,
mut handle_field: impl FnMut(&Self, Field, T1) -> Ty<'tcx>,
mut handle_opaque_cast: impl FnMut(&Self, T2) -> Ty<'tcx>,
) -> PlaceTy<'tcx>
where
V: ::std::fmt::Debug,
T: ::std::fmt::Debug + Copy,
T1: ::std::fmt::Debug + Copy,
T2: ::std::fmt::Debug + Copy,
{
if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) {
bug!("cannot use non field projection on downcasted place")
Expand Down
92 changes: 60 additions & 32 deletions compiler/rustc_mir_build/src/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use rustc_target::abi::VariantIdx;
use rustc_index::vec::Idx;

use std::assert_matches::assert_matches;
use std::convert::From;
use std::iter;

/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
Expand Down Expand Up @@ -66,7 +67,7 @@ pub(in crate::build) enum PlaceBuilder<'tcx> {
///
/// Note: in contrast to `PlaceBuilder::Local` we have not yet determined all `Field` types
/// and will only do so once converting to `PlaceBuilder::Local`.
UpVar(UpVar, Vec<PlaceElem<'tcx>>),
UpVar(UpVar, Vec<UpvarProjectionElem<'tcx>>),
}

#[derive(Copy, Clone, Debug, PartialEq)]
Expand All @@ -82,7 +83,7 @@ pub(crate) struct UpVar {
/// part of a path that is captured by a closure. We stop applying projections once we see the first
/// projection that isn't captured by a closure.
fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
mir_projections: &[PlaceElem<'tcx>],
mir_projections: &[UpvarProjectionElem<'tcx>],
) -> Vec<HirProjectionKind> {
let mut hir_projections = Vec::new();
let mut variant = None;
Expand Down Expand Up @@ -156,7 +157,7 @@ fn is_ancestor_or_same_capture(
fn find_capture_matching_projections<'a, 'tcx>(
upvars: &'a CaptureMap<'tcx>,
var_hir_id: LocalVarId,
projections: &[PlaceElem<'tcx>],
projections: &[UpvarProjectionElem<'tcx>],
) -> Option<(usize, &'a Capture<'tcx>)> {
let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections);

Expand Down Expand Up @@ -212,8 +213,7 @@ fn to_upvars_resolved_place_builder<'tcx>(
capture.captured_place.place.base_ty,
projection,
&capture.captured_place.place.projections,
)
.collect::<Vec<_>>();
);

let upvar_resolved_place_builder = PlaceBuilder::construct_local_place_builder(
cx,
Expand All @@ -222,6 +222,37 @@ fn to_upvars_resolved_place_builder<'tcx>(
upvar_projection,
);

debug_assert!({
let builder = upvar_resolved_place_builder.clone();
let mut valid_conversion = true;
match builder {
PlaceBuilder::Local(_, projections) => {
for proj in projections.iter() {
match proj {
ProjectionElem::Field(_, field_ty) => {
if matches!(field_ty.kind(), ty::Infer(..)) {
debug!(
"field ty should have been converted for projection {:?} in PlaceBuilder {:?}",
proj,
upvar_resolved_place_builder.clone()
);

valid_conversion = false;
break;
}
}
_ => {}
}
}
}
PlaceBuilder::UpVar(..) => {
unreachable!()
}
}

valid_conversion
});

Some(upvar_resolved_place_builder)
}

Expand All @@ -233,14 +264,14 @@ fn to_upvars_resolved_place_builder<'tcx>(
/// projection kinds are unsupported.
fn strip_prefix<'a, 'tcx>(
mut base_ty: Ty<'tcx>,
projections: &'a [PlaceElem<'tcx>],
projections: &'a [UpvarProjectionElem<'tcx>],
prefix_projections: &[HirProjection<'tcx>],
) -> impl Iterator<Item = PlaceElem<'tcx>> + 'a {
) -> Vec<UpvarProjectionElem<'tcx>> {
let mut iter = projections
.iter()
.copied()
// Filter out opaque casts, they are unnecessary in the prefix.
.filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..)));
.filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..)))
.map(|elem| *elem);
for projection in prefix_projections {
debug!(?projection, ?projection.ty);

Expand All @@ -261,7 +292,8 @@ fn strip_prefix<'a, 'tcx>(

base_ty = projection.ty;
}
iter

iter.collect::<Vec<_>>()
}

impl<'tcx> PlaceBuilder<'tcx> {
Expand Down Expand Up @@ -292,11 +324,11 @@ impl<'tcx> PlaceBuilder<'tcx> {
&self,
cx: &Builder<'_, 'tcx>,
) -> Option<PlaceBuilder<'tcx>> {
let PlaceBuilder::Upvar( Upvar {var_hir_id, closure_def_id }, projection) = self else {
let PlaceBuilder::UpVar( UpVar {var_hir_id, closure_def_id }, projection) = self else {
return None;
};

to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &projection)
to_upvars_resolved_place_builder(cx, *var_hir_id, *closure_def_id, &projection)
}

pub(crate) fn get_local_projection(&self) -> &[PlaceElem<'tcx>] {
Expand All @@ -309,19 +341,16 @@ impl<'tcx> PlaceBuilder<'tcx> {
}

#[instrument(skip(cx), level = "debug")]
pub(crate) fn field(
self,
cx: &Builder<'_, 'tcx>,
f: Field,
default_field_ty: Ty<'tcx>,
) -> Self {
pub(crate) fn field(self, cx: &Builder<'_, 'tcx>, f: Field) -> Self {
let field_ty = match self {
PlaceBuilder::Local(..) => {
let base_place = self.clone();
PlaceBuilder::try_compute_field_ty(cx, f, base_place)
.unwrap_or_else(|| default_field_ty)
PlaceBuilder::compute_field_ty(cx, f, base_place)
}
PlaceBuilder::UpVar(..) => {
let dummy_ty = cx.tcx.mk_ty_infer(ty::FreshTy(0));
dummy_ty
}
PlaceBuilder::UpVar(..) => default_field_ty,
};

self.project(ProjectionElem::Field(f, field_ty))
Expand All @@ -347,7 +376,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
PlaceBuilder::Local(local, proj)
}
PlaceBuilder::UpVar(upvar, mut proj) => {
proj.push(elem);
proj.push(elem.into());
PlaceBuilder::UpVar(upvar, proj)
}
};
Expand All @@ -363,8 +392,8 @@ impl<'tcx> PlaceBuilder<'tcx> {
*local,
Vec::from_iter(proj.iter().copied().chain([elem.into()])),
),
PlaceBuilder::Upvar(upvar, proj) => PlaceBuilder::UpVar(
upvar,
PlaceBuilder::UpVar(upvar, proj) => PlaceBuilder::UpVar(
*upvar,
Vec::from_iter(proj.iter().copied().chain([elem.into()])),
),
}
Expand All @@ -378,11 +407,11 @@ impl<'tcx> PlaceBuilder<'tcx> {
/// Fallible as the root of this place may be an upvar for
/// which no base type can be determined.
#[instrument(skip(cx), level = "debug")]
fn try_compute_field_ty(
fn compute_field_ty(
cx: &Builder<'_, 'tcx>,
field: Field,
base_place: PlaceBuilder<'tcx>,
) -> Option<Ty<'tcx>> {
) -> Ty<'tcx> {
let field_idx = field.as_usize();
let PlaceTy { ty, variant_index } = base_place.to_place(cx).ty(&cx.local_decls, cx.tcx);
let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
Expand Down Expand Up @@ -442,7 +471,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
_ => bug!("couldn't create field type, unexpected base type: {:?}", base_ty),
};

Some(cx.tcx.normalize_erasing_regions(cx.param_env, field_ty))
cx.tcx.normalize_erasing_regions(cx.param_env, field_ty)
}

/// Creates a `PlaceBuilder::Local` from a `PlaceBuilder::UpVar` whose upvars
Expand All @@ -455,7 +484,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
cx: &Builder<'_, 'tcx>,
local: Local,
mut local_projection: Vec<PlaceElem<'tcx>>,
upvar_projection: Vec<PlaceElem<'tcx>>,
upvar_projection: Vec<UpvarProjectionElem<'tcx>>,
) -> Self {
// We iterate through `upvar_projection` and whenever we find a `ProjectionElem::Field` we use
// the ancestor projections, i.e. those projection elements that come before the field projection,
Expand All @@ -464,11 +493,10 @@ impl<'tcx> PlaceBuilder<'tcx> {
for proj in upvar_projection.iter() {
debug!("proj: {:?}, local_projection: {:?}", proj, local_projection);
match *proj {
ProjectionElem::Field(field, default_field_ty) => {
ProjectionElem::Field(field, _) => {
let ancestor_proj = local_projection.to_vec();
let base_place = PlaceBuilder::Local(local, ancestor_proj);
let field_ty = PlaceBuilder::try_compute_field_ty(cx, field, base_place)
.unwrap_or_else(|| default_field_ty);
let field_ty = PlaceBuilder::compute_field_ty(cx, field, base_place);
debug!(?field_ty);

local_projection.push(ProjectionElem::Field(field, field_ty));
Expand Down Expand Up @@ -593,7 +621,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place_builder = place_builder.downcast(*adt_def, variant_index);
}
}
block.and(place_builder.field(this, name, expr.ty))
block.and(place_builder.field(this, name))
}
ExprKind::Deref { arg } => {
let place_builder = unpack!(
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,12 +355,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// base-supplied field, generate an operand that
// reads it from the base.
iter::zip(field_names, &**field_types)
.map(|(n, ty)| match fields_map.get(&n) {
.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(this, n, *ty).to_place(this),
place_builder.field(this, n).to_place(this),
)
}
})
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@ 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(self, subpattern.field, subpattern.pattern.ty);
let place = downcast_place.clone().field(self, subpattern.field);
// e.g., `(x as Variant).0 @ P1`
MatchPair::new(place, &subpattern.pattern, self)
});
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/matches/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
subpatterns
.iter()
.map(|fieldpat| {
let place = place.clone().field(self, fieldpat.field, fieldpat.pattern.ty);
let place = place.clone().field(self, fieldpat.field);

MatchPair::new(place, &fieldpat.pattern, self)
})
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_middle::ty::Ty;
pub struct AbstractOperand;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct AbstractType;
pub type AbstractElem = ProjectionElem<AbstractOperand, AbstractType>;
pub type AbstractElem = ProjectionElem<AbstractOperand, AbstractType, AbstractType>;

pub trait Lift {
type Abstract;
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_dataflow/src/value_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,10 +777,10 @@ pub enum TrackElem {
Field(Field),
}

impl<V, T> TryFrom<ProjectionElem<V, T>> for TrackElem {
impl<V, T1, T2> TryFrom<ProjectionElem<V, T1, T2>> for TrackElem {
type Error = ();

fn try_from(value: ProjectionElem<V, T>) -> Result<Self, Self::Error> {
fn try_from(value: ProjectionElem<V, T1, T2>) -> Result<Self, Self::Error> {
match value {
ProjectionElem::Field(field, _) => Ok(TrackElem::Field(field)),
_ => Err(()),
Expand Down