@@ -2,6 +2,9 @@ use std::fmt::Debug;
22use std:: ops:: ControlFlow ;
33
44use rustc_hir:: def_id:: DefId ;
5+ use rustc_infer:: infer:: at:: ToTrace ;
6+ use rustc_infer:: infer:: { BoundRegionConversionTime , TyCtxtInferExt } ;
7+ use rustc_infer:: traits:: ObligationCause ;
58use rustc_infer:: traits:: util:: PredicateSet ;
69use rustc_middle:: bug;
710use rustc_middle:: query:: Providers ;
@@ -13,7 +16,7 @@ use smallvec::{SmallVec, smallvec};
1316use tracing:: debug;
1417
1518use crate :: errors:: DumpVTableEntries ;
16- use crate :: traits:: { impossible_predicates, is_vtable_safe_method} ;
19+ use crate :: traits:: { ObligationCtxt , impossible_predicates, is_vtable_safe_method} ;
1720
1821#[ derive( Clone , Debug ) ]
1922pub enum VtblSegment < ' tcx > {
@@ -22,6 +25,8 @@ pub enum VtblSegment<'tcx> {
2225}
2326
2427/// Prepare the segments for a vtable
28+ // FIXME: This should take a `PolyExistentialTraitRef`, since we don't care
29+ // about our `Self` type here.
2530pub fn prepare_vtable_segments < ' tcx , T > (
2631 tcx : TyCtxt < ' tcx > ,
2732 trait_ref : ty:: PolyTraitRef < ' tcx > ,
@@ -327,14 +332,10 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
327332 let ty:: Dynamic ( source, _, _) = * key. self_ty ( ) . kind ( ) else {
328333 bug ! ( ) ;
329334 } ;
330- let source_principal = tcx
331- . normalize_erasing_regions ( ty:: ParamEnv :: reveal_all ( ) , source. principal ( ) . unwrap ( ) )
332- . with_self_ty ( tcx, tcx. types . trait_object_dummy_self ) ;
335+ let source_principal =
336+ source. principal ( ) . unwrap ( ) . with_self_ty ( tcx, tcx. types . trait_object_dummy_self ) ;
333337
334- let target_principal = tcx
335- . normalize_erasing_regions ( ty:: ParamEnv :: reveal_all ( ) , key)
336- // We don't care about the self type, since it will always be the same thing.
337- . with_self_ty ( tcx, tcx. types . trait_object_dummy_self ) ;
338+ let target_principal = ty:: Binder :: dummy ( ty:: ExistentialTraitRef :: erase_self_ty ( tcx, key) ) ;
338339
339340 let vtable_segment_callback = {
340341 let mut vptr_offset = 0 ;
@@ -343,15 +344,18 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
343344 VtblSegment :: MetadataDSA => {
344345 vptr_offset += TyCtxt :: COMMON_VTABLE_ENTRIES . len ( ) ;
345346 }
346- VtblSegment :: TraitOwnEntries { trait_ref, emit_vptr } => {
347- if tcx
348- . normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , trait_ref)
349- == target_principal
350- {
347+ VtblSegment :: TraitOwnEntries { trait_ref : vtable_principal, emit_vptr } => {
348+ if trait_refs_are_compatible (
349+ tcx,
350+ vtable_principal
351+ . map_bound ( |t| ty:: ExistentialTraitRef :: erase_self_ty ( tcx, t) ) ,
352+ target_principal,
353+ ) {
351354 return ControlFlow :: Break ( vptr_offset) ;
352355 }
353356
354- vptr_offset += tcx. own_existential_vtable_entries ( trait_ref. def_id ( ) ) . len ( ) ;
357+ vptr_offset +=
358+ tcx. own_existential_vtable_entries ( vtable_principal. def_id ( ) ) . len ( ) ;
355359
356360 if emit_vptr {
357361 vptr_offset += 1 ;
@@ -383,17 +387,14 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
383387 let ty:: Dynamic ( target, _, _) = * target. kind ( ) else {
384388 bug ! ( ) ;
385389 } ;
386- let target_principal = tcx
387- . normalize_erasing_regions ( ty:: ParamEnv :: reveal_all ( ) , target. principal ( ) ?)
388- . with_self_ty ( tcx, tcx. types . trait_object_dummy_self ) ;
390+ let target_principal = target. principal ( ) ?;
389391
390392 // Given that we have a target principal, it is a bug for there not to be a source principal.
391393 let ty:: Dynamic ( source, _, _) = * source. kind ( ) else {
392394 bug ! ( ) ;
393395 } ;
394- let source_principal = tcx
395- . normalize_erasing_regions ( ty:: ParamEnv :: reveal_all ( ) , source. principal ( ) . unwrap ( ) )
396- . with_self_ty ( tcx, tcx. types . trait_object_dummy_self ) ;
396+ let source_principal =
397+ source. principal ( ) . unwrap ( ) . with_self_ty ( tcx, tcx. types . trait_object_dummy_self ) ;
397398
398399 let vtable_segment_callback = {
399400 let mut vptr_offset = 0 ;
@@ -402,11 +403,15 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
402403 VtblSegment :: MetadataDSA => {
403404 vptr_offset += TyCtxt :: COMMON_VTABLE_ENTRIES . len ( ) ;
404405 }
405- VtblSegment :: TraitOwnEntries { trait_ref, emit_vptr } => {
406- vptr_offset += tcx. own_existential_vtable_entries ( trait_ref. def_id ( ) ) . len ( ) ;
407- if tcx. normalize_erasing_regions ( ty:: ParamEnv :: reveal_all ( ) , trait_ref)
408- == target_principal
409- {
406+ VtblSegment :: TraitOwnEntries { trait_ref : vtable_principal, emit_vptr } => {
407+ vptr_offset +=
408+ tcx. own_existential_vtable_entries ( vtable_principal. def_id ( ) ) . len ( ) ;
409+ if trait_refs_are_compatible (
410+ tcx,
411+ vtable_principal
412+ . map_bound ( |t| ty:: ExistentialTraitRef :: erase_self_ty ( tcx, t) ) ,
413+ target_principal,
414+ ) {
410415 if emit_vptr {
411416 return ControlFlow :: Break ( Some ( vptr_offset) ) ;
412417 } else {
@@ -426,6 +431,41 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
426431 prepare_vtable_segments ( tcx, source_principal, vtable_segment_callback) . unwrap ( )
427432}
428433
434+ fn trait_refs_are_compatible < ' tcx > (
435+ tcx : TyCtxt < ' tcx > ,
436+ hr_vtable_principal : ty:: PolyExistentialTraitRef < ' tcx > ,
437+ hr_target_principal : ty:: PolyExistentialTraitRef < ' tcx > ,
438+ ) -> bool {
439+ if hr_vtable_principal. def_id ( ) != hr_target_principal. def_id ( ) {
440+ return false ;
441+ }
442+
443+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
444+ let param_env = ty:: ParamEnv :: reveal_all ( ) ;
445+ let ocx = ObligationCtxt :: new ( & infcx) ;
446+ let hr_source_principal =
447+ ocx. normalize ( & ObligationCause :: dummy ( ) , param_env, hr_vtable_principal) ;
448+ let hr_target_principal =
449+ ocx. normalize ( & ObligationCause :: dummy ( ) , param_env, hr_target_principal) ;
450+ infcx. enter_forall ( hr_target_principal, |target_principal| {
451+ let source_principal = infcx. instantiate_binder_with_fresh_vars (
452+ DUMMY_SP ,
453+ BoundRegionConversionTime :: HigherRankedType ,
454+ hr_source_principal,
455+ ) ;
456+ let Ok ( ( ) ) = ocx. eq_trace (
457+ & ObligationCause :: dummy ( ) ,
458+ param_env,
459+ ToTrace :: to_trace ( & ObligationCause :: dummy ( ) , hr_target_principal, hr_source_principal) ,
460+ target_principal,
461+ source_principal,
462+ ) else {
463+ return false ;
464+ } ;
465+ ocx. select_all_or_error ( ) . is_empty ( )
466+ } )
467+ }
468+
429469pub ( super ) fn provide ( providers : & mut Providers ) {
430470 * providers = Providers {
431471 own_existential_vtable_entries,
0 commit comments