change is_subtype to relate_types

This commit is contained in:
ouz-a 2023-09-30 13:44:31 +03:00
parent cd7f471931
commit 6f0c5ee2d4
15 changed files with 128 additions and 86 deletions

View file

@ -716,14 +716,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
PlaceTy::from_ty(fty)
}
ProjectionElem::Subtype(_) => {
let guard = span_mirbug_and_err!(
self,
place,
"ProjectionElem::Subtype shouldn't exist in borrowck"
);
PlaceTy::from_ty(Ty::new_error(tcx, guard))
}
ProjectionElem::Subtype(_) => PlaceTy::from_ty(Ty::new_error_with_message(
tcx,
self.last_span,
"ProjectionElem::Subtype shouldn't exist in borrowck",
)),
ProjectionElem::OpaqueCast(ty) => {
let ty = self.sanitize_type(place, ty);
let ty = self.cx.normalize(ty, location);
@ -2564,7 +2561,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
ProjectionElem::Field(..)
| ProjectionElem::Subtype(..)
| ProjectionElem::Downcast(..)
| ProjectionElem::OpaqueCast(..)
| ProjectionElem::Index(..)
@ -2572,6 +2568,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| ProjectionElem::Subslice { .. } => {
// other field access
}
ProjectionElem::Subtype(_) => {
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
}
}
}
}

View file

@ -876,7 +876,7 @@ pub(crate) fn codegen_place<'tcx>(
cplace = cplace.place_deref(fx);
}
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, ty),
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)),
PlaceElem::Field(field, _ty) => {
cplace = cplace.place_field(fx, field);
}

View file

@ -674,12 +674,14 @@ impl<'tcx> CPlace<'tcx> {
}
}
/// Used for `ProjectionElem::Subtype`, ty has to be monomorphized before
/// passed on.
pub(crate) fn place_transmute_type(
self,
fx: &mut FunctionCx<'_, '_, 'tcx>,
ty: Ty<'tcx>,
) -> CPlace<'tcx> {
CPlace { inner: self.inner, layout: fx.layout_of(fx.monomorphize(ty)) }
CPlace { inner: self.inner, layout: fx.layout_of(ty) }
}
pub(crate) fn place_field(

View file

@ -13,7 +13,7 @@ use rustc_middle::ty::layout::{
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
TyAndLayout,
};
use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance};
use rustc_mir_dataflow::storage::always_storage_live_locals;
use rustc_session::Limit;
use rustc_span::Span;
@ -384,7 +384,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
// all normal lifetimes are erased, higher-ranked types with their
// late-bound lifetimes are still around and can lead to type
// differences.
if util::is_subtype(tcx, param_env, src.ty, dest.ty) {
if util::relate_types(tcx, param_env, Variance::Covariant, src.ty, dest.ty) {
// Make sure the layout is equal, too -- just to be safe. Miri really
// needs layout equality. For performance reason we skip this check when
// the types are equal. Equal types *can* have different layouts when

View file

@ -7,7 +7,7 @@ use rustc_infer::traits::Reveal;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance};
use rustc_mir_dataflow::impls::MaybeStorageLive;
use rustc_mir_dataflow::storage::always_storage_live_locals;
use rustc_mir_dataflow::{Analysis, ResultsCursor};
@ -16,7 +16,7 @@ use rustc_target::spec::abi::Abi;
use crate::util::is_within_packed;
use crate::util::is_subtype;
use crate::util::relate_types;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum EdgeKind {
@ -604,7 +604,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
return true;
}
return crate::util::is_subtype(self.tcx, self.param_env, src, dest);
// After borrowck subtyping should be fully explicit via
// `Subtype` projections.
let variance = if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
Variance::Invariant
} else {
Variance::Covariant
};
crate::util::relate_types(self.tcx, self.param_env, variance, src, dest)
}
}
@ -756,9 +764,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
ProjectionElem::Subtype(ty) => {
if !is_subtype(
if !relate_types(
self.tcx,
self.param_env,
Variance::Covariant,
ty,
place_ref.ty(&self.body.local_decls, self.tcx).ty,
) {

View file

@ -5,7 +5,7 @@
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::traits::{DefiningAnchor, ObligationCause};
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance};
use rustc_trait_selection::traits::ObligationCtxt;
/// Returns whether the two types are equal up to subtyping.
@ -24,16 +24,22 @@ pub fn is_equal_up_to_subtyping<'tcx>(
}
// Check for subtyping in either direction.
is_subtype(tcx, param_env, src, dest) || is_subtype(tcx, param_env, dest, src)
relate_types(tcx, param_env, Variance::Covariant, src, dest)
|| relate_types(tcx, param_env, Variance::Covariant, dest, src)
}
/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
///
/// For almost all of the use cases variance should be `Covariant`,
/// in `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial` variance should
/// be `Invariant`.
///
/// This mostly ignores opaque types as it can be used in constraining contexts
/// while still computing the final underlying type.
pub fn is_subtype<'tcx>(
pub fn relate_types<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
variance: Variance,
src: Ty<'tcx>,
dest: Ty<'tcx>,
) -> bool {
@ -48,7 +54,7 @@ pub fn is_subtype<'tcx>(
let cause = ObligationCause::dummy();
let src = ocx.normalize(&cause, param_env, src);
let dest = ocx.normalize(&cause, param_env, dest);
match ocx.sub(&cause, param_env, src, dest) {
match ocx.relate(&cause, param_env, variance, src, dest) {
Ok(()) => {}
Err(_) => return false,
};

View file

@ -7,7 +7,7 @@ mod type_name;
pub use self::alignment::{is_disaligned, is_within_packed};
pub use self::check_validity_requirement::check_validity_requirement;
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
pub use self::compare_types::{is_equal_up_to_subtyping, relate_types};
pub use self::type_name::type_name;
/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the

View file

@ -218,7 +218,13 @@ impl<'tcx> Inliner<'tcx> {
// Normally, this shouldn't be required, but trait normalization failure can create a
// validation ICE.
let output_type = callee_body.return_ty();
if !util::is_subtype(self.tcx, self.param_env, output_type, destination_ty) {
if !util::relate_types(
self.tcx,
self.param_env,
ty::Variance::Covariant,
output_type,
destination_ty,
) {
trace!(?output_type, ?destination_ty);
return Err("failed to normalize return type");
}
@ -248,7 +254,13 @@ impl<'tcx> Inliner<'tcx> {
self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
{
let input_type = callee_body.local_decls[input].ty;
if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
if !util::relate_types(
self.tcx,
self.param_env,
ty::Variance::Covariant,
input_type,
arg_ty,
) {
trace!(?arg_ty, ?input_type);
return Err("failed to normalize tuple argument type");
}
@ -257,7 +269,13 @@ impl<'tcx> Inliner<'tcx> {
for (arg, input) in args.iter().zip(callee_body.args_iter()) {
let input_type = callee_body.local_decls[input].ty;
let arg_ty = arg.ty(&caller_body.local_decls, self.tcx);
if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
if !util::relate_types(
self.tcx,
self.param_env,
ty::Variance::Covariant,
input_type,
arg_ty,
) {
trace!(?arg_ty, ?input_type);
return Err("failed to normalize argument type");
}

View file

@ -23,6 +23,7 @@ use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::Variance;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::TraitSolver;
@ -156,6 +157,20 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
pub fn relate<T: ToTrace<'tcx>>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
variance: Variance,
expected: T,
actual: T,
) -> Result<(), TypeError<'tcx>> {
self.infcx
.at(cause, param_env)
.relate(DefineOpaqueTypes::Yes, expected, variance, actual)
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
/// Checks whether `expected` is a supertype of `actual`: `expected :> actual`.
pub fn sup<T: ToTrace<'tcx>>(
&self,