@@ -6,14 +6,17 @@ mod simd;
66
77use std:: assert_matches:: assert_matches;
88
9- use rustc_abi:: { FieldIdx , HasDataLayout , Size , VariantIdx } ;
9+ use rustc_abi:: { FIRST_VARIANT , FieldIdx , HasDataLayout , Size , VariantIdx } ;
1010use rustc_apfloat:: ieee:: { Double , Half , Quad , Single } ;
11+ use rustc_hir:: def_id:: CRATE_DEF_ID ;
12+ use rustc_infer:: infer:: TyCtxtInferExt ;
1113use rustc_middle:: mir:: interpret:: { CTFE_ALLOC_SALT , read_target_uint, write_target_uint} ;
1214use rustc_middle:: mir:: { self , BinOp , ConstValue , NonDivergingIntrinsic } ;
1315use rustc_middle:: ty:: layout:: TyAndLayout ;
14- use rustc_middle:: ty:: { FloatTy , Ty , TyCtxt } ;
16+ use rustc_middle:: ty:: { FloatTy , PolyExistentialPredicate , Ty , TyCtxt , TypeFoldable } ;
1517use rustc_middle:: { bug, span_bug, ty} ;
1618use rustc_span:: { Symbol , sym} ;
19+ use rustc_trait_selection:: traits:: { Obligation , ObligationCause , ObligationCtxt } ;
1720use tracing:: trace;
1821
1922use super :: memory:: MemoryKind ;
@@ -219,6 +222,49 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
219222
220223 self . write_scalar ( Scalar :: from_target_usize ( offset, self ) , dest) ?;
221224 }
225+ sym:: vtable_for => {
226+ let tp_ty = instance. args . type_at ( 0 ) ;
227+ let result_ty = instance. args . type_at ( 1 ) ;
228+
229+ ensure_monomorphic_enough ( tcx, tp_ty) ?;
230+ ensure_monomorphic_enough ( tcx, result_ty) ?;
231+ let ty:: Dynamic ( preds, _) = result_ty. kind ( ) else {
232+ span_bug ! (
233+ self . find_closest_untracked_caller_location( ) ,
234+ "Invalid type provided to vtable_for::<T, U>. U must be dyn Trait, got {result_ty}."
235+ ) ;
236+ } ;
237+
238+ let ( infcx, param_env) =
239+ self . tcx . infer_ctxt ( ) . build_with_typing_env ( self . typing_env ) ;
240+
241+ let ocx = ObligationCtxt :: new ( & infcx) ;
242+ ocx. register_obligations ( preds. iter ( ) . map ( |pred : PolyExistentialPredicate < ' _ > | {
243+ let pred = pred. with_self_ty ( tcx, tp_ty) ;
244+ // Lifetimes can only be 'static because of the bound on T
245+ let pred = pred. fold_with ( & mut ty:: BottomUpFolder {
246+ tcx,
247+ ty_op : |ty| ty,
248+ lt_op : |lt| {
249+ if lt == tcx. lifetimes . re_erased { tcx. lifetimes . re_static } else { lt }
250+ } ,
251+ ct_op : |ct| ct,
252+ } ) ;
253+ Obligation :: new ( tcx, ObligationCause :: dummy ( ) , param_env, pred)
254+ } ) ) ;
255+ let type_impls_trait = ocx. evaluate_obligations_error_on_ambiguity ( ) . is_empty ( ) ;
256+ // Since `assumed_wf_tys=[]` the choice of LocalDefId is irrelevant, so using the "default"
257+ let regions_are_valid = ocx. resolve_regions ( CRATE_DEF_ID , param_env, [ ] ) . is_empty ( ) ;
258+
259+ if regions_are_valid && type_impls_trait {
260+ let vtable_ptr = self . get_vtable_ptr ( tp_ty, preds) ?;
261+ // Writing a non-null pointer into an `Option<NonNull>` will automatically make it `Some`.
262+ self . write_pointer ( vtable_ptr, dest) ?;
263+ } else {
264+ // Write `None`
265+ self . write_discriminant ( FIRST_VARIANT , dest) ?;
266+ }
267+ }
222268 sym:: variant_count => {
223269 let tp_ty = instance. args . type_at ( 0 ) ;
224270 let ty = match tp_ty. kind ( ) {
0 commit comments