@@ -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 , IntTy , List , TraitRef , Ty , TyCtxt ,
13
+ 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,42 +360,7 @@ 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) ) ;
383
-
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
- }
398
- } else if tcx. is_closure_like ( instance. def_id ( ) ) {
363
+ if tcx. is_closure_like ( instance. def_id ( ) ) {
399
364
// We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
400
365
// instantiate it, and take the type of its only method as our own.
401
366
let closure_ty = instance. ty ( tcx, ty:: ParamEnv :: reveal_all ( ) ) ;
@@ -447,8 +412,62 @@ pub fn transform_instance<'tcx>(
447
412
448
413
instance. def = ty:: InstanceKind :: Virtual ( call, 0 ) ;
449
414
instance. args = abstract_args;
415
+ } else if let Some ( ( trait_ref, method_id, ancestor) ) = implemented_method ( tcx, instance) {
416
+ // Trait methods will have a Self polymorphic parameter, where the concreteized
417
+ // implementatation will not. We need to walk back to the more general trait method
418
+ let trait_ref = tcx. instantiate_and_normalize_erasing_regions (
419
+ instance. args ,
420
+ ty:: ParamEnv :: reveal_all ( ) ,
421
+ trait_ref,
422
+ ) ;
423
+ let invoke_ty = trait_object_ty ( tcx, ty:: Binder :: dummy ( trait_ref) ) ;
424
+
425
+ // At the call site, any call to this concrete function through a vtable will be
426
+ // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
427
+ // original method id, and we've recovered the trait arguments, we can make the callee
428
+ // instance we're computing the alias set for match the caller instance.
429
+ //
430
+ // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
431
+ // If we ever *do* start encoding the vtable index, we will need to generate an alias set
432
+ // based on which vtables we are putting this method into, as there will be more than one
433
+ // index value when supertraits are involved.
434
+ instance. def = ty:: InstanceKind :: Virtual ( method_id, 0 ) ;
435
+ let abstract_trait_args =
436
+ tcx. mk_args_trait ( invoke_ty, trait_ref. args . into_iter ( ) . skip ( 1 ) ) ;
437
+ instance. args = instance. args . rebase_onto ( tcx, ancestor, abstract_trait_args) ;
450
438
}
451
439
}
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 Some ( trait_method_bound) = tcx. opt_associated_item ( instance. def_id ( ) ) {
461
+ // Provided method in a `trait` block (or closure, but we checked that separately)
462
+ trait_method = trait_method_bound;
463
+ method_id = instance. def_id ( ) ;
464
+ trait_id = tcx. trait_of_item ( method_id) ?;
465
+ trait_ref = ty:: EarlyBinder :: bind ( TraitRef :: from_method ( tcx, trait_id, instance. args ) ) ;
466
+ trait_id
467
+ } else {
468
+ return None ;
469
+ } ;
470
+ let vtable_possible =
471
+ traits:: is_vtable_safe_method ( tcx, trait_id, trait_method) && tcx. is_object_safe ( trait_id) ;
472
+ vtable_possible. then_some ( ( trait_ref, method_id, ancestor) )
473
+ }
0 commit comments