Do not treat vtable supertraits as distinct when bound with different bound vars
This commit is contained in:
parent
37a430e6ea
commit
fdc4bd22b7
18 changed files with 146 additions and 115 deletions
|
@ -2,8 +2,8 @@ use std::fmt::Debug;
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::infer::at::ToTrace;
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_infer::traits::util::PredicateSet;
|
||||
use rustc_middle::bug;
|
||||
|
@ -20,7 +20,7 @@ use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum VtblSegment<'tcx> {
|
||||
MetadataDSA,
|
||||
TraitOwnEntries { trait_ref: ty::PolyTraitRef<'tcx>, emit_vptr: bool },
|
||||
TraitOwnEntries { trait_ref: ty::TraitRef<'tcx>, emit_vptr: bool },
|
||||
}
|
||||
|
||||
/// Prepare the segments for a vtable
|
||||
|
@ -28,7 +28,7 @@ pub enum VtblSegment<'tcx> {
|
|||
// about our `Self` type here.
|
||||
pub fn prepare_vtable_segments<'tcx, T>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
|
||||
) -> Option<T> {
|
||||
prepare_vtable_segments_inner(tcx, trait_ref, segment_visitor).break_value()
|
||||
|
@ -38,7 +38,7 @@ pub fn prepare_vtable_segments<'tcx, T>(
|
|||
/// such that we can use `?` in the body.
|
||||
fn prepare_vtable_segments_inner<'tcx, T>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
|
||||
) -> ControlFlow<T> {
|
||||
// The following constraints holds for the final arrangement.
|
||||
|
@ -91,7 +91,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
|
|||
let mut emit_vptr_on_new_entry = false;
|
||||
let mut visited = PredicateSet::new(tcx);
|
||||
let predicate = trait_ref.upcast(tcx);
|
||||
let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
|
||||
let mut stack: SmallVec<[(ty::TraitRef<'tcx>, _, _); 5]> =
|
||||
smallvec![(trait_ref, emit_vptr_on_new_entry, maybe_iter(None))];
|
||||
visited.insert(predicate);
|
||||
|
||||
|
@ -124,10 +124,19 @@ fn prepare_vtable_segments_inner<'tcx, T>(
|
|||
let &(inner_most_trait_ref, _, _) = stack.last().unwrap();
|
||||
|
||||
let mut direct_super_traits_iter = tcx
|
||||
.explicit_super_predicates_of(inner_most_trait_ref.def_id())
|
||||
.explicit_super_predicates_of(inner_most_trait_ref.def_id)
|
||||
.iter_identity_copied()
|
||||
.filter_map(move |(pred, _)| {
|
||||
pred.instantiate_supertrait(tcx, inner_most_trait_ref).as_trait_clause()
|
||||
Some(
|
||||
tcx.instantiate_bound_regions_with_erased(
|
||||
pred.instantiate_supertrait(
|
||||
tcx,
|
||||
ty::Binder::dummy(inner_most_trait_ref),
|
||||
)
|
||||
.as_trait_clause()?,
|
||||
)
|
||||
.trait_ref,
|
||||
)
|
||||
});
|
||||
|
||||
// Find an unvisited supertrait
|
||||
|
@ -135,16 +144,11 @@ fn prepare_vtable_segments_inner<'tcx, T>(
|
|||
.find(|&super_trait| visited.insert(super_trait.upcast(tcx)))
|
||||
{
|
||||
// Push it to the stack for the next iteration of 'diving_in to pick up
|
||||
Some(unvisited_super_trait) => {
|
||||
// We're throwing away potential constness of super traits here.
|
||||
// FIXME: handle ~const super traits
|
||||
let next_super_trait = unvisited_super_trait.map_bound(|t| t.trait_ref);
|
||||
stack.push((
|
||||
next_super_trait,
|
||||
emit_vptr_on_new_entry,
|
||||
maybe_iter(Some(direct_super_traits_iter)),
|
||||
))
|
||||
}
|
||||
Some(next_super_trait) => stack.push((
|
||||
next_super_trait,
|
||||
emit_vptr_on_new_entry,
|
||||
maybe_iter(Some(direct_super_traits_iter)),
|
||||
)),
|
||||
|
||||
// There are no more unvisited direct super traits, dive-in finished
|
||||
None => break 'diving_in,
|
||||
|
@ -153,8 +157,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
|
|||
|
||||
// emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
|
||||
while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() {
|
||||
let has_entries =
|
||||
has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id());
|
||||
let has_entries = has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id);
|
||||
|
||||
segment_visitor(VtblSegment::TraitOwnEntries {
|
||||
trait_ref: inner_most_trait_ref,
|
||||
|
@ -168,11 +171,6 @@ fn prepare_vtable_segments_inner<'tcx, T>(
|
|||
if let Some(next_inner_most_trait_ref) =
|
||||
siblings.find(|&sibling| visited.insert(sibling.upcast(tcx)))
|
||||
{
|
||||
// We're throwing away potential constness of super traits here.
|
||||
// FIXME: handle ~const super traits
|
||||
let next_inner_most_trait_ref =
|
||||
next_inner_most_trait_ref.map_bound(|t| t.trait_ref);
|
||||
|
||||
stack.push((next_inner_most_trait_ref, emit_vptr_on_new_entry, siblings));
|
||||
|
||||
// just pushed a new trait onto the stack, so we need to go through its super traits
|
||||
|
@ -229,7 +227,7 @@ fn own_existential_vtable_entries_iter(
|
|||
/// that come from `trait_ref`, including its supertraits.
|
||||
fn vtable_entries<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> &'tcx [VtblEntry<'tcx>] {
|
||||
debug!("vtable_entries({:?})", trait_ref);
|
||||
|
||||
|
@ -241,33 +239,26 @@ fn vtable_entries<'tcx>(
|
|||
entries.extend(TyCtxt::COMMON_VTABLE_ENTRIES);
|
||||
}
|
||||
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
|
||||
let existential_trait_ref = trait_ref
|
||||
.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
|
||||
let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref);
|
||||
|
||||
// Lookup the shape of vtable for the trait.
|
||||
let own_existential_entries =
|
||||
tcx.own_existential_vtable_entries(existential_trait_ref.def_id());
|
||||
tcx.own_existential_vtable_entries(existential_trait_ref.def_id);
|
||||
|
||||
let own_entries = own_existential_entries.iter().copied().map(|def_id| {
|
||||
debug!("vtable_entries: trait_method={:?}", def_id);
|
||||
|
||||
// The method may have some early-bound lifetimes; add regions for those.
|
||||
let args = trait_ref.map_bound(|trait_ref| {
|
||||
// FIXME: Is this normalize needed?
|
||||
let args = tcx.normalize_erasing_regions(
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
GenericArgs::for_item(tcx, def_id, |param, _| match param.kind {
|
||||
GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
|
||||
GenericParamDefKind::Type { .. }
|
||||
| GenericParamDefKind::Const { .. } => {
|
||||
trait_ref.args[param.index as usize]
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// The trait type may have higher-ranked lifetimes in it;
|
||||
// erase them if they appear, so that we get the type
|
||||
// at some particular call site.
|
||||
let args = tcx.normalize_erasing_late_bound_regions(
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
args,
|
||||
}),
|
||||
);
|
||||
|
||||
// It's possible that the method relies on where-clauses that
|
||||
|
@ -318,10 +309,11 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
|
|||
let ty::Dynamic(source, _, _) = *key.self_ty().kind() else {
|
||||
bug!();
|
||||
};
|
||||
let source_principal =
|
||||
source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
|
||||
let source_principal = tcx.instantiate_bound_regions_with_erased(
|
||||
source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self),
|
||||
);
|
||||
|
||||
let target_principal = ty::Binder::dummy(ty::ExistentialTraitRef::erase_self_ty(tcx, key));
|
||||
let target_principal = ty::ExistentialTraitRef::erase_self_ty(tcx, key);
|
||||
|
||||
let vtable_segment_callback = {
|
||||
let mut vptr_offset = 0;
|
||||
|
@ -333,15 +325,14 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
|
|||
VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
|
||||
if trait_refs_are_compatible(
|
||||
tcx,
|
||||
vtable_principal
|
||||
.map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)),
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal),
|
||||
target_principal,
|
||||
) {
|
||||
return ControlFlow::Break(vptr_offset);
|
||||
}
|
||||
|
||||
vptr_offset +=
|
||||
tcx.own_existential_vtable_entries(vtable_principal.def_id()).len();
|
||||
tcx.own_existential_vtable_entries(vtable_principal.def_id).len();
|
||||
|
||||
if emit_vptr {
|
||||
vptr_offset += 1;
|
||||
|
@ -373,14 +364,15 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
|
|||
let ty::Dynamic(target, _, _) = *target.kind() else {
|
||||
bug!();
|
||||
};
|
||||
let target_principal = target.principal()?;
|
||||
let target_principal = tcx.instantiate_bound_regions_with_erased(target.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 {
|
||||
bug!();
|
||||
};
|
||||
let source_principal =
|
||||
source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
|
||||
let source_principal = tcx.instantiate_bound_regions_with_erased(
|
||||
source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self),
|
||||
);
|
||||
|
||||
let vtable_segment_callback = {
|
||||
let mut vptr_offset = 0;
|
||||
|
@ -391,11 +383,10 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
|
|||
}
|
||||
VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
|
||||
vptr_offset +=
|
||||
tcx.own_existential_vtable_entries(vtable_principal.def_id()).len();
|
||||
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)),
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal),
|
||||
target_principal,
|
||||
) {
|
||||
if emit_vptr {
|
||||
|
@ -419,37 +410,32 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
|
|||
|
||||
fn trait_refs_are_compatible<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
hr_vtable_principal: ty::PolyExistentialTraitRef<'tcx>,
|
||||
hr_target_principal: ty::PolyExistentialTraitRef<'tcx>,
|
||||
vtable_principal: ty::ExistentialTraitRef<'tcx>,
|
||||
target_principal: ty::ExistentialTraitRef<'tcx>,
|
||||
) -> bool {
|
||||
if hr_vtable_principal.def_id() != hr_target_principal.def_id() {
|
||||
if vtable_principal.def_id != target_principal.def_id {
|
||||
return false;
|
||||
}
|
||||
|
||||
let (infcx, param_env) =
|
||||
tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized());
|
||||
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(
|
||||
let source_principal = ocx.normalize(&ObligationCause::dummy(), param_env, vtable_principal);
|
||||
let target_principal = ocx.normalize(&ObligationCause::dummy(), param_env, target_principal);
|
||||
let Ok(()) = ocx.eq_trace(
|
||||
&ObligationCause::dummy(),
|
||||
param_env,
|
||||
ToTrace::to_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()
|
||||
})
|
||||
ty::Binder::dummy(target_principal),
|
||||
ty::Binder::dummy(source_principal),
|
||||
),
|
||||
target_principal,
|
||||
source_principal,
|
||||
) else {
|
||||
return false;
|
||||
};
|
||||
ocx.select_all_or_error().is_empty()
|
||||
}
|
||||
|
||||
pub(super) fn provide(providers: &mut Providers) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue