merge PlaceTy field_ty computation
This commit is contained in:
parent
809f55d66a
commit
51cd03a127
2 changed files with 65 additions and 123 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue