@@ -519,7 +519,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
519
519
}
520
520
}
521
521
// 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) => {
523
523
let mut args = args. to_vec ( ) ;
524
524
// We have to implement all "object safe receivers". So we have to go search for a
525
525
// 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> {
552
552
}
553
553
}
554
554
} ;
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 ( ) {
566
567
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" )
570
576
} ;
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
+ }
571
602
572
603
// `*mut receiver_place.layout.ty` is almost the layout that we
573
604
// want for args[0]: We have to project to field 0 because we want
0 commit comments