]> git.lizzy.rs Git - rust.git/commitdiff
properly handle enum field projections
authorb-naber <bn263@gmx.de>
Wed, 2 Nov 2022 21:02:39 +0000 (22:02 +0100)
committerb-naber <bn263@gmx.de>
Wed, 23 Nov 2022 19:01:11 +0000 (20:01 +0100)
compiler/rustc_mir_build/src/build/expr/as_place.rs
compiler/rustc_mir_build/src/build/matches/simplify.rs
compiler/rustc_mir_build/src/build/matches/util.rs

index b6f2e3de66827cf857b1686242c486149b08501d..b682b0c3bd470f3a3c1fa82a8e628b4951918656 100644 (file)
@@ -7,6 +7,7 @@
 use rustc_middle::hir::place::Projection as HirProjection;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
+use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::AssertKind::BoundsCheck;
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
@@ -324,56 +325,35 @@ pub(crate) fn clone_project(&self, elem: PlaceElem<'tcx>) -> Self {
         }
     }
 
-    pub fn try_ty<D>(&self, local_decls: &D, cx: &Builder<'_, 'tcx>) -> Option<Ty<'tcx>>
+    pub fn try_compute_ty<D>(
+        &self,
+        local_decls: &D,
+        cx: &Builder<'_, 'tcx>,
+    ) -> Option<PlaceTy<'tcx>>
     where
         D: HasLocalDecls<'tcx>,
     {
-        let tcx = cx.tcx;
-
-        let project_ty = |ty: Ty<'tcx>, elem: &PlaceElem<'tcx>| -> Ty<'tcx> {
-            match elem {
-                ProjectionElem::Deref => {
-                    ty.builtin_deref(true)
-                        .unwrap_or_else(|| {
-                            bug!("deref projection of non-dereferenceable ty {:?}", ty)
-                        })
-                        .ty
-                }
-                ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
-                    ty.builtin_index().unwrap()
-                }
-                ProjectionElem::Subslice { from, to, from_end } => match ty.kind() {
-                    ty::Slice(..) => ty,
-                    ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64),
-                    ty::Array(inner, size) if *from_end => {
-                        let size = size.eval_usize(tcx, ty::ParamEnv::empty());
-                        let len = size - (*from as u64) - (*to as u64);
-                        tcx.mk_array(*inner, len)
-                    }
-                    _ => bug!("cannot subslice non-array type: `{:?}`", ty),
-                },
-                ProjectionElem::Downcast(..) => ty,
-                ProjectionElem::Field(_, ty) | ProjectionElem::OpaqueCast(ty) => *ty,
-            }
-        };
-
         match self.base {
-            PlaceBase::Local(local) => {
-                let base_ty = local_decls.local_decls()[local].ty;
-                Some(self.projection.iter().fold(base_ty, |ty, &elem| project_ty(ty, &elem)))
-            }
+            PlaceBase::Local(_) => Some(self.clone().into_place(cx).ty(local_decls, cx.tcx)),
             PlaceBase::Upvar { .. } => {
                 match to_upvars_resolved_place_builder(self.clone(), cx) {
                     Ok(resolved_place_builder) => {
                         // `base` is guaranteed to be `PlaceBase::Local` now, so recursive call is ok
-                        resolved_place_builder.try_ty(local_decls, cx)
+                        resolved_place_builder.try_compute_ty(local_decls, cx)
                     }
                     Err(place_builder) => {
                         match &place_builder.projection[..] {
-                            &[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => Some(
-                                projections.iter().fold(base_ty, |ty, &elem| project_ty(ty, &elem)),
-                            ),
+                            &[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => {
+                                let place_ty = projections
+                                    .iter()
+                                    .fold(PlaceTy::from_ty(base_ty), |place_ty, &elem| {
+                                        place_ty.projection_ty(cx.tcx, elem)
+                                    });
+
+                                debug!(?place_ty);
 
+                                Some(place_ty)
+                            }
                             _ => None, // would need a base `Ty` for these
                         }
                     }
index fb9f19b7b9066070420c6ff8e8c9e5f3a7adf321..36aa7693e827ff3009026c32fd2b88c3a8c7b2af 100644 (file)
@@ -272,9 +272,9 @@ fn simplify_match_pair<'pat>(
                     || !adt_def.is_variant_list_non_exhaustive());
                 if irrefutable {
                     let place_builder = match_pair.place.downcast(adt_def, variant_index);
-                    candidate
-                        .match_pairs
-                        .extend(self.field_match_pairs(place_builder, subpatterns));
+                    let field_match_pairs =
+                        self.field_match_pairs(place_builder.clone(), subpatterns);
+                    candidate.match_pairs.extend(field_match_pairs);
                     Ok(())
                 } else {
                     Err(match_pair)
@@ -294,9 +294,7 @@ fn simplify_match_pair<'pat>(
 
             PatKind::Leaf { ref subpatterns } => {
                 // tuple struct, match subpats (if any)
-                candidate
-                    .match_pairs
-                    .extend(self.field_match_pairs_tuple_struct(match_pair.place, subpatterns));
+                candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns));
                 Ok(())
             }
 
index 6a07b07ee12781f10acab82da32b6ffcfbdf160a..7423b5e1ae3ec81c25aace0b75c50dd547bafb3a 100644 (file)
@@ -31,10 +31,14 @@ pub(crate) fn field_match_pairs_tuple_struct<'pat>(
         place_builder: PlaceBuilder<'tcx>,
         subpatterns: &'pat [FieldPat<'tcx>],
     ) -> Vec<MatchPair<'pat, 'tcx>> {
-        let place_ty = place_builder
-            .try_ty(&self.local_decls, self)
-            .map(|ty| self.tcx.normalize_erasing_regions(self.param_env, ty));
-        debug!(?place_ty);
+        let place_ty_and_variant_idx =
+            place_builder.try_compute_ty(&self.local_decls, self).map(|place_ty| {
+                (
+                    self.tcx.normalize_erasing_regions(self.param_env, place_ty.ty),
+                    place_ty.variant_index,
+                )
+            });
+        debug!(?place_ty_and_variant_idx);
 
         subpatterns
             .iter()
@@ -43,9 +47,13 @@ pub(crate) fn field_match_pairs_tuple_struct<'pat>(
                 // during borrow-checking on higher-ranked types if we use the
                 // ascribed type as the field type, so we try to get the actual field
                 // type from the `Place`, if possible, see issue #96514
-                let field_ty = if let Some(place_ty) = place_ty {
+                let field_ty = if let Some((place_ty, opt_variant_idx)) = place_ty_and_variant_idx {
                     let field_idx = fieldpat.field.as_usize();
                     let field_ty = match place_ty.kind() {
+                        ty::Adt(adt_def, substs) if adt_def.is_enum() => {
+                            let variant_idx = opt_variant_idx.unwrap();
+                            adt_def.variant(variant_idx).fields[field_idx].ty(self.tcx, substs)
+                        }
                         ty::Adt(adt_def, substs) => {
                             adt_def.all_fields().collect::<Vec<_>>()[field_idx].ty(self.tcx, substs)
                         }