about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2024-12-18 14:02:42 +0100
committerlcnr <rust@lcnr.de>2024-12-18 14:15:08 +0100
commit51cd03a1279d720a02db252e64cc11f2513d9704 (patch)
tree9d7e28df86dcd9f4298b482af25a1042bcc3f6fd
parent809f55d66aeb8f4236bd778178b9eafbab1d6a1d (diff)
downloadrust-51cd03a1279d720a02db252e64cc11f2513d9704.tar.gz
rust-51cd03a1279d720a02db252e64cc11f2513d9704.zip
merge PlaceTy field_ty computation
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs117
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs71
2 files changed, 65 insertions, 123 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index dc28856ebe7..812633843e6 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -3,7 +3,7 @@
 use std::rc::Rc;
 use std::{fmt, iter, mem};
 
-use rustc_abi::{FIRST_VARIANT, FieldIdx};
+use rustc_abi::FieldIdx;
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::ErrorGuaranteed;
@@ -273,35 +273,18 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
             | ProjectionElem::Downcast(..) => {}
             ProjectionElem::Field(field, fty) => {
                 let fty = self.typeck.normalize(fty, location);
-                match self.expected_field_ty(base_ty, field, location) {
-                    Ok(ty) => {
-                        let ty = self.typeck.normalize(ty, location);
-                        debug!(?fty, ?ty);
+                let ty = base_ty.field_ty(tcx, field);
+                let ty = self.typeck.normalize(ty, location);
+                debug!(?fty, ?ty);
 
-                        if let Err(terr) = self.typeck.relate_types(
-                            ty,
-                            context.ambient_variance(),
-                            fty,
-                            location.to_locations(),
-                            ConstraintCategory::Boring,
-                        ) {
-                            span_mirbug!(
-                                self,
-                                place,
-                                "bad field access ({:?}: {:?}): {:?}",
-                                ty,
-                                fty,
-                                terr
-                            );
-                        }
-                    }
-                    Err(FieldAccessError::OutOfRange { field_count }) => span_mirbug!(
-                        self,
-                        place,
-                        "accessed field #{} but variant only has {}",
-                        field.index(),
-                        field_count
-                    ),
+                if let Err(terr) = self.typeck.relate_types(
+                    ty,
+                    context.ambient_variance(),
+                    fty,
+                    location.to_locations(),
+                    ConstraintCategory::Boring,
+                ) {
+                    span_mirbug!(self, place, "bad field access ({:?}: {:?}): {:?}", ty, fty, terr);
                 }
             }
             ProjectionElem::OpaqueCast(ty) => {
@@ -589,82 +572,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
             self.typeck.constraints.liveness_constraints.add_location(region, location);
         }
     }
-
-    fn expected_field_ty(
-        &mut self,
-        base_ty: PlaceTy<'tcx>,
-        field: FieldIdx,
-        location: Location,
-    ) -> Result<Ty<'tcx>, FieldAccessError> {
-        let tcx = self.tcx();
-
-        let (variant, args) = match base_ty {
-            PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() {
-                ty::Adt(adt_def, args) => (adt_def.variant(variant_index), args),
-                ty::Coroutine(def_id, args) => {
-                    let mut variants = args.as_coroutine().state_tys(def_id, tcx);
-                    let Some(mut variant) = variants.nth(variant_index.into()) else {
-                        bug!(
-                            "variant_index of coroutine out of range: {:?}/{:?}",
-                            variant_index,
-                            args.as_coroutine().state_tys(def_id, tcx).count()
-                        );
-                    };
-                    return match variant.nth(field.index()) {
-                        Some(ty) => Ok(ty),
-                        None => Err(FieldAccessError::OutOfRange { field_count: variant.count() }),
-                    };
-                }
-                _ => bug!("can't have downcast of non-adt non-coroutine type"),
-            },
-            PlaceTy { ty, variant_index: None } => match *ty.kind() {
-                ty::Adt(adt_def, args) if !adt_def.is_enum() => {
-                    (adt_def.variant(FIRST_VARIANT), args)
-                }
-                ty::Closure(_, args) => {
-                    return match args.as_closure().upvar_tys().get(field.index()) {
-                        Some(&ty) => Ok(ty),
-                        None => Err(FieldAccessError::OutOfRange {
-                            field_count: args.as_closure().upvar_tys().len(),
-                        }),
-                    };
-                }
-                ty::CoroutineClosure(_, args) => {
-                    return match args.as_coroutine_closure().upvar_tys().get(field.index()) {
-                        Some(&ty) => Ok(ty),
-                        None => Err(FieldAccessError::OutOfRange {
-                            field_count: args.as_coroutine_closure().upvar_tys().len(),
-                        }),
-                    };
-                }
-                ty::Coroutine(_, args) => {
-                    // Only prefix fields (upvars and current state) are
-                    // accessible without a variant index.
-                    return match args.as_coroutine().prefix_tys().get(field.index()) {
-                        Some(ty) => Ok(*ty),
-                        None => Err(FieldAccessError::OutOfRange {
-                            field_count: args.as_coroutine().prefix_tys().len(),
-                        }),
-                    };
-                }
-                ty::Tuple(tys) => {
-                    return match tys.get(field.index()) {
-                        Some(&ty) => Ok(ty),
-                        None => Err(FieldAccessError::OutOfRange { field_count: tys.len() }),
-                    };
-                }
-                _ => {
-                    span_bug!(self.last_span, "can't project out of {:?}", base_ty);
-                }
-            },
-        };
-
-        if let Some(field) = variant.fields.get(field) {
-            Ok(self.typeck.normalize(field.ty(tcx, args), location))
-        } else {
-            Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
-        }
-    }
 }
 
 /// The MIR type checker. Visits the MIR and enforces all the
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 476e352ed92..db77017310a 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -5,6 +5,7 @@
 
 use rustc_hir as hir;
 use tracing::{debug, instrument};
+use ty::CoroutineArgsExt;
 
 use crate::mir::*;
 
@@ -25,29 +26,63 @@ impl<'tcx> PlaceTy<'tcx> {
         PlaceTy { ty, variant_index: None }
     }
 
-    /// `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`.)
+    /// `place_ty.field_ty(tcx, f)` computes the type of a given field.
+    ///
+    /// 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`.
     ///
     /// Note that the resulting type has not been normalized.
     #[instrument(level = "debug", skip(tcx), ret)]
     pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> {
-        match self.ty.kind() {
-            ty::Adt(adt_def, args) => {
-                let variant_def = match self.variant_index {
-                    None => adt_def.non_enum_variant(),
-                    Some(variant_index) => {
-                        assert!(adt_def.is_enum());
-                        adt_def.variant(variant_index)
-                    }
-                };
-                let field_def = &variant_def.fields[f];
-                field_def.ty(tcx, args)
+        if let Some(variant_index) = self.variant_index {
+            match *self.ty.kind() {
+                ty::Adt(adt_def, args) if adt_def.is_enum() => {
+                    adt_def.variant(variant_index).fields[f].ty(tcx, args)
+                }
+                ty::Coroutine(def_id, args) => {
+                    let mut variants = args.as_coroutine().state_tys(def_id, tcx);
+                    let Some(mut variant) = variants.nth(variant_index.into()) else {
+                        bug!("variant {variant_index:?} of coroutine out of range: {self:?}");
+                    };
+
+                    variant
+                        .nth(f.index())
+                        .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}"))
+                }
+                _ => bug!("can't downcast non-adt non-coroutine type: {self:?}"),
+            }
+        } else {
+            match self.ty.kind() {
+                ty::Adt(adt_def, args) if !adt_def.is_enum() => {
+                    adt_def.non_enum_variant().fields[f].ty(tcx, args)
+                }
+                ty::Closure(_, args) => args
+                    .as_closure()
+                    .upvar_tys()
+                    .get(f.index())
+                    .copied()
+                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
+                ty::CoroutineClosure(_, args) => args
+                    .as_coroutine_closure()
+                    .upvar_tys()
+                    .get(f.index())
+                    .copied()
+                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
+                // Only prefix fields (upvars and current state) are
+                // accessible without a variant index.
+                ty::Coroutine(_, args) => args
+                    .as_coroutine()
+                    .prefix_tys()
+                    .get(f.index())
+                    .copied()
+                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
+                ty::Tuple(tys) => tys
+                    .get(f.index())
+                    .copied()
+                    .unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
+                _ => bug!("can't project out of {self:?}"),
             }
-            ty::Tuple(tys) => tys[f.index()],
-            _ => bug!("extracting field of non-tuple non-adt: {:?}", self),
         }
     }