@@ -759,7 +759,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
759
759
// `unsafe fn(arg0,arg1,...) -> _`
760
760
let closure_sig = substs_a. as_closure ( ) . sig ( ) ;
761
761
let unsafety = fn_ty. unsafety ( ) ;
762
- let pointer_ty = self . tcx . coerce_closure_fn_ty ( closure_sig, unsafety) ;
762
+ let pointer_ty =
763
+ self . tcx . mk_fn_ptr ( self . tcx . signature_unclosure ( closure_sig, unsafety) ) ;
763
764
debug ! ( "coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})" , a, b, pointer_ty) ;
764
765
self . unify_and (
765
766
pointer_ty,
@@ -875,23 +876,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
875
876
debug ! ( "coercion::try_find_coercion_lub({:?}, {:?})" , prev_ty, new_ty) ;
876
877
877
878
// Special-case that coercion alone cannot handle:
878
- // Two function item types of differing IDs or InternalSubsts.
879
- if let ( & ty:: FnDef ( ..) , & ty:: FnDef ( ..) ) = ( & prev_ty. kind , & new_ty. kind ) {
880
- // Don't reify if the function types have a LUB, i.e., they
881
- // are the same function and their parameters have a LUB.
882
- let lub_ty = self
883
- . commit_if_ok ( |_| self . at ( cause, self . param_env ) . lub ( prev_ty, new_ty) )
884
- . map ( |ok| self . register_infer_ok_obligations ( ok) ) ;
885
-
886
- if lub_ty. is_ok ( ) {
887
- // We have a LUB of prev_ty and new_ty, just return it.
888
- return lub_ty;
879
+ // Function items or non-capturing closures of differing IDs or InternalSubsts.
880
+ let ( a_sig, b_sig) = {
881
+ let is_capturing_closure = |ty| {
882
+ if let & ty:: Closure ( _, substs) = ty {
883
+ substs. as_closure ( ) . upvar_tys ( ) . next ( ) . is_some ( )
884
+ } else {
885
+ false
886
+ }
887
+ } ;
888
+ if is_capturing_closure ( & prev_ty. kind ) || is_capturing_closure ( & new_ty. kind ) {
889
+ ( None , None )
890
+ } else {
891
+ match ( & prev_ty. kind , & new_ty. kind ) {
892
+ ( & ty:: FnDef ( ..) , & ty:: FnDef ( ..) ) => {
893
+ // Don't reify if the function types have a LUB, i.e., they
894
+ // are the same function and their parameters have a LUB.
895
+ match self
896
+ . commit_if_ok ( |_| self . at ( cause, self . param_env ) . lub ( prev_ty, new_ty) )
897
+ {
898
+ // We have a LUB of prev_ty and new_ty, just return it.
899
+ Ok ( ok) => return Ok ( self . register_infer_ok_obligations ( ok) ) ,
900
+ Err ( _) => {
901
+ ( Some ( prev_ty. fn_sig ( self . tcx ) ) , Some ( new_ty. fn_sig ( self . tcx ) ) )
902
+ }
903
+ }
904
+ }
905
+ ( & ty:: Closure ( _, substs) , & ty:: FnDef ( ..) ) => {
906
+ let b_sig = new_ty. fn_sig ( self . tcx ) ;
907
+ let a_sig = self
908
+ . tcx
909
+ . signature_unclosure ( substs. as_closure ( ) . sig ( ) , b_sig. unsafety ( ) ) ;
910
+ ( Some ( a_sig) , Some ( b_sig) )
911
+ }
912
+ ( & ty:: FnDef ( ..) , & ty:: Closure ( _, substs) ) => {
913
+ let a_sig = prev_ty. fn_sig ( self . tcx ) ;
914
+ let b_sig = self
915
+ . tcx
916
+ . signature_unclosure ( substs. as_closure ( ) . sig ( ) , a_sig. unsafety ( ) ) ;
917
+ ( Some ( a_sig) , Some ( b_sig) )
918
+ }
919
+ ( & ty:: Closure ( _, substs_a) , & ty:: Closure ( _, substs_b) ) => (
920
+ Some ( self . tcx . signature_unclosure (
921
+ substs_a. as_closure ( ) . sig ( ) ,
922
+ hir:: Unsafety :: Normal ,
923
+ ) ) ,
924
+ Some ( self . tcx . signature_unclosure (
925
+ substs_b. as_closure ( ) . sig ( ) ,
926
+ hir:: Unsafety :: Normal ,
927
+ ) ) ,
928
+ ) ,
929
+ _ => ( None , None ) ,
930
+ }
889
931
}
890
-
932
+ } ;
933
+ if let ( Some ( a_sig) , Some ( b_sig) ) = ( a_sig, b_sig) {
891
934
// The signature must match.
892
- let a_sig = prev_ty. fn_sig ( self . tcx ) ;
893
935
let a_sig = self . normalize_associated_types_in ( new. span , & a_sig) ;
894
- let b_sig = new_ty. fn_sig ( self . tcx ) ;
895
936
let b_sig = self . normalize_associated_types_in ( new. span , & b_sig) ;
896
937
let sig = self
897
938
. at ( cause, self . param_env )
@@ -901,17 +942,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
901
942
902
943
// Reify both sides and return the reified fn pointer type.
903
944
let fn_ptr = self . tcx . mk_fn_ptr ( sig) ;
904
- for expr in exprs. iter ( ) . map ( |e| e. as_coercion_site ( ) ) . chain ( Some ( new) ) {
905
- // The only adjustment that can produce an fn item is
906
- // `NeverToAny`, so this should always be valid.
945
+ let prev_adjustment = match prev_ty. kind {
946
+ ty:: Closure ( ..) => Adjust :: Pointer ( PointerCast :: ClosureFnPointer ( a_sig. unsafety ( ) ) ) ,
947
+ ty:: FnDef ( ..) => Adjust :: Pointer ( PointerCast :: ReifyFnPointer ) ,
948
+ _ => unreachable ! ( ) ,
949
+ } ;
950
+ let next_adjustment = match new_ty. kind {
951
+ ty:: Closure ( ..) => Adjust :: Pointer ( PointerCast :: ClosureFnPointer ( b_sig. unsafety ( ) ) ) ,
952
+ ty:: FnDef ( ..) => Adjust :: Pointer ( PointerCast :: ReifyFnPointer ) ,
953
+ _ => unreachable ! ( ) ,
954
+ } ;
955
+ for expr in exprs. iter ( ) . map ( |e| e. as_coercion_site ( ) ) {
907
956
self . apply_adjustments (
908
957
expr,
909
- vec ! [ Adjustment {
910
- kind: Adjust :: Pointer ( PointerCast :: ReifyFnPointer ) ,
911
- target: fn_ptr,
912
- } ] ,
958
+ vec ! [ Adjustment { kind: prev_adjustment. clone( ) , target: fn_ptr } ] ,
913
959
) ;
914
960
}
961
+ self . apply_adjustments ( new, vec ! [ Adjustment { kind: next_adjustment, target: fn_ptr } ] ) ;
915
962
return Ok ( fn_ptr) ;
916
963
}
917
964
0 commit comments