|
10 | 10 | use rustc_data_structures::base_n;
|
11 | 11 | use rustc_data_structures::fx::FxHashMap;
|
12 | 12 | use rustc_hir as hir;
|
| 13 | +use rustc_hir::lang_items::LangItem; |
13 | 14 | use rustc_middle::ty::layout::IntegerExt;
|
14 | 15 | use rustc_middle::ty::TypeVisitableExt;
|
15 | 16 | use rustc_middle::ty::{
|
@@ -1152,43 +1153,91 @@ pub fn typeid_for_instance<'tcx>(
|
1152 | 1153 | instance.args = tcx.mk_args_trait(self_ty, List::empty());
|
1153 | 1154 | } else if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
|
1154 | 1155 | instance.args = strip_receiver_auto(tcx, instance.args);
|
| 1156 | + } else if let ty::InstanceDef::VTableShim(def_id) = instance.def |
| 1157 | + && let Some(trait_id) = tcx.trait_of_item(def_id) |
| 1158 | + { |
| 1159 | + // VTableShims may have a trait method, but a concrete Self. This is not suitable for a vtable, |
| 1160 | + // as the caller will not know the concrete Self. |
| 1161 | + let trait_ref = ty::TraitRef::new(tcx, trait_id, instance.args); |
| 1162 | + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); |
| 1163 | + instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); |
1155 | 1164 | }
|
1156 | 1165 |
|
1157 |
| - if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE) |
1158 |
| - && let Some(impl_id) = tcx.impl_of_method(instance.def_id()) |
1159 |
| - && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) |
1160 |
| - { |
1161 |
| - let impl_method = tcx.associated_item(instance.def_id()); |
1162 |
| - let method_id = impl_method |
1163 |
| - .trait_item_def_id |
1164 |
| - .expect("Part of a trait implementation, but not linked to the def_id?"); |
1165 |
| - let trait_method = tcx.associated_item(method_id); |
1166 |
| - let trait_id = trait_ref.skip_binder().def_id; |
1167 |
| - if traits::is_vtable_safe_method(tcx, trait_id, trait_method) |
1168 |
| - && tcx.object_safety_violations(trait_id).is_empty() |
| 1166 | + if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE) { |
| 1167 | + if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) |
| 1168 | + && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) |
1169 | 1169 | {
|
1170 |
| - // Trait methods will have a Self polymorphic parameter, where the concreteized |
1171 |
| - // implementatation will not. We need to walk back to the more general trait method |
1172 |
| - let trait_ref = tcx.instantiate_and_normalize_erasing_regions( |
1173 |
| - instance.args, |
1174 |
| - ty::ParamEnv::reveal_all(), |
1175 |
| - trait_ref, |
1176 |
| - ); |
| 1170 | + let impl_method = tcx.associated_item(instance.def_id()); |
| 1171 | + let method_id = impl_method |
| 1172 | + .trait_item_def_id |
| 1173 | + .expect("Part of a trait implementation, but not linked to the def_id?"); |
| 1174 | + let trait_method = tcx.associated_item(method_id); |
| 1175 | + let trait_id = trait_ref.skip_binder().def_id; |
| 1176 | + if traits::is_vtable_safe_method(tcx, trait_id, trait_method) |
| 1177 | + && tcx.object_safety_violations(trait_id).is_empty() |
| 1178 | + { |
| 1179 | + // Trait methods will have a Self polymorphic parameter, where the concreteized |
| 1180 | + // implementatation will not. We need to walk back to the more general trait method |
| 1181 | + let trait_ref = tcx.instantiate_and_normalize_erasing_regions( |
| 1182 | + instance.args, |
| 1183 | + ty::ParamEnv::reveal_all(), |
| 1184 | + trait_ref, |
| 1185 | + ); |
| 1186 | + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); |
| 1187 | + |
| 1188 | + // At the call site, any call to this concrete function through a vtable will be |
| 1189 | + // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the |
| 1190 | + // original method id, and we've recovered the trait arguments, we can make the callee |
| 1191 | + // instance we're computing the alias set for match the caller instance. |
| 1192 | + // |
| 1193 | + // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder. |
| 1194 | + // If we ever *do* start encoding the vtable index, we will need to generate an alias set |
| 1195 | + // based on which vtables we are putting this method into, as there will be more than one |
| 1196 | + // index value when supertraits are involved. |
| 1197 | + instance.def = ty::InstanceDef::Virtual(method_id, 0); |
| 1198 | + let abstract_trait_args = |
| 1199 | + tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); |
| 1200 | + instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args); |
| 1201 | + } |
| 1202 | + } else if tcx.is_closure_like(instance.def_id()) { |
| 1203 | + // We're either a closure or a coroutine. Our goal is to find the trait we're defined on, |
| 1204 | + // instantiate it, and take the type of its only method as our own. |
| 1205 | + let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); |
| 1206 | + let (trait_id, inputs) = match closure_ty.kind() { |
| 1207 | + ty::Closure(..) => { |
| 1208 | + let closure_args = instance.args.as_closure(); |
| 1209 | + let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap(); |
| 1210 | + let tuple_args = |
| 1211 | + tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0]; |
| 1212 | + (trait_id, tuple_args) |
| 1213 | + } |
| 1214 | + ty::Coroutine(..) => ( |
| 1215 | + tcx.require_lang_item(LangItem::Coroutine, None), |
| 1216 | + instance.args.as_coroutine().resume_ty(), |
| 1217 | + ), |
| 1218 | + ty::CoroutineClosure(..) => ( |
| 1219 | + tcx.require_lang_item(LangItem::FnOnce, None), |
| 1220 | + tcx.instantiate_bound_regions_with_erased( |
| 1221 | + instance.args.as_coroutine_closure().coroutine_closure_sig(), |
| 1222 | + ) |
| 1223 | + .tupled_inputs_ty, |
| 1224 | + ), |
| 1225 | + x => bug!("Unexpected type kind for closure-like: {x:?}"), |
| 1226 | + }; |
| 1227 | + let trait_ref = ty::TraitRef::new(tcx, trait_id, [closure_ty, inputs]); |
1177 | 1228 | let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
|
| 1229 | + let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); |
| 1230 | + // There should be exactly one method on this trait, and it should be the one we're |
| 1231 | + // defining. |
| 1232 | + let call = tcx |
| 1233 | + .associated_items(trait_id) |
| 1234 | + .in_definition_order() |
| 1235 | + .find(|it| it.kind == ty::AssocKind::Fn) |
| 1236 | + .expect("No call-family function on closure-like Fn trait?") |
| 1237 | + .def_id; |
1178 | 1238 |
|
1179 |
| - // At the call site, any call to this concrete function through a vtable will be |
1180 |
| - // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the |
1181 |
| - // original method id, and we've recovered the trait arguments, we can make the callee |
1182 |
| - // instance we're computing the alias set for match the caller instance. |
1183 |
| - // |
1184 |
| - // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder. |
1185 |
| - // If we ever *do* start encoding the vtable index, we will need to generate an alias set |
1186 |
| - // based on which vtables we are putting this method into, as there will be more than one |
1187 |
| - // index value when supertraits are involved. |
1188 |
| - instance.def = ty::InstanceDef::Virtual(method_id, 0); |
1189 |
| - let abstract_trait_args = |
1190 |
| - tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); |
1191 |
| - instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args); |
| 1239 | + instance.def = ty::InstanceDef::Virtual(call, 0); |
| 1240 | + instance.args = abstract_args; |
1192 | 1241 | }
|
1193 | 1242 | }
|
1194 | 1243 |
|
|
0 commit comments