1010use rustc_data_structures:: base_n;
1111use rustc_data_structures:: fx:: FxHashMap ;
1212use rustc_hir as hir;
13+ use rustc_infer:: traits;
1314use rustc_middle:: ty:: layout:: IntegerExt ;
15+ use rustc_middle:: ty:: TypeVisitableExt ;
1416use rustc_middle:: ty:: {
1517 self , Const , ExistentialPredicate , FloatTy , FnSig , Instance , IntTy , List , Region , RegionKind ,
1618 TermKind , Ty , TyCtxt , UintTy ,
@@ -22,6 +24,7 @@ use rustc_target::abi::call::{Conv, FnAbi, PassMode};
2224use rustc_target:: abi:: Integer ;
2325use rustc_target:: spec:: abi:: Abi ;
2426use std:: fmt:: Write as _;
27+ use std:: iter;
2528
2629use crate :: typeid:: TypeIdOptions ;
2730
@@ -1115,51 +1118,31 @@ pub fn typeid_for_instance<'tcx>(
11151118 instance. args = strip_receiver_auto ( tcx, instance. args )
11161119 }
11171120
1121+ if let Some ( impl_id) = tcx. impl_of_method ( instance. def_id ( ) )
1122+ && let Some ( trait_ref) = tcx. impl_trait_ref ( impl_id)
1123+ {
1124+ // Trait methods will have a Self polymorphic parameter, where the concreteized
1125+ // implementatation will not. We need to walk back to the more general trait method
1126+ let trait_ref = trait_ref. instantiate ( tcx, instance. args ) ;
1127+ let invoke_ty = trait_object_ty ( tcx, ty:: Binder :: dummy ( trait_ref) ) ;
1128+ let method_id = tcx
1129+ . impl_item_implementor_ids ( impl_id)
1130+ . items ( )
1131+ . filter_map ( |( trait_method, impl_method) | {
1132+ ( * impl_method == instance. def_id ( ) ) . then_some ( * trait_method)
1133+ } )
1134+ . min ( )
1135+ . unwrap ( ) ;
1136+ instance. def = ty:: InstanceDef :: Virtual ( method_id, 0 ) ;
1137+ instance. args = tcx. mk_args_trait ( invoke_ty, trait_ref. args . into_iter ( ) . skip ( 1 ) ) ;
1138+ }
1139+
11181140 let fn_abi = tcx
11191141 . fn_abi_of_instance ( tcx. param_env ( instance. def_id ( ) ) . and ( ( instance, ty:: List :: empty ( ) ) ) )
11201142 . unwrap_or_else ( |instance| {
11211143 bug ! ( "typeid_for_instance: couldn't get fn_abi of instance {:?}" , instance)
11221144 } ) ;
11231145
1124- // If this instance is a method and self is a reference, get the impl it belongs to
1125- let impl_def_id = tcx. impl_of_method ( instance. def_id ( ) ) ;
1126- if impl_def_id. is_some ( ) && !fn_abi. args . is_empty ( ) && fn_abi. args [ 0 ] . layout . ty . is_ref ( ) {
1127- // If this impl is not an inherent impl, get the trait it implements
1128- if let Some ( trait_ref) = tcx. impl_trait_ref ( impl_def_id. unwrap ( ) ) {
1129- // Transform the concrete self into a reference to a trait object
1130- let existential_predicate = trait_ref. map_bound ( |trait_ref| {
1131- ty:: ExistentialPredicate :: Trait ( ty:: ExistentialTraitRef :: erase_self_ty (
1132- tcx, trait_ref,
1133- ) )
1134- } ) ;
1135- let existential_predicates = tcx. mk_poly_existential_predicates ( & [ ty:: Binder :: dummy (
1136- existential_predicate. skip_binder ( ) ,
1137- ) ] ) ;
1138- // Is the concrete self mutable?
1139- let self_ty = if fn_abi. args [ 0 ] . layout . ty . is_mutable_ptr ( ) {
1140- Ty :: new_mut_ref (
1141- tcx,
1142- tcx. lifetimes . re_erased ,
1143- Ty :: new_dynamic ( tcx, existential_predicates, tcx. lifetimes . re_erased , ty:: Dyn ) ,
1144- )
1145- } else {
1146- Ty :: new_imm_ref (
1147- tcx,
1148- tcx. lifetimes . re_erased ,
1149- Ty :: new_dynamic ( tcx, existential_predicates, tcx. lifetimes . re_erased , ty:: Dyn ) ,
1150- )
1151- } ;
1152-
1153- // Replace the concrete self in an fn_abi clone by the reference to a trait object
1154- let mut fn_abi = fn_abi. clone ( ) ;
1155- // HACK(rcvalle): It is okay to not replace or update the entire ArgAbi here because the
1156- // other fields are never used.
1157- fn_abi. args [ 0 ] . layout . ty = self_ty;
1158-
1159- return typeid_for_fnabi ( tcx, & fn_abi, options) ;
1160- }
1161- }
1162-
11631146 typeid_for_fnabi ( tcx, fn_abi, options)
11641147}
11651148
@@ -1182,3 +1165,33 @@ fn strip_receiver_auto<'tcx>(
11821165 let new_rcvr = Ty :: new_dynamic ( tcx, filtered_preds, * lifetime, * kind) ;
11831166 tcx. mk_args_trait ( new_rcvr, args. into_iter ( ) . skip ( 1 ) )
11841167}
1168+
1169+ fn trait_object_ty < ' tcx > ( tcx : TyCtxt < ' tcx > , poly_trait_ref : ty:: PolyTraitRef < ' tcx > ) -> Ty < ' tcx > {
1170+ assert ! ( !poly_trait_ref. has_non_region_param( ) ) ;
1171+ let principal_pred = poly_trait_ref. map_bound ( |trait_ref| {
1172+ ty:: ExistentialPredicate :: Trait ( ty:: ExistentialTraitRef :: erase_self_ty ( tcx, trait_ref) )
1173+ } ) ;
1174+ let assoc_preds =
1175+ traits:: util:: supertraits ( tcx, poly_trait_ref) . flat_map ( |super_poly_trait_ref| {
1176+ tcx. associated_items ( super_poly_trait_ref. def_id ( ) )
1177+ . in_definition_order ( )
1178+ . filter ( |item| item. kind == ty:: AssocKind :: Type )
1179+ . map ( move |assoc_ty| {
1180+ super_poly_trait_ref. map_bound ( |super_trait_ref| {
1181+ let alias_ty = ty:: AliasTy :: new ( tcx, assoc_ty. def_id , super_trait_ref. args ) ;
1182+ let resolved = tcx. normalize_erasing_regions (
1183+ ty:: ParamEnv :: reveal_all ( ) ,
1184+ alias_ty. to_ty ( tcx) ,
1185+ ) ;
1186+ ty:: ExistentialPredicate :: Projection ( ty:: ExistentialProjection {
1187+ def_id : assoc_ty. def_id ,
1188+ args : ty:: ExistentialTraitRef :: erase_self_ty ( tcx, super_trait_ref) . args ,
1189+ term : resolved. into ( ) ,
1190+ } )
1191+ } )
1192+ } )
1193+ } ) ;
1194+ let preds =
1195+ tcx. mk_poly_existential_predicates_from_iter ( iter:: once ( principal_pred) . chain ( assoc_preds) ) ;
1196+ Ty :: new_dynamic ( tcx, preds, tcx. lifetimes . re_erased , ty:: Dyn )
1197+ }
0 commit comments