@@ -519,7 +519,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
519519 }
520520 }
521521 // cannot use the shim here, because that will only result in infinite recursion
522- ty:: InstanceDef :: Virtual ( _ , idx) => {
522+ ty:: InstanceDef :: Virtual ( def_id , idx) => {
523523 let mut args = args. to_vec ( ) ;
524524 // We have to implement all "object safe receivers". So we have to go search for a
525525 // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
@@ -552,22 +552,53 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
552552 }
553553 }
554554 } ;
555- // Find and consult vtable. The type now could be something like RcBox<dyn Trait>,
556- // i.e., it is still not necessarily `ty::Dynamic` (so we cannot use
557- // `place.vtable()`), but it should have a `dyn Trait` tail.
558- assert ! ( matches!(
559- self . tcx
560- . struct_tail_erasing_lifetimes( receiver_place. layout. ty, self . param_env)
561- . kind( ) ,
562- ty:: Dynamic ( ..)
563- ) ) ;
564- let vtable = self . scalar_to_ptr ( receiver_place. meta . unwrap_meta ( ) ) ?;
565- let Some ( ty:: VtblEntry :: Method ( fn_inst) ) = self . get_vtable_entries ( vtable) ?. get ( idx) . copied ( ) else {
555+ // Obtain the underlying trait we are working on.
556+ let receiver_tail = self
557+ . tcx
558+ . struct_tail_erasing_lifetimes ( receiver_place. layout . ty , self . param_env ) ;
559+ let ty:: Dynamic ( data, ..) = receiver_tail. kind ( ) else {
560+ span_bug ! ( self . cur_span( ) , "dyanmic call on non-`dyn` type {}" , receiver_tail)
561+ } ;
562+
563+ // Get the required information from the vtable.
564+ let vptr = self . scalar_to_ptr ( receiver_place. meta . unwrap_meta ( ) ) ?;
565+ let ( dyn_ty, dyn_trait) = self . get_ptr_vtable ( vptr) ?;
566+ if dyn_trait != data. principal ( ) {
566567 throw_ub_format ! (
567- "calling index {idx} of vtable {vtable} but \
568- that vtable is too small or does not have a method at that index"
569- )
568+ "`dyn` call on a pointer whose vtable does not match its type"
569+ ) ;
570+ }
571+
572+ // Now determine the actual method to call. We can do that in two different ways and
573+ // compare them to ensure everything fits.
574+ let ty:: VtblEntry :: Method ( fn_inst) = self . get_vtable_entries ( vptr) ?[ idx] else {
575+ span_bug ! ( self . cur_span( ) , "dyn call index points at something that is not a method" )
570576 } ;
577+ if cfg ! ( debug_assertions) {
578+ let tcx = * self . tcx ;
579+
580+ let trait_def_id = tcx. trait_of_item ( def_id) . unwrap ( ) ;
581+ let virtual_trait_ref =
582+ ty:: TraitRef :: from_method ( tcx, trait_def_id, instance. substs ) ;
583+ assert_eq ! (
584+ receiver_tail,
585+ virtual_trait_ref. self_ty( ) ,
586+ "mismatch in underlying dyn trait computation within Miri and MIR building" ,
587+ ) ;
588+ let existential_trait_ref =
589+ ty:: ExistentialTraitRef :: erase_self_ty ( tcx, virtual_trait_ref) ;
590+ let concrete_trait_ref = existential_trait_ref. with_self_ty ( tcx, dyn_ty) ;
591+
592+ let concrete_method = Instance :: resolve (
593+ tcx,
594+ self . param_env ,
595+ def_id,
596+ instance. substs . rebase_onto ( tcx, trait_def_id, concrete_trait_ref. substs ) ,
597+ )
598+ . unwrap ( )
599+ . unwrap ( ) ;
600+ assert_eq ! ( fn_inst, concrete_method) ;
601+ }
571602
572603 // `*mut receiver_place.layout.ty` is almost the layout that we
573604 // want for args[0]: We have to project to field 0 because we want
0 commit comments