about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs4
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs32
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs15
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs92
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs4
9 files changed, 105 insertions, 52 deletions
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 364c1b375ae..a646860ed45 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -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 {
@@ -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]
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index fed943169df..004dd004c72 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -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> {
     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
@@ -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
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index fa3adafd4b8..e3ca1f41d7e 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -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> {
@@ -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")
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 bf417dae785..bd27b6c2beb 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -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
@@ -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)]
@@ -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;
@@ -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);
 
@@ -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,
@@ -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)
 }
 
@@ -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);
 
@@ -261,7 +292,8 @@ fn strip_prefix<'a, 'tcx>(
 
         base_ty = projection.ty;
     }
-    iter
+
+    iter.collect::<Vec<_>>()
 }
 
 impl<'tcx> PlaceBuilder<'tcx> {
@@ -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>] {
@@ -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))
@@ -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)
             }
         };
@@ -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()])),
             ),
         }
@@ -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);
@@ -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
@@ -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,
@@ -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));
@@ -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!(
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 12cd0e65a11..e5c2f4f4cbe 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -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),
                                 )
                             }
                         })
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 7b932eda744..c669016e0ed 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -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)
         });
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 30f4e49d8ba..27a7b03465f 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -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)
             })
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
index 7806e8f45d3..5cfbbb1ac01 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs
@@ -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;
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index cc69a1bb02d..b09503a3093 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -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(()),