@@ -11,6 +11,7 @@ use rustc_data_structures::base_n;
11
11
use rustc_data_structures:: fx:: FxHashMap ;
12
12
use rustc_hir as hir;
13
13
use rustc_middle:: ty:: layout:: IntegerExt ;
14
+ use rustc_middle:: ty:: TypeVisitableExt ;
14
15
use rustc_middle:: ty:: {
15
16
self , Const , ExistentialPredicate , FloatTy , FnSig , Instance , IntTy , List , Region , RegionKind ,
16
17
TermKind , Ty , TyCtxt , UintTy ,
@@ -21,7 +22,9 @@ use rustc_span::sym;
21
22
use rustc_target:: abi:: call:: { Conv , FnAbi , PassMode } ;
22
23
use rustc_target:: abi:: Integer ;
23
24
use rustc_target:: spec:: abi:: Abi ;
25
+ use rustc_trait_selection:: traits;
24
26
use std:: fmt:: Write as _;
27
+ use std:: iter;
25
28
26
29
use crate :: typeid:: TypeIdOptions ;
27
30
@@ -1113,51 +1116,46 @@ pub fn typeid_for_instance<'tcx>(
1113
1116
instance. args = strip_receiver_auto ( tcx, instance. args )
1114
1117
}
1115
1118
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
+
1116
1153
let fn_abi = tcx
1117
1154
. fn_abi_of_instance ( tcx. param_env ( instance. def_id ( ) ) . and ( ( instance, ty:: List :: empty ( ) ) ) )
1118
1155
. unwrap_or_else ( |instance| {
1119
1156
bug ! ( "typeid_for_instance: couldn't get fn_abi of instance {:?}" , instance)
1120
1157
} ) ;
1121
1158
1122
- // If this instance is a method and self is a reference, get the impl it belongs to
1123
- let impl_def_id = tcx. impl_of_method ( instance. def_id ( ) ) ;
1124
- if impl_def_id. is_some ( ) && !fn_abi. args . is_empty ( ) && fn_abi. args [ 0 ] . layout . ty . is_ref ( ) {
1125
- // If this impl is not an inherent impl, get the trait it implements
1126
- if let Some ( trait_ref) = tcx. impl_trait_ref ( impl_def_id. unwrap ( ) ) {
1127
- // Transform the concrete self into a reference to a trait object
1128
- let existential_predicate = trait_ref. map_bound ( |trait_ref| {
1129
- ty:: ExistentialPredicate :: Trait ( ty:: ExistentialTraitRef :: erase_self_ty (
1130
- tcx, trait_ref,
1131
- ) )
1132
- } ) ;
1133
- let existential_predicates = tcx. mk_poly_existential_predicates ( & [ ty:: Binder :: dummy (
1134
- existential_predicate. skip_binder ( ) ,
1135
- ) ] ) ;
1136
- // Is the concrete self mutable?
1137
- let self_ty = if fn_abi. args [ 0 ] . layout . ty . is_mutable_ptr ( ) {
1138
- Ty :: new_mut_ref (
1139
- tcx,
1140
- tcx. lifetimes . re_erased ,
1141
- Ty :: new_dynamic ( tcx, existential_predicates, tcx. lifetimes . re_erased , ty:: Dyn ) ,
1142
- )
1143
- } else {
1144
- Ty :: new_imm_ref (
1145
- tcx,
1146
- tcx. lifetimes . re_erased ,
1147
- Ty :: new_dynamic ( tcx, existential_predicates, tcx. lifetimes . re_erased , ty:: Dyn ) ,
1148
- )
1149
- } ;
1150
-
1151
- // Replace the concrete self in an fn_abi clone by the reference to a trait object
1152
- let mut fn_abi = fn_abi. clone ( ) ;
1153
- // HACK(rcvalle): It is okay to not replace or update the entire ArgAbi here because the
1154
- // other fields are never used.
1155
- fn_abi. args [ 0 ] . layout . ty = self_ty;
1156
-
1157
- return typeid_for_fnabi ( tcx, & fn_abi, options) ;
1158
- }
1159
- }
1160
-
1161
1159
typeid_for_fnabi ( tcx, fn_abi, options)
1162
1160
}
1163
1161
@@ -1183,3 +1181,36 @@ fn strip_receiver_auto<'tcx>(
1183
1181
} ;
1184
1182
tcx. mk_args_trait ( new_rcvr, args. into_iter ( ) . skip ( 1 ) )
1185
1183
}
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