@@ -56,7 +56,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
56
56
let sig = tcx. erase_late_bound_regions ( & ty. fn_sig ( tcx) ) ;
57
57
let arg_tys = sig. inputs ( ) ;
58
58
59
- build_call_shim ( tcx, instance, Some ( adjustment) , CallKind :: Indirect , Some ( arg_tys) )
59
+ build_call_shim ( tcx, instance, Some ( adjustment) , CallKind :: Indirect ( ty ) , Some ( arg_tys) )
60
60
}
61
61
// We are generating a call back to our def-id, which the
62
62
// codegen backend knows to turn to an actual call, be it
@@ -147,9 +147,9 @@ enum Adjustment {
147
147
}
148
148
149
149
#[ derive( Copy , Clone , Debug , PartialEq ) ]
150
- enum CallKind {
150
+ enum CallKind < ' tcx > {
151
151
/// Call the `FnPtr` that was passed as the receiver.
152
- Indirect ,
152
+ Indirect ( Ty < ' tcx > ) ,
153
153
154
154
/// Call a known `FnDef`.
155
155
Direct ( DefId ) ,
@@ -671,7 +671,7 @@ fn build_call_shim<'tcx>(
671
671
tcx : TyCtxt < ' tcx > ,
672
672
instance : ty:: InstanceDef < ' tcx > ,
673
673
rcvr_adjustment : Option < Adjustment > ,
674
- call_kind : CallKind ,
674
+ call_kind : CallKind < ' tcx > ,
675
675
untuple_args : Option < & [ Ty < ' tcx > ] > ,
676
676
) -> Body < ' tcx > {
677
677
debug ! (
@@ -684,6 +684,29 @@ fn build_call_shim<'tcx>(
684
684
let sig = tcx. fn_sig ( def_id) ;
685
685
let mut sig = tcx. erase_late_bound_regions ( & sig) ;
686
686
687
+ if let CallKind :: Indirect ( fnty) = call_kind {
688
+ // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
689
+ // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from
690
+ // the implemented `FnX` trait.
691
+
692
+ // Apply the opposite adjustment to the MIR input.
693
+ let mut inputs_and_output = sig. inputs_and_output . to_vec ( ) ;
694
+
695
+ // Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the
696
+ // fn arguments. `Self` may be passed via (im)mutable reference or by-value.
697
+ assert_eq ! ( inputs_and_output. len( ) , 3 ) ;
698
+
699
+ // `Self` is always the original fn type `ty`. The MIR call terminator is only defined for
700
+ // `FnDef` and `FnPtr` callees, not the `Self` type param.
701
+ let self_arg = & mut inputs_and_output[ 0 ] ;
702
+ * self_arg = match rcvr_adjustment. unwrap ( ) {
703
+ Adjustment :: Identity => fnty,
704
+ Adjustment :: Deref => tcx. mk_imm_ptr ( fnty) ,
705
+ Adjustment :: RefMut => tcx. mk_mut_ptr ( fnty) ,
706
+ } ;
707
+ sig. inputs_and_output = tcx. intern_type_list ( & inputs_and_output) ;
708
+ }
709
+
687
710
// FIXME(eddyb) avoid having this snippet both here and in
688
711
// `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
689
712
if let ty:: InstanceDef :: VtableShim ( ..) = instance {
@@ -737,7 +760,7 @@ fn build_call_shim<'tcx>(
737
760
738
761
let ( callee, mut args) = match call_kind {
739
762
// `FnPtr` call has no receiver. Args are untupled below.
740
- CallKind :: Indirect => ( rcvr. unwrap ( ) , vec ! [ ] ) ,
763
+ CallKind :: Indirect ( _ ) => ( rcvr. unwrap ( ) , vec ! [ ] ) ,
741
764
742
765
// `FnDef` call with optional receiver.
743
766
CallKind :: Direct ( def_id) => {
0 commit comments