@@ -2559,7 +2559,8 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
25592559 iterator_expr,
25602560 & [ ] ,
25612561 AutorefArgs :: No ,
2562- DontTupleArguments ) ;
2562+ DontTupleArguments ,
2563+ NoExpectation ) ;
25632564
25642565 match method {
25652566 Some ( method) => {
@@ -2601,7 +2602,8 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
26012602 callee_expr : & ast:: Expr ,
26022603 args_no_rcvr : & [ P < ast:: Expr > ] ,
26032604 autoref_args : AutorefArgs ,
2604- tuple_arguments : TupleArgumentsFlag )
2605+ tuple_arguments : TupleArgumentsFlag ,
2606+ expected : Expectation < ' tcx > )
26052607 -> ty:: FnOutput < ' tcx > {
26062608 if ty:: type_is_error ( method_fn_ty) {
26072609 let err_inputs = err_args ( fcx. tcx ( ) , args_no_rcvr. len ( ) ) ;
@@ -2614,6 +2616,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
26142616 check_argument_types ( fcx,
26152617 sp,
26162618 & err_inputs[ ] ,
2619+ & [ ] ,
26172620 args_no_rcvr,
26182621 autoref_args,
26192622 false ,
@@ -2623,9 +2626,15 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
26232626 match method_fn_ty. sty {
26242627 ty:: ty_bare_fn( _, ref fty) => {
26252628 // HACK(eddyb) ignore self in the definition (see above).
2629+ let expected_arg_tys = expected_types_for_fn_args ( fcx,
2630+ sp,
2631+ expected,
2632+ fty. sig . 0 . output ,
2633+ & fty. sig . 0 . inputs [ 1 ..] ) ;
26262634 check_argument_types ( fcx,
26272635 sp,
26282636 & fty. sig . 0 . inputs [ 1 ..] ,
2637+ & expected_arg_tys[ ] ,
26292638 args_no_rcvr,
26302639 autoref_args,
26312640 fty. sig . 0 . variadic ,
@@ -2645,6 +2654,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
26452654fn check_argument_types < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
26462655 sp : Span ,
26472656 fn_inputs : & [ Ty < ' tcx > ] ,
2657+ expected_arg_tys : & [ Ty < ' tcx > ] ,
26482658 args : & [ P < ast:: Expr > ] ,
26492659 autoref_args : AutorefArgs ,
26502660 variadic : bool ,
@@ -2659,6 +2669,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
26592669 1
26602670 } ;
26612671
2672+ let mut expected_arg_tys = expected_arg_tys;
26622673 let expected_arg_count = fn_inputs. len ( ) ;
26632674 let formal_tys = if tuple_arguments == TupleArguments {
26642675 let tuple_type = structurally_resolved_type ( fcx, sp, fn_inputs[ 0 ] ) ;
@@ -2671,23 +2682,32 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
26712682 if arg_types. len( ) == 1 { "" } else { "s" } ,
26722683 args. len( ) ,
26732684 if args. len( ) == 1 { " was" } else { "s were" } ) ;
2685+ expected_arg_tys = & [ ] [ ] ;
26742686 err_args ( fcx. tcx ( ) , args. len ( ) )
26752687 } else {
2688+ expected_arg_tys = match expected_arg_tys. get ( 0 ) {
2689+ Some ( & ty) => match ty. sty {
2690+ ty:: ty_tup( ref tys) => & * * tys,
2691+ _ => & [ ]
2692+ } ,
2693+ None => & [ ]
2694+ } ;
26762695 ( * arg_types) . clone ( )
26772696 }
26782697 }
26792698 _ => {
26802699 span_err ! ( tcx. sess, sp, E0059 ,
26812700 "cannot use call notation; the first type parameter \
26822701 for the function trait is neither a tuple nor unit") ;
2702+ expected_arg_tys = & [ ] [ ] ;
26832703 err_args ( fcx. tcx ( ) , args. len ( ) )
26842704 }
26852705 }
26862706 } else if expected_arg_count == supplied_arg_count {
2687- fn_inputs. iter ( ) . map ( |a| * a ) . collect ( )
2707+ fn_inputs. to_vec ( )
26882708 } else if variadic {
26892709 if supplied_arg_count >= expected_arg_count {
2690- fn_inputs. iter ( ) . map ( |a| * a ) . collect ( )
2710+ fn_inputs. to_vec ( )
26912711 } else {
26922712 span_err ! ( tcx. sess, sp, E0060 ,
26932713 "this function takes at least {} parameter{} \
@@ -2696,6 +2716,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
26962716 if expected_arg_count == 1 { "" } else { "s" } ,
26972717 supplied_arg_count,
26982718 if supplied_arg_count == 1 { " was" } else { "s were" } ) ;
2719+ expected_arg_tys = & [ ] [ ] ;
26992720 err_args ( fcx. tcx ( ) , supplied_arg_count)
27002721 }
27012722 } else {
@@ -2705,6 +2726,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
27052726 if expected_arg_count == 1 { "" } else { "s" } ,
27062727 supplied_arg_count,
27072728 if supplied_arg_count == 1 { " was" } else { "s were" } ) ;
2729+ expected_arg_tys = & [ ] [ ] ;
27082730 err_args ( fcx. tcx ( ) , supplied_arg_count)
27092731 } ;
27102732
@@ -2768,7 +2790,25 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
27682790 AutorefArgs :: No => { }
27692791 }
27702792
2771- check_expr_coercable_to_type ( fcx, & * * arg, formal_ty) ;
2793+ // The special-cased logic below has three functions:
2794+ // 1. Provide as good of an expected type as possible.
2795+ let expected = expected_arg_tys. get ( i) . map ( |& ty| {
2796+ Expectation :: rvalue_hint ( ty)
2797+ } ) ;
2798+
2799+ check_expr_with_unifier ( fcx, & * * arg,
2800+ expected. unwrap_or ( ExpectHasType ( formal_ty) ) ,
2801+ NoPreference , || {
2802+ // 2. Coerce to the most detailed type that could be coerced
2803+ // to, which is `expected_ty` if `rvalue_hint` returns an
2804+ // `ExprHasType(expected_ty)`, or the `formal_ty` otherwise.
2805+ let coerce_ty = expected. and_then ( |e| e. only_has_type ( fcx) ) ;
2806+ demand:: coerce ( fcx, arg. span , coerce_ty. unwrap_or ( formal_ty) , & * * arg) ;
2807+
2808+ // 3. Relate the expected type and the formal one,
2809+ // if the expected type was used for the coercion.
2810+ coerce_ty. map ( |ty| demand:: suptype ( fcx, arg. span , formal_ty, ty) ) ;
2811+ } ) ;
27722812 }
27732813 }
27742814 }
@@ -3008,6 +3048,45 @@ enum TupleArgumentsFlag {
30083048 TupleArguments ,
30093049}
30103050
3051+ /// Unifies the return type with the expected type early, for more coercions
3052+ /// and forward type information on the argument expressions.
3053+ fn expected_types_for_fn_args < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
3054+ call_span : Span ,
3055+ expected_ret : Expectation < ' tcx > ,
3056+ formal_ret : ty:: FnOutput < ' tcx > ,
3057+ formal_args : & [ Ty < ' tcx > ] )
3058+ -> Vec < Ty < ' tcx > > {
3059+ let expected_args = expected_ret. only_has_type ( fcx) . and_then ( |ret_ty| {
3060+ if let ty:: FnConverging ( formal_ret_ty) = formal_ret {
3061+ fcx. infcx ( ) . commit_regions_if_ok ( || {
3062+ // Attempt to apply a subtyping relationship between the formal
3063+ // return type (likely containing type variables if the function
3064+ // is polymorphic) and the expected return type.
3065+ // No argument expectations are produced if unification fails.
3066+ let origin = infer:: Misc ( call_span) ;
3067+ let ures = fcx. infcx ( ) . sub_types ( false , origin, formal_ret_ty, ret_ty) ;
3068+ // FIXME(#15760) can't use try! here, FromError doesn't default
3069+ // to identity so the resulting type is not constrained.
3070+ if let Err ( e) = ures {
3071+ return Err ( e) ;
3072+ }
3073+
3074+ // Record all the argument types, with the substitutions
3075+ // produced from the above subtyping unification.
3076+ Ok ( formal_args. iter ( ) . map ( |ty| {
3077+ fcx. infcx ( ) . resolve_type_vars_if_possible ( ty)
3078+ } ) . collect ( ) )
3079+ } ) . ok ( )
3080+ } else {
3081+ None
3082+ }
3083+ } ) . unwrap_or ( vec ! [ ] ) ;
3084+ debug ! ( "expected_types_for_fn_args(formal={} -> {}, expected={} -> {})" ,
3085+ formal_args. repr( fcx. tcx( ) ) , formal_ret. repr( fcx. tcx( ) ) ,
3086+ expected_args. repr( fcx. tcx( ) ) , expected_ret. repr( fcx. tcx( ) ) ) ;
3087+ expected_args
3088+ }
3089+
30113090/// Invariant:
30123091/// If an expression has any sub-expressions that result in a type error,
30133092/// inspecting that expression's type with `ty::type_is_error` will return
@@ -3029,12 +3108,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
30293108 expr. repr( fcx. tcx( ) ) , expected. repr( fcx. tcx( ) ) ) ;
30303109
30313110 // Checks a method call.
3032- fn check_method_call ( fcx : & FnCtxt ,
3033- expr : & ast:: Expr ,
3034- method_name : ast:: SpannedIdent ,
3035- args : & [ P < ast:: Expr > ] ,
3036- tps : & [ P < ast:: Ty > ] ,
3037- lvalue_pref : LvaluePreference ) {
3111+ fn check_method_call < ' a , ' tcx > ( fcx : & FnCtxt < ' a , ' tcx > ,
3112+ expr : & ast:: Expr ,
3113+ method_name : ast:: SpannedIdent ,
3114+ args : & [ P < ast:: Expr > ] ,
3115+ tps : & [ P < ast:: Ty > ] ,
3116+ expected : Expectation < ' tcx > ,
3117+ lvalue_pref : LvaluePreference ) {
30383118 let rcvr = & * args[ 0 ] ;
30393119 check_expr_with_lvalue_pref ( fcx, & * rcvr, lvalue_pref) ;
30403120
@@ -3071,7 +3151,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
30713151 expr,
30723152 & args[ 1 ..] ,
30733153 AutorefArgs :: No ,
3074- DontTupleArguments ) ;
3154+ DontTupleArguments ,
3155+ expected) ;
30753156
30763157 write_call ( fcx, expr, ret_ty) ;
30773158 }
@@ -3182,7 +3263,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
31823263 op_ex,
31833264 args,
31843265 autoref_args,
3185- DontTupleArguments ) {
3266+ DontTupleArguments ,
3267+ NoExpectation ) {
31863268 ty:: FnConverging ( result_type) => result_type,
31873269 ty:: FnDiverging => fcx. tcx ( ) . types . err
31883270 }
@@ -3198,7 +3280,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
31983280 op_ex,
31993281 args,
32003282 autoref_args,
3201- DontTupleArguments ) ;
3283+ DontTupleArguments ,
3284+ NoExpectation ) ;
32023285 fcx. tcx ( ) . types . err
32033286 }
32043287 }
@@ -4045,10 +4128,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
40454128 fcx. write_ty ( id, fcx. node_ty ( b. id ) ) ;
40464129 }
40474130 ast:: ExprCall ( ref callee, ref args) => {
4048- callee:: check_call ( fcx, expr, & * * callee, & args[ ] ) ;
4131+ callee:: check_call ( fcx, expr, & * * callee, & args[ ] , expected ) ;
40494132 }
40504133 ast:: ExprMethodCall ( ident, ref tps, ref args) => {
4051- check_method_call ( fcx, expr, ident, & args[ ] , & tps[ ] , lvalue_pref) ;
4134+ check_method_call ( fcx, expr, ident, & args[ ] , & tps[ ] , expected , lvalue_pref) ;
40524135 let arg_tys = args. iter ( ) . map ( |a| fcx. expr_ty ( & * * a) ) ;
40534136 let args_err = arg_tys. fold ( false ,
40544137 |rest_err, a| {
0 commit comments