Auto merge of #134465 - lcnr:type-verifier, r=compiler-errors

cleanup `TypeVerifier`

We should merge it with the `TypeChecker` as we no longer bail in cases where it encounters an error since #111863.

It's quite inconsistent whether a check lives in the verifier or the `TypeChecker`, so this feels like a quite impactful cleanup. I expect that for this we may want to change the `TypeChecker` to also be a MIR visitor 🤔 this is non-trivial so I didn't fully do it in this PR.

Best reviewed commit by commit.

r? `@compiler-errors` feel free to reassign however
This commit is contained in:
bors
2024-12-23 04:15:41 +00:00
3 changed files with 159 additions and 342 deletions

View File

@@ -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),
}
}

View File

@@ -1361,12 +1361,12 @@ pub enum PlaceContext {
impl PlaceContext {
/// Returns `true` if this place context represents a drop.
#[inline]
pub fn is_drop(&self) -> bool {
pub fn is_drop(self) -> bool {
matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
}
/// Returns `true` if this place context represents a borrow.
pub fn is_borrow(&self) -> bool {
pub fn is_borrow(self) -> bool {
matches!(
self,
PlaceContext::NonMutatingUse(
@@ -1376,7 +1376,7 @@ impl PlaceContext {
}
/// Returns `true` if this place context represents an address-of.
pub fn is_address_of(&self) -> bool {
pub fn is_address_of(self) -> bool {
matches!(
self,
PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow)
@@ -1386,7 +1386,7 @@ impl PlaceContext {
/// Returns `true` if this place context represents a storage live or storage dead marker.
#[inline]
pub fn is_storage_marker(&self) -> bool {
pub fn is_storage_marker(self) -> bool {
matches!(
self,
PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
@@ -1395,18 +1395,18 @@ impl PlaceContext {
/// Returns `true` if this place context represents a use that potentially changes the value.
#[inline]
pub fn is_mutating_use(&self) -> bool {
pub fn is_mutating_use(self) -> bool {
matches!(self, PlaceContext::MutatingUse(..))
}
/// Returns `true` if this place context represents a use.
#[inline]
pub fn is_use(&self) -> bool {
pub fn is_use(self) -> bool {
!matches!(self, PlaceContext::NonUse(..))
}
/// Returns `true` if this place context represents an assignment statement.
pub fn is_place_assignment(&self) -> bool {
pub fn is_place_assignment(self) -> bool {
matches!(
self,
PlaceContext::MutatingUse(
@@ -1416,4 +1416,19 @@ impl PlaceContext {
)
)
}
/// The variance of a place in the given context.
pub fn ambient_variance(self) -> ty::Variance {
use NonMutatingUseContext::*;
use NonUseContext::*;
match self {
PlaceContext::MutatingUse(_) => ty::Invariant,
PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
PlaceContext::NonMutatingUse(
Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | RawBorrow
| Projection,
) => ty::Covariant,
PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
}
}
}