@@ -9,10 +9,10 @@ use rustc_hir::LangItem;
9
9
use rustc_middle:: bug;
10
10
use rustc_middle:: ty:: fold:: { TypeFolder , TypeSuperFoldable } ;
11
11
use rustc_middle:: ty:: {
12
- self , ExistentialPredicateStableCmpExt as _, Instance , IntTy , List , Ty , TyCtxt , TypeFoldable ,
13
- TypeVisitableExt , UintTy ,
12
+ self , ExistentialPredicateStableCmpExt as _, Instance , InstanceKind , IntTy , List , TraitRef , Ty ,
13
+ TyCtxt , TypeFoldable , TypeVisitableExt , UintTy ,
14
14
} ;
15
- use rustc_span:: sym;
15
+ use rustc_span:: { def_id :: DefId , sym} ;
16
16
use rustc_trait_selection:: traits;
17
17
use std:: iter;
18
18
use tracing:: { debug, instrument} ;
@@ -360,41 +360,29 @@ pub fn transform_instance<'tcx>(
360
360
if !options. contains ( TransformTyOptions :: USE_CONCRETE_SELF ) {
361
361
// Perform type erasure for calls on trait objects by transforming self into a trait object
362
362
// of the trait that defines the method.
363
- if let Some ( impl_id) = tcx. impl_of_method ( instance. def_id ( ) )
364
- && let Some ( trait_ref) = tcx. impl_trait_ref ( impl_id)
365
- {
366
- let impl_method = tcx. associated_item ( instance. def_id ( ) ) ;
367
- let method_id = impl_method
368
- . trait_item_def_id
369
- . expect ( "Part of a trait implementation, but not linked to the def_id?" ) ;
370
- let trait_method = tcx. associated_item ( method_id) ;
371
- let trait_id = trait_ref. skip_binder ( ) . def_id ;
372
- if traits:: is_vtable_safe_method ( tcx, trait_id, trait_method)
373
- && tcx. is_object_safe ( trait_id)
374
- {
375
- // Trait methods will have a Self polymorphic parameter, where the concreteized
376
- // implementatation will not. We need to walk back to the more general trait method
377
- let trait_ref = tcx. instantiate_and_normalize_erasing_regions (
378
- instance. args ,
379
- ty:: ParamEnv :: reveal_all ( ) ,
380
- trait_ref,
381
- ) ;
382
- let invoke_ty = trait_object_ty ( tcx, ty:: Binder :: dummy ( trait_ref) ) ;
363
+ if let Some ( ( trait_ref, method_id, ancestor) ) = implemented_method ( tcx, instance) {
364
+ // Trait methods will have a Self polymorphic parameter, where the concreteized
365
+ // implementatation will not. We need to walk back to the more general trait method
366
+ let trait_ref = tcx. instantiate_and_normalize_erasing_regions (
367
+ instance. args ,
368
+ ty:: ParamEnv :: reveal_all ( ) ,
369
+ trait_ref,
370
+ ) ;
371
+ let invoke_ty = trait_object_ty ( tcx, ty:: Binder :: dummy ( trait_ref) ) ;
383
372
384
- // At the call site, any call to this concrete function through a vtable will be
385
- // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
386
- // original method id, and we've recovered the trait arguments, we can make the callee
387
- // instance we're computing the alias set for match the caller instance.
388
- //
389
- // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
390
- // If we ever *do* start encoding the vtable index, we will need to generate an alias set
391
- // based on which vtables we are putting this method into, as there will be more than one
392
- // index value when supertraits are involved.
393
- instance. def = ty:: InstanceKind :: Virtual ( method_id, 0 ) ;
394
- let abstract_trait_args =
395
- tcx. mk_args_trait ( invoke_ty, trait_ref. args . into_iter ( ) . skip ( 1 ) ) ;
396
- instance. args = instance. args . rebase_onto ( tcx, impl_id, abstract_trait_args) ;
397
- }
373
+ // At the call site, any call to this concrete function through a vtable will be
374
+ // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
375
+ // original method id, and we've recovered the trait arguments, we can make the callee
376
+ // instance we're computing the alias set for match the caller instance.
377
+ //
378
+ // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
379
+ // If we ever *do* start encoding the vtable index, we will need to generate an alias set
380
+ // based on which vtables we are putting this method into, as there will be more than one
381
+ // index value when supertraits are involved.
382
+ instance. def = ty:: InstanceKind :: Virtual ( method_id, 0 ) ;
383
+ let abstract_trait_args =
384
+ tcx. mk_args_trait ( invoke_ty, trait_ref. args . into_iter ( ) . skip ( 1 ) ) ;
385
+ instance. args = instance. args . rebase_onto ( tcx, ancestor, abstract_trait_args) ;
398
386
} else if tcx. is_closure_like ( instance. def_id ( ) ) {
399
387
// We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
400
388
// instantiate it, and take the type of its only method as our own.
@@ -452,3 +440,36 @@ pub fn transform_instance<'tcx>(
452
440
453
441
instance
454
442
}
443
+
444
+ fn implemented_method < ' tcx > (
445
+ tcx : TyCtxt < ' tcx > ,
446
+ instance : Instance < ' tcx > ,
447
+ ) -> Option < ( ty:: EarlyBinder < ' tcx , TraitRef < ' tcx > > , DefId , DefId ) > {
448
+ let trait_ref;
449
+ let method_id;
450
+ let trait_id;
451
+ let trait_method;
452
+ let ancestor = if let Some ( impl_id) = tcx. impl_of_method ( instance. def_id ( ) ) {
453
+ // Implementation in an `impl` block
454
+ trait_ref = tcx. impl_trait_ref ( impl_id) ?;
455
+ let impl_method = tcx. associated_item ( instance. def_id ( ) ) ;
456
+ method_id = impl_method. trait_item_def_id ?;
457
+ trait_method = tcx. associated_item ( method_id) ;
458
+ trait_id = trait_ref. skip_binder ( ) . def_id ;
459
+ impl_id
460
+ } else if let InstanceKind :: Item ( def_id) = instance. def
461
+ && let Some ( trait_method_bound) = tcx. opt_associated_item ( def_id)
462
+ {
463
+ // Provided method in a `trait` block
464
+ trait_method = trait_method_bound;
465
+ method_id = instance. def_id ( ) ;
466
+ trait_id = tcx. trait_of_item ( method_id) ?;
467
+ trait_ref = ty:: EarlyBinder :: bind ( TraitRef :: from_method ( tcx, trait_id, instance. args ) ) ;
468
+ trait_id
469
+ } else {
470
+ return None ;
471
+ } ;
472
+ let vtable_possible =
473
+ traits:: is_vtable_safe_method ( tcx, trait_id, trait_method) && tcx. is_object_safe ( trait_id) ;
474
+ vtable_possible. then_some ( ( trait_ref, method_id, ancestor) )
475
+ }
0 commit comments