@@ -56,7 +56,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
5656 let sig = tcx. erase_late_bound_regions ( & ty. fn_sig ( tcx) ) ;
5757 let arg_tys = sig. inputs ( ) ;
5858
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) )
6060 }
6161 // We are generating a call back to our def-id, which the
6262 // codegen backend knows to turn to an actual call, be it
@@ -147,9 +147,9 @@ enum Adjustment {
147147}
148148
149149#[ derive( Copy , Clone , Debug , PartialEq ) ]
150- enum CallKind {
150+ enum CallKind < ' tcx > {
151151 /// Call the `FnPtr` that was passed as the receiver.
152- Indirect ,
152+ Indirect ( Ty < ' tcx > ) ,
153153
154154 /// Call a known `FnDef`.
155155 Direct ( DefId ) ,
@@ -671,7 +671,7 @@ fn build_call_shim<'tcx>(
671671 tcx : TyCtxt < ' tcx > ,
672672 instance : ty:: InstanceDef < ' tcx > ,
673673 rcvr_adjustment : Option < Adjustment > ,
674- call_kind : CallKind ,
674+ call_kind : CallKind < ' tcx > ,
675675 untuple_args : Option < & [ Ty < ' tcx > ] > ,
676676) -> Body < ' tcx > {
677677 debug ! (
@@ -684,6 +684,29 @@ fn build_call_shim<'tcx>(
684684 let sig = tcx. fn_sig ( def_id) ;
685685 let mut sig = tcx. erase_late_bound_regions ( & sig) ;
686686
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+
687710 // FIXME(eddyb) avoid having this snippet both here and in
688711 // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
689712 if let ty:: InstanceDef :: VtableShim ( ..) = instance {
@@ -737,7 +760,7 @@ fn build_call_shim<'tcx>(
737760
738761 let ( callee, mut args) = match call_kind {
739762 // `FnPtr` call has no receiver. Args are untupled below.
740- CallKind :: Indirect => ( rcvr. unwrap ( ) , vec ! [ ] ) ,
763+ CallKind :: Indirect ( _ ) => ( rcvr. unwrap ( ) , vec ! [ ] ) ,
741764
742765 // `FnDef` call with optional receiver.
743766 CallKind :: Direct ( def_id) => {
0 commit comments