1
Fork 0

Normalize vtable entries before walking and deduplicating them

This commit is contained in:
Michael Goulet 2025-01-10 04:47:45 +00:00
parent fdc4bd22b7
commit 739ef83f31
6 changed files with 77 additions and 24 deletions

View file

@ -419,7 +419,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty));
let vtable_entries = self.vtable_entries(data_a.principal(), ty);
if let Some(entry_idx) = vptr_entry_idx {
let Some(&ty::VtblEntry::TraitVPtr(_)) = vtable_entries.get(entry_idx)
let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) =
vtable_entries.get(entry_idx)
else {
span_bug!(
self.cur_span(),
@ -428,6 +429,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
dest_pointee_ty
);
};
let erased_trait_ref =
ty::ExistentialTraitRef::erase_self_ty(*self.tcx, upcast_trait_ref);
assert!(data_b.principal().is_some_and(|b| self.eq_in_param_env(
erased_trait_ref,
self.tcx.instantiate_bound_regions_with_erased(b)
)));
} else {
// In this case codegen would keep using the old vtable. We don't want to do
// that as it has the wrong trait. The reason codegen can do this is that

View file

@ -402,6 +402,18 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
}
}
impl<'tcx> ToTrace<'tcx> for ty::ExistentialTraitRef<'tcx> {
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
TypeTrace {
cause: cause.clone(),
values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(
ty::Binder::dummy(a),
ty::Binder::dummy(b),
)),
}
}
}
impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
TypeTrace {
@ -410,3 +422,15 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
}
}
}
impl<'tcx> ToTrace<'tcx> for ty::ExistentialProjection<'tcx> {
fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
TypeTrace {
cause: cause.clone(),
values: ValuePairs::ExistentialProjection(ExpectedFound::new(
ty::Binder::dummy(a),
ty::Binder::dummy(b),
)),
}
}
}

View file

@ -3,7 +3,6 @@ use std::ops::ControlFlow;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::at::ToTrace;
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::util::PredicateSet;
use rustc_middle::bug;
@ -127,16 +126,15 @@ fn prepare_vtable_segments_inner<'tcx, T>(
.explicit_super_predicates_of(inner_most_trait_ref.def_id)
.iter_identity_copied()
.filter_map(move |(pred, _)| {
Some(
tcx.instantiate_bound_regions_with_erased(
pred.instantiate_supertrait(
tcx,
ty::Binder::dummy(inner_most_trait_ref),
)
.as_trait_clause()?,
)
.trait_ref,
pred.instantiate_supertrait(tcx, ty::Binder::dummy(inner_most_trait_ref))
.as_trait_clause()
})
.map(move |pred| {
tcx.normalize_erasing_late_bound_regions(
ty::TypingEnv::fully_monomorphized(),
pred,
)
.trait_ref
});
// Find an unvisited supertrait
@ -229,6 +227,8 @@ fn vtable_entries<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
) -> &'tcx [VtblEntry<'tcx>] {
debug_assert!(!trait_ref.has_non_region_infer() && !trait_ref.has_non_region_param());
debug!("vtable_entries({:?})", trait_ref);
let mut entries = vec![];
@ -422,17 +422,8 @@ fn trait_refs_are_compatible<'tcx>(
let ocx = ObligationCtxt::new(&infcx);
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(),
ty::Binder::dummy(target_principal),
ty::Binder::dummy(source_principal),
),
target_principal,
source_principal,
) else {
let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, target_principal, source_principal)
else {
return false;
};
ocx.select_all_or_error().is_empty()

View file

@ -3,8 +3,6 @@ error: vtable entries: [
MetadataSize,
MetadataAlign,
Method(<() as Supertrait<()>>::_print_numbers),
Method(<() as Supertrait<()>>::_print_numbers),
TraitVPtr(<() as Supertrait<<() as Identity>::Selff>>),
Method(<() as Middle<()>>::say_hello),
]
--> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:29:1

View file

@ -0,0 +1,32 @@
//@ run-pass
//@ check-run-results
#![feature(trait_upcasting)]
trait Supertrait<T> {
fn _print_numbers(&self, mem: &[usize; 100]) {
println!("{mem:?}");
}
}
impl<T> Supertrait<T> for () {}
trait Identity {
type Selff;
}
impl<Selff> Identity for Selff {
type Selff = Selff;
}
trait Middle<T>: Supertrait<()> + Supertrait<T> {
fn say_hello(&self, _: &usize) {
println!("Hello!");
}
}
impl<T> Middle<T> for () {}
trait Trait: Middle<<() as Identity>::Selff> {}
impl Trait for () {}
fn main() {
(&() as &dyn Trait as &dyn Middle<()>).say_hello(&0);
}