Skip to content

Commit feabbf0

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

File tree

2 files changed

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

2 files changed

+66
-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

+54-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,64 @@ 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 at a given field.
30+
/// This may be used for everything supported by const evaluation.
31+
///
32+
/// Most clients of `PlaceTy` can instead just extract the relevant type
33+
/// directly from their `PlaceElem`, but some instances of `ProjectionElem<V, T>`
34+
/// do not carry a `Ty` for `T`.
3335
///
3436
/// Note that the resulting type has not been normalized.
3537
#[instrument(level = "debug", skip(tcx), ret)]
3638
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)
39+
if let Some(variant_index) = self.variant_index {
40+
match *self.ty.kind() {
41+
ty::Adt(adt_def, args) if adt_def.is_enum() => {
42+
adt_def.variant(variant_index).fields[f].ty(tcx, args)
43+
}
44+
ty::Coroutine(def_id, args) => {
45+
let mut variants = args.as_coroutine().state_tys(def_id, tcx);
46+
let Some(mut variant) = variants.nth(variant_index.into()) else {
47+
bug!("variant {variant_index:?} of coroutine out of range: {self:?}");
48+
};
49+
50+
variant
51+
.nth(f.index())
52+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}"))
53+
}
54+
_ => bug!("can't downcast non-adt non-coroutine type: {self:?}"),
55+
}
56+
} else {
57+
match self.ty.kind() {
58+
ty::Adt(adt_def, args) if !adt_def.is_enum() => {
59+
adt_def.non_enum_variant().fields[f].ty(tcx, args)
60+
}
61+
ty::Closure(_, args) => args
62+
.as_closure()
63+
.upvar_tys()
64+
.get(f.index())
65+
.copied()
66+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
67+
ty::CoroutineClosure(_, args) => args
68+
.as_coroutine_closure()
69+
.upvar_tys()
70+
.get(f.index())
71+
.copied()
72+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
73+
// Only prefix fields (upvars and current state) are
74+
// accessible without a variant index.
75+
ty::Coroutine(_, args) => args
76+
.as_coroutine()
77+
.prefix_tys()
78+
.get(f.index())
79+
.copied()
80+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
81+
ty::Tuple(tys) => tys
82+
.get(f.index())
83+
.copied()
84+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
85+
_ => bug!("can't project out of {self:?}"),
4886
}
49-
ty::Tuple(tys) => tys[f.index()],
50-
_ => bug!("extracting field of non-tuple non-adt: {:?}", self),
5187
}
5288
}
5389

0 commit comments

Comments
 (0)