mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Extract trait_refs_are_compatible, make it instantiate binders
This commit is contained in:
parent
af3f212453
commit
d87e0ca497
@ -9,12 +9,13 @@ use rustc_infer::infer::canonical::{
|
|||||||
Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
|
Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
|
||||||
};
|
};
|
||||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError};
|
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace};
|
||||||
use rustc_macros::extension;
|
use rustc_macros::extension;
|
||||||
use rustc_middle::arena::ArenaAllocatable;
|
use rustc_middle::arena::ArenaAllocatable;
|
||||||
use rustc_middle::traits::query::NoSolution;
|
use rustc_middle::traits::query::NoSolution;
|
||||||
use rustc_middle::ty::error::TypeError;
|
use rustc_middle::ty::error::TypeError;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance};
|
||||||
|
use rustc_type_ir::relate::Relate;
|
||||||
|
|
||||||
use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine};
|
use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine};
|
||||||
use crate::error_reporting::InferCtxtErrorExt;
|
use crate::error_reporting::InferCtxtErrorExt;
|
||||||
@ -133,6 +134,20 @@ where
|
|||||||
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
|
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn eq_trace<T: Relate<TyCtxt<'tcx>>>(
|
||||||
|
&self,
|
||||||
|
cause: &ObligationCause<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
trace: TypeTrace<'tcx>,
|
||||||
|
expected: T,
|
||||||
|
actual: T,
|
||||||
|
) -> Result<(), TypeError<'tcx>> {
|
||||||
|
self.infcx
|
||||||
|
.at(cause, param_env)
|
||||||
|
.eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual)
|
||||||
|
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks whether `expected` is a subtype of `actual`: `expected <: actual`.
|
/// Checks whether `expected` is a subtype of `actual`: `expected <: actual`.
|
||||||
pub fn sub<T: ToTrace<'tcx>>(
|
pub fn sub<T: ToTrace<'tcx>>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -2,6 +2,7 @@ use std::fmt::Debug;
|
|||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_infer::infer::at::ToTrace;
|
||||||
use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt};
|
use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::ObligationCause;
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_infer::traits::util::PredicateSet;
|
use rustc_infer::traits::util::PredicateSet;
|
||||||
@ -24,6 +25,8 @@ pub enum VtblSegment<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare the segments for a vtable
|
/// Prepare the segments for a vtable
|
||||||
|
// FIXME: This should take a `PolyExistentialTraitRef`, since we don't care
|
||||||
|
// about our `Self` type here.
|
||||||
pub fn prepare_vtable_segments<'tcx, T>(
|
pub fn prepare_vtable_segments<'tcx, T>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
@ -385,7 +388,7 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
|
|||||||
let ty::Dynamic(target, _, _) = *target.kind() else {
|
let ty::Dynamic(target, _, _) = *target.kind() else {
|
||||||
bug!();
|
bug!();
|
||||||
};
|
};
|
||||||
let target_principal = target.principal()?.with_self_ty(tcx, tcx.types.trait_object_dummy_self);
|
let target_principal = target.principal()?;
|
||||||
|
|
||||||
// Given that we have a target principal, it is a bug for there not to be a source principal.
|
// Given that we have a target principal, it is a bug for there not to be a source principal.
|
||||||
let ty::Dynamic(source, _, _) = *source.kind() else {
|
let ty::Dynamic(source, _, _) = *source.kind() else {
|
||||||
@ -394,29 +397,6 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
|
|||||||
let source_principal =
|
let source_principal =
|
||||||
source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
|
source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
|
||||||
|
|
||||||
let infcx = tcx.infer_ctxt().build();
|
|
||||||
let param_env = ty::ParamEnv::reveal_all();
|
|
||||||
let trait_refs_are_compatible =
|
|
||||||
|source: ty::PolyTraitRef<'tcx>, target: ty::PolyTraitRef<'tcx>| {
|
|
||||||
infcx.probe(|_| {
|
|
||||||
let ocx = ObligationCtxt::new(&infcx);
|
|
||||||
let source = ocx.normalize(&ObligationCause::dummy(), param_env, source);
|
|
||||||
let target = ocx.normalize(&ObligationCause::dummy(), param_env, target);
|
|
||||||
infcx.enter_forall(target, |target| {
|
|
||||||
let source = infcx.instantiate_binder_with_fresh_vars(
|
|
||||||
DUMMY_SP,
|
|
||||||
BoundRegionConversionTime::HigherRankedType,
|
|
||||||
source,
|
|
||||||
);
|
|
||||||
let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, target, source)
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
ocx.select_all_or_error().is_empty()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let vtable_segment_callback = {
|
let vtable_segment_callback = {
|
||||||
let mut vptr_offset = 0;
|
let mut vptr_offset = 0;
|
||||||
move |segment| {
|
move |segment| {
|
||||||
@ -424,9 +404,15 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
|
|||||||
VtblSegment::MetadataDSA => {
|
VtblSegment::MetadataDSA => {
|
||||||
vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
|
vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
|
||||||
}
|
}
|
||||||
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
|
VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
|
||||||
vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len();
|
vptr_offset +=
|
||||||
if trait_refs_are_compatible(trait_ref, target_principal) {
|
tcx.own_existential_vtable_entries(vtable_principal.def_id()).len();
|
||||||
|
if trait_refs_are_compatible(
|
||||||
|
tcx,
|
||||||
|
vtable_principal
|
||||||
|
.map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)),
|
||||||
|
target_principal,
|
||||||
|
) {
|
||||||
if emit_vptr {
|
if emit_vptr {
|
||||||
return ControlFlow::Break(Some(vptr_offset));
|
return ControlFlow::Break(Some(vptr_offset));
|
||||||
} else {
|
} else {
|
||||||
@ -446,6 +432,41 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
|
|||||||
prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
|
prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn trait_refs_are_compatible<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
hr_vtable_principal: ty::PolyExistentialTraitRef<'tcx>,
|
||||||
|
hr_target_principal: ty::PolyExistentialTraitRef<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
if hr_vtable_principal.def_id() != hr_target_principal.def_id() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let infcx = tcx.infer_ctxt().build();
|
||||||
|
let param_env = ty::ParamEnv::reveal_all();
|
||||||
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
|
let hr_source_principal =
|
||||||
|
ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal);
|
||||||
|
let hr_target_principal =
|
||||||
|
ocx.normalize(&ObligationCause::dummy(), param_env, hr_target_principal);
|
||||||
|
infcx.enter_forall(hr_target_principal, |target_principal| {
|
||||||
|
let source_principal = infcx.instantiate_binder_with_fresh_vars(
|
||||||
|
DUMMY_SP,
|
||||||
|
BoundRegionConversionTime::HigherRankedType,
|
||||||
|
hr_source_principal,
|
||||||
|
);
|
||||||
|
let Ok(()) = ocx.eq_trace(
|
||||||
|
&ObligationCause::dummy(),
|
||||||
|
param_env,
|
||||||
|
ToTrace::to_trace(&ObligationCause::dummy(), hr_target_principal, hr_source_principal),
|
||||||
|
target_principal,
|
||||||
|
source_principal,
|
||||||
|
) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
ocx.select_all_or_error().is_empty()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn provide(providers: &mut Providers) {
|
pub(super) fn provide(providers: &mut Providers) {
|
||||||
*providers = Providers {
|
*providers = Providers {
|
||||||
own_existential_vtable_entries,
|
own_existential_vtable_entries,
|
||||||
|
Loading…
Reference in New Issue
Block a user