Skip to content

Commit 51cd03a

Browse files
committed
merge PlaceTy field_ty computation
1 parent 809f55d commit 51cd03a

File tree

2 files changed

+65
-123
lines changed
  • compiler
    • rustc_borrowck/src/type_check
    • rustc_middle/src/mir

2 files changed

+65
-123
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+12-105
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::rc::Rc;
44
use std::{fmt, iter, mem};
55

6-
use rustc_abi::{FIRST_VARIANT, FieldIdx};
6+
use rustc_abi::FieldIdx;
77
use rustc_data_structures::frozen::Frozen;
88
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
99
use rustc_errors::ErrorGuaranteed;
@@ -273,35 +273,18 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
273273
| ProjectionElem::Downcast(..) => {}
274274
ProjectionElem::Field(field, fty) => {
275275
let fty = self.typeck.normalize(fty, location);
276-
match self.expected_field_ty(base_ty, field, location) {
277-
Ok(ty) => {
278-
let ty = self.typeck.normalize(ty, location);
279-
debug!(?fty, ?ty);
276+
let ty = base_ty.field_ty(tcx, field);
277+
let ty = self.typeck.normalize(ty, location);
278+
debug!(?fty, ?ty);
280279

281-
if let Err(terr) = self.typeck.relate_types(
282-
ty,
283-
context.ambient_variance(),
284-
fty,
285-
location.to_locations(),
286-
ConstraintCategory::Boring,
287-
) {
288-
span_mirbug!(
289-
self,
290-
place,
291-
"bad field access ({:?}: {:?}): {:?}",
292-
ty,
293-
fty,
294-
terr
295-
);
296-
}
297-
}
298-
Err(FieldAccessError::OutOfRange { field_count }) => span_mirbug!(
299-
self,
300-
place,
301-
"accessed field #{} but variant only has {}",
302-
field.index(),
303-
field_count
304-
),
280+
if let Err(terr) = self.typeck.relate_types(
281+
ty,
282+
context.ambient_variance(),
283+
fty,
284+
location.to_locations(),
285+
ConstraintCategory::Boring,
286+
) {
287+
span_mirbug!(self, place, "bad field access ({:?}: {:?}): {:?}", ty, fty, terr);
305288
}
306289
}
307290
ProjectionElem::OpaqueCast(ty) => {
@@ -589,82 +572,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
589572
self.typeck.constraints.liveness_constraints.add_location(region, location);
590573
}
591574
}
592-
593-
fn expected_field_ty(
594-
&mut self,
595-
base_ty: PlaceTy<'tcx>,
596-
field: FieldIdx,
597-
location: Location,
598-
) -> Result<Ty<'tcx>, FieldAccessError> {
599-
let tcx = self.tcx();
600-
601-
let (variant, args) = match base_ty {
602-
PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() {
603-
ty::Adt(adt_def, args) => (adt_def.variant(variant_index), args),
604-
ty::Coroutine(def_id, args) => {
605-
let mut variants = args.as_coroutine().state_tys(def_id, tcx);
606-
let Some(mut variant) = variants.nth(variant_index.into()) else {
607-
bug!(
608-
"variant_index of coroutine out of range: {:?}/{:?}",
609-
variant_index,
610-
args.as_coroutine().state_tys(def_id, tcx).count()
611-
);
612-
};
613-
return match variant.nth(field.index()) {
614-
Some(ty) => Ok(ty),
615-
None => Err(FieldAccessError::OutOfRange { field_count: variant.count() }),
616-
};
617-
}
618-
_ => bug!("can't have downcast of non-adt non-coroutine type"),
619-
},
620-
PlaceTy { ty, variant_index: None } => match *ty.kind() {
621-
ty::Adt(adt_def, args) if !adt_def.is_enum() => {
622-
(adt_def.variant(FIRST_VARIANT), args)
623-
}
624-
ty::Closure(_, args) => {
625-
return match args.as_closure().upvar_tys().get(field.index()) {
626-
Some(&ty) => Ok(ty),
627-
None => Err(FieldAccessError::OutOfRange {
628-
field_count: args.as_closure().upvar_tys().len(),
629-
}),
630-
};
631-
}
632-
ty::CoroutineClosure(_, args) => {
633-
return match args.as_coroutine_closure().upvar_tys().get(field.index()) {
634-
Some(&ty) => Ok(ty),
635-
None => Err(FieldAccessError::OutOfRange {
636-
field_count: args.as_coroutine_closure().upvar_tys().len(),
637-
}),
638-
};
639-
}
640-
ty::Coroutine(_, args) => {
641-
// Only prefix fields (upvars and current state) are
642-
// accessible without a variant index.
643-
return match args.as_coroutine().prefix_tys().get(field.index()) {
644-
Some(ty) => Ok(*ty),
645-
None => Err(FieldAccessError::OutOfRange {
646-
field_count: args.as_coroutine().prefix_tys().len(),
647-
}),
648-
};
649-
}
650-
ty::Tuple(tys) => {
651-
return match tys.get(field.index()) {
652-
Some(&ty) => Ok(ty),
653-
None => Err(FieldAccessError::OutOfRange { field_count: tys.len() }),
654-
};
655-
}
656-
_ => {
657-
span_bug!(self.last_span, "can't project out of {:?}", base_ty);
658-
}
659-
},
660-
};
661-
662-
if let Some(field) = variant.fields.get(field) {
663-
Ok(self.typeck.normalize(field.ty(tcx, args), location))
664-
} else {
665-
Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
666-
}
667-
}
668575
}
669576

670577
/// The MIR type checker. Visits the MIR and enforces all the

compiler/rustc_middle/src/mir/tcx.rs

+53-18
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
use rustc_hir as hir;
77
use tracing::{debug, instrument};
8+
use ty::CoroutineArgsExt;
89

910
use crate::mir::*;
1011

@@ -25,29 +26,63 @@ impl<'tcx> PlaceTy<'tcx> {
2526
PlaceTy { ty, variant_index: None }
2627
}
2728

28-
/// `place_ty.field_ty(tcx, f)` computes the type at a given field
29-
/// of a record or enum-variant. (Most clients of `PlaceTy` can
30-
/// instead just extract the relevant type directly from their
31-
/// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do
32-
/// not carry a `Ty` for `T`.)
29+
/// `place_ty.field_ty(tcx, f)` computes the type of a given field.
30+
///
31+
/// Most clients of `PlaceTy` can instead just extract the relevant type
32+
/// directly from their `PlaceElem`, but some instances of `ProjectionElem<V, T>`
33+
/// do not carry a `Ty` for `T`.
3334
///
3435
/// Note that the resulting type has not been normalized.
3536
#[instrument(level = "debug", skip(tcx), ret)]
3637
pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> {
37-
match self.ty.kind() {
38-
ty::Adt(adt_def, args) => {
39-
let variant_def = match self.variant_index {
40-
None => adt_def.non_enum_variant(),
41-
Some(variant_index) => {
42-
assert!(adt_def.is_enum());
43-
adt_def.variant(variant_index)
44-
}
45-
};
46-
let field_def = &variant_def.fields[f];
47-
field_def.ty(tcx, args)
38+
if let Some(variant_index) = self.variant_index {
39+
match *self.ty.kind() {
40+
ty::Adt(adt_def, args) if adt_def.is_enum() => {
41+
adt_def.variant(variant_index).fields[f].ty(tcx, args)
42+
}
43+
ty::Coroutine(def_id, args) => {
44+
let mut variants = args.as_coroutine().state_tys(def_id, tcx);
45+
let Some(mut variant) = variants.nth(variant_index.into()) else {
46+
bug!("variant {variant_index:?} of coroutine out of range: {self:?}");
47+
};
48+
49+
variant
50+
.nth(f.index())
51+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}"))
52+
}
53+
_ => bug!("can't downcast non-adt non-coroutine type: {self:?}"),
54+
}
55+
} else {
56+
match self.ty.kind() {
57+
ty::Adt(adt_def, args) if !adt_def.is_enum() => {
58+
adt_def.non_enum_variant().fields[f].ty(tcx, args)
59+
}
60+
ty::Closure(_, args) => args
61+
.as_closure()
62+
.upvar_tys()
63+
.get(f.index())
64+
.copied()
65+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
66+
ty::CoroutineClosure(_, args) => args
67+
.as_coroutine_closure()
68+
.upvar_tys()
69+
.get(f.index())
70+
.copied()
71+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
72+
// Only prefix fields (upvars and current state) are
73+
// accessible without a variant index.
74+
ty::Coroutine(_, args) => args
75+
.as_coroutine()
76+
.prefix_tys()
77+
.get(f.index())
78+
.copied()
79+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
80+
ty::Tuple(tys) => tys
81+
.get(f.index())
82+
.copied()
83+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
84+
_ => bug!("can't project out of {self:?}"),
4885
}
49-
ty::Tuple(tys) => tys[f.index()],
50-
_ => bug!("extracting field of non-tuple non-adt: {:?}", self),
5186
}
5287
}
5388

0 commit comments

Comments
 (0)