@@ -2,6 +2,9 @@ use std::fmt::Debug;
2
2
use std:: ops:: ControlFlow ;
3
3
4
4
use 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 ;
5
8
use rustc_infer:: traits:: util:: PredicateSet ;
6
9
use rustc_middle:: bug;
7
10
use rustc_middle:: query:: Providers ;
@@ -13,7 +16,7 @@ use smallvec::{SmallVec, smallvec};
13
16
use tracing:: debug;
14
17
15
18
use crate :: errors:: DumpVTableEntries ;
16
- use crate :: traits:: { impossible_predicates, is_vtable_safe_method} ;
19
+ use crate :: traits:: { ObligationCtxt , impossible_predicates, is_vtable_safe_method} ;
17
20
18
21
#[ derive( Clone , Debug ) ]
19
22
pub enum VtblSegment < ' tcx > {
@@ -22,6 +25,8 @@ pub enum VtblSegment<'tcx> {
22
25
}
23
26
24
27
/// Prepare the segments for a vtable
28
+ // FIXME: This should take a `PolyExistentialTraitRef`, since we don't care
29
+ // about our `Self` type here.
25
30
pub fn prepare_vtable_segments < ' tcx , T > (
26
31
tcx : TyCtxt < ' tcx > ,
27
32
trait_ref : ty:: PolyTraitRef < ' tcx > ,
@@ -327,14 +332,10 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
327
332
let ty:: Dynamic ( source, _, _) = * key. self_ty ( ) . kind ( ) else {
328
333
bug ! ( ) ;
329
334
} ;
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 ) ;
333
337
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) ) ;
338
339
339
340
let vtable_segment_callback = {
340
341
let mut vptr_offset = 0 ;
@@ -343,15 +344,18 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
343
344
VtblSegment :: MetadataDSA => {
344
345
vptr_offset += TyCtxt :: COMMON_VTABLE_ENTRIES . len ( ) ;
345
346
}
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
+ ) {
351
354
return ControlFlow :: Break ( vptr_offset) ;
352
355
}
353
356
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 ( ) ;
355
359
356
360
if emit_vptr {
357
361
vptr_offset += 1 ;
@@ -383,17 +387,14 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
383
387
let ty:: Dynamic ( target, _, _) = * target. kind ( ) else {
384
388
bug ! ( ) ;
385
389
} ;
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 ( ) ?;
389
391
390
392
// Given that we have a target principal, it is a bug for there not to be a source principal.
391
393
let ty:: Dynamic ( source, _, _) = * source. kind ( ) else {
392
394
bug ! ( ) ;
393
395
} ;
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 ) ;
397
398
398
399
let vtable_segment_callback = {
399
400
let mut vptr_offset = 0 ;
@@ -402,11 +403,15 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
402
403
VtblSegment :: MetadataDSA => {
403
404
vptr_offset += TyCtxt :: COMMON_VTABLE_ENTRIES . len ( ) ;
404
405
}
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
+ ) {
410
415
if emit_vptr {
411
416
return ControlFlow :: Break ( Some ( vptr_offset) ) ;
412
417
} else {
@@ -426,6 +431,41 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
426
431
prepare_vtable_segments ( tcx, source_principal, vtable_segment_callback) . unwrap ( )
427
432
}
428
433
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
+
429
469
pub ( super ) fn provide ( providers : & mut Providers ) {
430
470
* providers = Providers {
431
471
own_existential_vtable_entries,
0 commit comments