@@ -9,10 +9,10 @@ use rustc_hir::LangItem;
99use rustc_middle:: bug;
1010use rustc_middle:: ty:: fold:: { TypeFolder , TypeSuperFoldable } ;
1111use 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 ,
1414} ;
15- use rustc_span:: sym;
15+ use rustc_span:: { def_id :: DefId , sym} ;
1616use rustc_trait_selection:: traits;
1717use std:: iter;
1818use tracing:: { debug, instrument} ;
@@ -360,41 +360,29 @@ pub fn transform_instance<'tcx>(
360360 if !options. contains ( TransformTyOptions :: USE_CONCRETE_SELF ) {
361361 // Perform type erasure for calls on trait objects by transforming self into a trait object
362362 // 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) ) ;
383372
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) ;
398386 } else if tcx. is_closure_like ( instance. def_id ( ) ) {
399387 // We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
400388 // instantiate it, and take the type of its only method as our own.
@@ -452,3 +440,36 @@ pub fn transform_instance<'tcx>(
452440
453441 instance
454442}
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