@@ -11,6 +11,7 @@ use rustc_data_structures::base_n;
1111use rustc_data_structures:: fx:: FxHashMap ;
1212use rustc_hir as hir;
1313use rustc_middle:: ty:: layout:: IntegerExt ;
14+ use rustc_middle:: ty:: TypeVisitableExt ;
1415use rustc_middle:: ty:: {
1516 self , Const , ExistentialPredicate , FloatTy , FnSig , Instance , IntTy , List , Region , RegionKind ,
1617 TermKind , Ty , TyCtxt , UintTy ,
@@ -21,7 +22,9 @@ use rustc_span::sym;
2122use rustc_target:: abi:: call:: { Conv , FnAbi , PassMode } ;
2223use rustc_target:: abi:: Integer ;
2324use rustc_target:: spec:: abi:: Abi ;
25+ use rustc_trait_selection:: traits;
2426use std:: fmt:: Write as _;
27+ use std:: iter;
2528
2629use crate :: typeid:: TypeIdOptions ;
2730
@@ -747,9 +750,8 @@ fn transform_predicates<'tcx>(
747750 tcx : TyCtxt < ' tcx > ,
748751 predicates : & List < ty:: PolyExistentialPredicate < ' tcx > > ,
749752) -> & ' tcx List < ty:: PolyExistentialPredicate < ' tcx > > {
750- let predicates: Vec < ty:: PolyExistentialPredicate < ' tcx > > = predicates
751- . iter ( )
752- . filter_map ( |predicate| match predicate. skip_binder ( ) {
753+ tcx. mk_poly_existential_predicates_from_iter ( predicates. iter ( ) . filter_map ( |predicate| {
754+ match predicate. skip_binder ( ) {
753755 ty:: ExistentialPredicate :: Trait ( trait_ref) => {
754756 let trait_ref = ty:: TraitRef :: identity ( tcx, trait_ref. def_id ) ;
755757 Some ( ty:: Binder :: dummy ( ty:: ExistentialPredicate :: Trait (
@@ -758,9 +760,8 @@ fn transform_predicates<'tcx>(
758760 }
759761 ty:: ExistentialPredicate :: Projection ( ..) => None ,
760762 ty:: ExistentialPredicate :: AutoTrait ( ..) => Some ( predicate) ,
761- } )
762- . collect ( ) ;
763- tcx. mk_poly_existential_predicates ( & predicates)
763+ }
764+ } ) )
764765}
765766
766767/// Transforms args for being encoded and used in the substitution dictionary.
@@ -1115,51 +1116,46 @@ pub fn typeid_for_instance<'tcx>(
11151116 instance. args = strip_receiver_auto ( tcx, instance. args )
11161117 }
11171118
1119+ if let Some ( impl_id) = tcx. impl_of_method ( instance. def_id ( ) )
1120+ && let Some ( trait_ref) = tcx. impl_trait_ref ( impl_id)
1121+ {
1122+ let impl_method = tcx. associated_item ( instance. def_id ( ) ) ;
1123+ let method_id = impl_method
1124+ . trait_item_def_id
1125+ . expect ( "Part of a trait implementation, but not linked to the def_id?" ) ;
1126+ let trait_method = tcx. associated_item ( method_id) ;
1127+ if traits:: is_vtable_safe_method ( tcx, trait_ref. skip_binder ( ) . def_id , trait_method) {
1128+ // Trait methods will have a Self polymorphic parameter, where the concreteized
1129+ // implementatation will not. We need to walk back to the more general trait method
1130+ let trait_ref = tcx. instantiate_and_normalize_erasing_regions (
1131+ instance. args ,
1132+ ty:: ParamEnv :: reveal_all ( ) ,
1133+ trait_ref,
1134+ ) ;
1135+ let invoke_ty = trait_object_ty ( tcx, ty:: Binder :: dummy ( trait_ref) ) ;
1136+
1137+ // At the call site, any call to this concrete function through a vtable will be
1138+ // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
1139+ // original method id, and we've recovered the trait arguments, we can make the callee
1140+ // instance we're computing the alias set for match the caller instance.
1141+ //
1142+ // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
1143+ // If we ever *do* start encoding the vtable index, we will need to generate an alias set
1144+ // based on which vtables we are putting this method into, as there will be more than one
1145+ // index value when supertraits are involved.
1146+ instance. def = ty:: InstanceDef :: Virtual ( method_id, 0 ) ;
1147+ let abstract_trait_args =
1148+ tcx. mk_args_trait ( invoke_ty, trait_ref. args . into_iter ( ) . skip ( 1 ) ) ;
1149+ instance. args = instance. args . rebase_onto ( tcx, impl_id, abstract_trait_args) ;
1150+ }
1151+ }
1152+
11181153 let fn_abi = tcx
11191154 . fn_abi_of_instance ( tcx. param_env ( instance. def_id ( ) ) . and ( ( instance, ty:: List :: empty ( ) ) ) )
11201155 . unwrap_or_else ( |instance| {
11211156 bug ! ( "typeid_for_instance: couldn't get fn_abi of instance {:?}" , instance)
11221157 } ) ;
11231158
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-
11631159 typeid_for_fnabi ( tcx, fn_abi, options)
11641160}
11651161
@@ -1171,14 +1167,50 @@ fn strip_receiver_auto<'tcx>(
11711167 let ty:: Dynamic ( preds, lifetime, kind) = ty. kind ( ) else {
11721168 bug ! ( "Tried to strip auto traits from non-dynamic type {ty}" ) ;
11731169 } ;
1174- let filtered_preds =
1175- if preds . principal ( ) . is_some ( ) {
1170+ let new_rcvr = if preds . principal ( ) . is_some ( ) {
1171+ let filtered_preds =
11761172 tcx. mk_poly_existential_predicates_from_iter ( preds. into_iter ( ) . filter ( |pred| {
11771173 !matches ! ( pred. skip_binder( ) , ty:: ExistentialPredicate :: AutoTrait ( ..) )
1178- } ) )
1179- } else {
1180- ty:: List :: empty ( )
1181- } ;
1182- let new_rcvr = Ty :: new_dynamic ( tcx, filtered_preds, * lifetime, * kind) ;
1174+ } ) ) ;
1175+ Ty :: new_dynamic ( tcx, filtered_preds, * lifetime, * kind)
1176+ } else {
1177+ // If there's no principal type, re-encode it as a unit, since we don't know anything
1178+ // about it. This technically discards the knowledge that it was a type that was made
1179+ // into a trait object at some point, but that's not a lot.
1180+ tcx. types . unit
1181+ } ;
11831182 tcx. mk_args_trait ( new_rcvr, args. into_iter ( ) . skip ( 1 ) )
11841183}
1184+
1185+ fn trait_object_ty < ' tcx > ( tcx : TyCtxt < ' tcx > , poly_trait_ref : ty:: PolyTraitRef < ' tcx > ) -> Ty < ' tcx > {
1186+ assert ! ( !poly_trait_ref. has_non_region_param( ) ) ;
1187+ let principal_pred = poly_trait_ref. map_bound ( |trait_ref| {
1188+ ty:: ExistentialPredicate :: Trait ( ty:: ExistentialTraitRef :: erase_self_ty ( tcx, trait_ref) )
1189+ } ) ;
1190+ let mut assoc_preds: Vec < _ > = traits:: supertraits ( tcx, poly_trait_ref)
1191+ . flat_map ( |super_poly_trait_ref| {
1192+ tcx. associated_items ( super_poly_trait_ref. def_id ( ) )
1193+ . in_definition_order ( )
1194+ . filter ( |item| item. kind == ty:: AssocKind :: Type )
1195+ . map ( move |assoc_ty| {
1196+ super_poly_trait_ref. map_bound ( |super_trait_ref| {
1197+ let alias_ty = ty:: AliasTy :: new ( tcx, assoc_ty. def_id , super_trait_ref. args ) ;
1198+ let resolved = tcx. normalize_erasing_regions (
1199+ ty:: ParamEnv :: reveal_all ( ) ,
1200+ alias_ty. to_ty ( tcx) ,
1201+ ) ;
1202+ ty:: ExistentialPredicate :: Projection ( ty:: ExistentialProjection {
1203+ def_id : assoc_ty. def_id ,
1204+ args : ty:: ExistentialTraitRef :: erase_self_ty ( tcx, super_trait_ref) . args ,
1205+ term : resolved. into ( ) ,
1206+ } )
1207+ } )
1208+ } )
1209+ } )
1210+ . collect ( ) ;
1211+ assoc_preds. sort_by ( |a, b| a. skip_binder ( ) . stable_cmp ( tcx, & b. skip_binder ( ) ) ) ;
1212+ let preds = tcx. mk_poly_existential_predicates_from_iter (
1213+ iter:: once ( principal_pred) . chain ( assoc_preds. into_iter ( ) ) ,
1214+ ) ;
1215+ Ty :: new_dynamic ( tcx, preds, tcx. lifetimes . re_erased , ty:: Dyn )
1216+ }
0 commit comments