@@ -2173,6 +2173,11 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
2173
2173
Optional<std::function<bool (ArrayRef<OverloadChoice>)>> callback = None,
2174
2174
bool includeInaccessibleMembers = true);
2175
2175
2176
+ bool diagnoseTrailingClosureErrors (ApplyExpr *expr);
2177
+
2178
+ bool diagnoseClosureExpr (ClosureExpr *closureExpr, Type contextualType,
2179
+ std::function<bool (Type, Type)> resultTypeProcessor);
2180
+
2176
2181
bool visitExpr (Expr *E);
2177
2182
bool visitIdentityExpr (IdentityExpr *E);
2178
2183
bool visitTryExpr (TryExpr *E);
@@ -5525,7 +5530,7 @@ bool FailureDiagnosis::diagnoseParameterErrors(CalleeCandidateInfo &CCI,
5525
5530
// It could be that the argument doesn't conform to an archetype.
5526
5531
if (CCI.diagnoseGenericParameterErrors (badArgExpr))
5527
5532
return true ;
5528
-
5533
+
5529
5534
// Re-type-check the argument with the expected type of the candidate set.
5530
5535
// This should produce a specific and tailored diagnostic saying that the
5531
5536
// type mismatches with expectations.
@@ -5989,10 +5994,223 @@ static bool isCastToTypedPointer(ConstraintSystem *CS, const Expr *Fn,
5989
5994
return true ;
5990
5995
}
5991
5996
5997
+ static bool diagnoseClosureExplicitParameterMismatch (
5998
+ ConstraintSystem *const CS, SourceLoc loc,
5999
+ ArrayRef<AnyFunctionType::Param> params,
6000
+ ArrayRef<AnyFunctionType::Param> args) {
6001
+ // We are not trying to diagnose structural problems with top-level
6002
+ // arguments here.
6003
+ if (params.size () != args.size ())
6004
+ return false ;
6005
+
6006
+ for (unsigned i = 0 , n = params.size (); i != n; ++i) {
6007
+ auto paramType = params[i].getType ();
6008
+ auto argType = args[i].getType ();
6009
+
6010
+ if (auto paramFnType = paramType->getAs <AnyFunctionType>()) {
6011
+ if (auto argFnType = argType->getAs <AnyFunctionType>())
6012
+ return diagnoseClosureExplicitParameterMismatch (
6013
+ CS, loc, paramFnType->getParams (), argFnType->getParams ());
6014
+ }
6015
+
6016
+ if (!paramType || !argType || isUnresolvedOrTypeVarType (paramType) ||
6017
+ isUnresolvedOrTypeVarType (argType))
6018
+ continue ;
6019
+
6020
+ if (!CS->TC .isConvertibleTo (argType, paramType, CS->DC )) {
6021
+ CS->TC .diagnose (loc, diag::types_not_convertible, false , paramType,
6022
+ argType);
6023
+ return true ;
6024
+ }
6025
+ }
6026
+
6027
+ return false ;
6028
+ }
6029
+
6030
+ bool FailureDiagnosis::diagnoseTrailingClosureErrors (ApplyExpr *callExpr) {
6031
+ if (!callExpr->hasTrailingClosure ())
6032
+ return false ;
6033
+
6034
+ auto *fnExpr = callExpr->getFn ();
6035
+ auto *argExpr = callExpr->getArg ();
6036
+
6037
+ ClosureExpr *closureExpr = nullptr ;
6038
+ if (auto *PE = dyn_cast<ParenExpr>(argExpr)) {
6039
+ closureExpr = dyn_cast<ClosureExpr>(PE->getSubExpr ());
6040
+ } else {
6041
+ return false ;
6042
+ }
6043
+
6044
+ if (!closureExpr)
6045
+ return false ;
6046
+
6047
+ class CallResultListener : public ExprTypeCheckListener {
6048
+ Type expectedResultType;
6049
+
6050
+ public:
6051
+ explicit CallResultListener (Type resultType)
6052
+ : expectedResultType(resultType) {}
6053
+
6054
+ bool builtConstraints (ConstraintSystem &cs, Expr *expr) override {
6055
+ if (!expectedResultType)
6056
+ return false ;
6057
+
6058
+ auto resultType = cs.getType (expr);
6059
+ auto *locator = cs.getConstraintLocator (expr);
6060
+
6061
+ // Since we know that this is trailing closure, format of the
6062
+ // type could be like this - ((Input) -> Result) -> ClosureResult
6063
+ // which we can leverage to create specific conversion for
6064
+ // result type of the call itself, this might help us gain
6065
+ // some valuable contextual information.
6066
+ if (auto *fnType = resultType->getAs <AnyFunctionType>()) {
6067
+ cs.addConstraint (ConstraintKind::Conversion, fnType->getResult (),
6068
+ expectedResultType, locator);
6069
+ } else if (auto *typeVar = resultType->getAs <TypeVariableType>()) {
6070
+ auto tv =
6071
+ cs.createTypeVariable (cs.getConstraintLocator (expr),
6072
+ TVO_CanBindToLValue | TVO_CanBindToInOut |
6073
+ TVO_PrefersSubtypeBinding);
6074
+
6075
+ auto extInfo = FunctionType::ExtInfo ().withThrows ();
6076
+ auto fTy = FunctionType::get (ParenType::get (cs.getASTContext (), tv),
6077
+ expectedResultType, extInfo);
6078
+
6079
+ // Add a conversion constraint between the types.
6080
+ cs.addConstraint (ConstraintKind::Conversion, typeVar, fTy , locator,
6081
+ /* isFavored*/ true );
6082
+ }
6083
+
6084
+ return false ;
6085
+ }
6086
+ };
6087
+
6088
+ SmallVector<Type, 4 > possibleTypes;
6089
+ auto currentType = CS->getType (fnExpr);
6090
+
6091
+ // If current type has type variables or unresolved types
6092
+ // let's try to re-typecheck it to see if we can get some
6093
+ // more information about what is going on.
6094
+ if (currentType->hasTypeVariable () || currentType->hasUnresolvedType ()) {
6095
+ auto contextualType = CS->getContextualType ();
6096
+ CallResultListener listener (contextualType);
6097
+ CS->TC .getPossibleTypesOfExpressionWithoutApplying (
6098
+ fnExpr, CS->DC , possibleTypes, FreeTypeVariableBinding::UnresolvedType,
6099
+ &listener);
6100
+
6101
+ // Looks like there is there a contextual mismatch
6102
+ // related to function type, let's try to diagnose it.
6103
+ if (possibleTypes.empty () && contextualType &&
6104
+ !contextualType->hasUnresolvedType ())
6105
+ return diagnoseContextualConversionError ();
6106
+ } else {
6107
+ possibleTypes.push_back (currentType);
6108
+ }
6109
+
6110
+ for (auto type : possibleTypes) {
6111
+ auto *fnType = type->getAs <AnyFunctionType>();
6112
+ if (!fnType)
6113
+ continue ;
6114
+
6115
+ auto paramType = fnType->getInput ();
6116
+ switch (paramType->getKind ()) {
6117
+ case TypeKind::Tuple: {
6118
+ auto tuple = paramType->getAs <TupleType>();
6119
+ if (tuple->getNumElements () != 1 )
6120
+ continue ;
6121
+
6122
+ paramType = tuple->getElement (0 ).getType ();
6123
+ break ;
6124
+ }
6125
+
6126
+ case TypeKind::Paren:
6127
+ paramType = paramType->getWithoutParens ();
6128
+ break ;
6129
+
6130
+ default :
6131
+ return false ;
6132
+ }
6133
+
6134
+ if (auto paramFnType = paramType->getAs <AnyFunctionType>()) {
6135
+ auto closureType = CS->getType (closureExpr);
6136
+ if (auto *argFnType = closureType->getAs <AnyFunctionType>()) {
6137
+ auto *params = closureExpr->getParameters ();
6138
+ auto loc = params ? params->getStartLoc () : closureExpr->getStartLoc ();
6139
+ if (diagnoseClosureExplicitParameterMismatch (
6140
+ CS, loc, argFnType->getParams (), paramFnType->getParams ()))
6141
+ return true ;
6142
+ }
6143
+ }
6144
+
6145
+ auto processor = [&](Type resultType, Type expectedResultType) -> bool {
6146
+ if (resultType && expectedResultType) {
6147
+ if (!resultType->isEqual (expectedResultType)) {
6148
+ CS->TC .diagnose (closureExpr->getEndLoc (),
6149
+ diag::cannot_convert_closure_result, resultType,
6150
+ expectedResultType);
6151
+ return true ;
6152
+ }
6153
+
6154
+ // Looks like both actual and expected result types match,
6155
+ // there is nothing we can diagnose in this case.
6156
+ return false ;
6157
+ }
6158
+
6159
+ // If we got a result type, let's re-typecheck the function using it,
6160
+ // maybe we can find a problem where contextually we expect one type
6161
+ // but trailing closure produces completely different one.
6162
+ auto fnType = paramType->getAs <AnyFunctionType>();
6163
+ if (!fnType)
6164
+ return false ;
6165
+
6166
+ auto expectedArgType = FunctionType::get (fnType->getInput (), resultType,
6167
+ fnType->getExtInfo ());
6168
+
6169
+ auto expectedType =
6170
+ FunctionType::get (expectedArgType, CS->getContextualType ());
6171
+
6172
+ class ClosureCalleeListener : public ExprTypeCheckListener {
6173
+ Type contextualType;
6174
+
6175
+ public:
6176
+ explicit ClosureCalleeListener (Type contextualType)
6177
+ : contextualType(contextualType) {}
6178
+
6179
+ bool builtConstraints (ConstraintSystem &cs, Expr *expr) override {
6180
+ cs.addConstraint (ConstraintKind::Conversion, cs.getType (expr),
6181
+ contextualType, cs.getConstraintLocator (expr),
6182
+ /* isFavored*/ true );
6183
+ return false ;
6184
+ }
6185
+ };
6186
+
6187
+ ClosureCalleeListener listener (expectedType);
6188
+ return !typeCheckChildIndependently (callExpr->getFn (), Type (),
6189
+ CTP_CalleeResult, TCC_ForceRecheck,
6190
+ &listener);
6191
+ };
6192
+
6193
+ // Let's see if there are any structural problems with closure itself.
6194
+ if (diagnoseClosureExpr (closureExpr, paramType, processor))
6195
+ return true ;
6196
+ }
6197
+
6198
+ return false ;
6199
+ }
6200
+
5992
6201
bool FailureDiagnosis::visitApplyExpr (ApplyExpr *callExpr) {
5993
- // Type check the function subexpression to resolve a type for it if possible.
6202
+ // If this call involves trailing closure as an argument,
6203
+ // let's treat it specially, because re-typecheck of the
6204
+ // either function or arguments might results in diagnosing
6205
+ // of the unrelated problems due to luck of context.
6206
+ if (diagnoseTrailingClosureErrors (callExpr))
6207
+ return true ;
6208
+
6209
+ // Type check the function subexpression to resolve a type for it if
6210
+ // possible.
5994
6211
auto fnExpr = typeCheckChildIndependently (callExpr->getFn ());
5995
- if (!fnExpr) return true ;
6212
+ if (!fnExpr)
6213
+ return true ;
5996
6214
5997
6215
SWIFT_DEFER {
5998
6216
if (!fnExpr) return ;
@@ -6151,6 +6369,23 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
6151
6369
}
6152
6370
}
6153
6371
6372
+ // If there is a failing constraint associated with current constraint
6373
+ // system which points to the argument/parameter mismatch, let's use
6374
+ // that information while re-typechecking argument expression, this
6375
+ // makes it a lot easier to determine contextual mismatch.
6376
+ if (CS->failedConstraint && !hasTrailingClosure) {
6377
+ auto *constraint = CS->failedConstraint ;
6378
+ if (constraint->getKind () == ConstraintKind::ArgumentTupleConversion) {
6379
+ if (auto *locator = constraint->getLocator ()) {
6380
+ if (locator->getAnchor () == callExpr) {
6381
+ argType = constraint->getSecondType ();
6382
+ if (auto *typeVar = argType->getAs <TypeVariableType>())
6383
+ argType = CS->getFixedType (typeVar);
6384
+ }
6385
+ }
6386
+ }
6387
+ }
6388
+
6154
6389
// Get the expression result of type checking the arguments to the call
6155
6390
// independently, so we have some idea of what we're working with.
6156
6391
//
@@ -6629,9 +6864,36 @@ visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) {
6629
6864
return false ;
6630
6865
}
6631
6866
6867
+ static bool isInvalidClosureResultType (Type resultType) {
6868
+ return !resultType || resultType->hasUnresolvedType () ||
6869
+ resultType->hasTypeVariable () || resultType->hasArchetype ();
6870
+ }
6632
6871
6633
6872
bool FailureDiagnosis::visitClosureExpr (ClosureExpr *CE) {
6634
- auto contextualType = CS->getContextualType ();
6873
+ return diagnoseClosureExpr (
6874
+ CE, CS->getContextualType (),
6875
+ [&](Type resultType, Type expectedResultType) -> bool {
6876
+ if (isInvalidClosureResultType (expectedResultType))
6877
+ return false ;
6878
+
6879
+ // Following situations are possible:
6880
+ // * No result type - possible structurable problem in the body;
6881
+ // * Function result type - possible use of function without calling it,
6882
+ // which is properly diagnosed by actual type-check call.
6883
+ if (resultType && !resultType->getRValueType ()->is <AnyFunctionType>()) {
6884
+ if (!resultType->isEqual (expectedResultType)) {
6885
+ diagnose (CE->getEndLoc (), diag::cannot_convert_closure_result,
6886
+ resultType, expectedResultType);
6887
+ return true ;
6888
+ }
6889
+ }
6890
+ return false ;
6891
+ });
6892
+ }
6893
+
6894
+ bool FailureDiagnosis::diagnoseClosureExpr (
6895
+ ClosureExpr *CE, Type contextualType,
6896
+ std::function<bool (Type, Type)> resultTypeProcessor) {
6635
6897
// Look through IUO because it doesn't influence
6636
6898
// neither parameter nor return type diagnostics itself,
6637
6899
// but if we have function type inside, that might
@@ -6792,7 +7054,7 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) {
6792
7054
// - if the there is a result type associated with the closure;
6793
7055
// - and it's not a void type;
6794
7056
// - and it hasn't been explicitly written.
6795
- auto resultType = CS-> getResultType (CE );
7057
+ auto resultType = fnType-> getResult ( );
6796
7058
auto hasResult = [](Type resultType) -> bool {
6797
7059
return resultType && !resultType->isVoid ();
6798
7060
};
@@ -6912,6 +7174,9 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) {
6912
7174
if (!CE->hasSingleExpressionBody ())
6913
7175
return false ;
6914
7176
7177
+ if (isInvalidClosureResultType (expectedResultType))
7178
+ expectedResultType = Type ();
7179
+
6915
7180
// When we're type checking a single-expression closure, we need to reset the
6916
7181
// DeclContext to this closure for the recursive type checking. Otherwise,
6917
7182
// if there is a closure in the subexpression, we can violate invariants.
@@ -6937,19 +7202,8 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) {
6937
7202
auto type = CS->TC .getTypeOfExpressionWithoutApplying (
6938
7203
closure, CS->DC , decl, FreeTypeVariableBinding::Disallow);
6939
7204
6940
- Type resultType = type.hasValue () ? *type : Type ();
6941
-
6942
- // Following situations are possible:
6943
- // * No result type - possible structurable problem in the body;
6944
- // * Function result type - possible use of function without calling it,
6945
- // which is properly diagnosed by actual type-check call.
6946
- if (resultType && !resultType->getRValueType ()->is <AnyFunctionType>()) {
6947
- if (!resultType->isEqual (expectedResultType)) {
6948
- diagnose (closure->getEndLoc (), diag::cannot_convert_closure_result,
6949
- resultType, expectedResultType);
6950
- return true ;
6951
- }
6952
- }
7205
+ if (type && resultTypeProcessor (*type, expectedResultType))
7206
+ return true ;
6953
7207
}
6954
7208
6955
7209
// If the closure had an expected result type, use it.
@@ -6960,9 +7214,14 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) {
6960
7214
// let's run proper type-check with expected type and try to verify it.
6961
7215
6962
7216
auto CTP = expectedResultType ? CTP_ClosureResult : CTP_Unused;
6963
- if (!typeCheckChildIndependently (CE->getSingleExpressionBody (),
6964
- expectedResultType, CTP, TCCOptions (),
6965
- nullptr , false ))
7217
+ auto *bodyExpr = typeCheckChildIndependently (CE->getSingleExpressionBody (),
7218
+ expectedResultType, CTP,
7219
+ TCCOptions (), nullptr , false );
7220
+
7221
+ if (!bodyExpr)
7222
+ return true ;
7223
+
7224
+ if (resultTypeProcessor (bodyExpr->getType (), expectedResultType))
6966
7225
return true ;
6967
7226
}
6968
7227
@@ -6974,12 +7233,18 @@ bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) {
6974
7233
if (!fnType || fnType->isEqual (CS->getType (CE)))
6975
7234
return false ;
6976
7235
7236
+ auto contextualResultType = fnType->getResult ();
7237
+ // If the result type was unknown, it doesn't really make
7238
+ // sense to diagnose from expected to unknown here.
7239
+ if (isInvalidClosureResultType (contextualResultType))
7240
+ return false ;
7241
+
6977
7242
// If the closure had an explicitly written return type incompatible with
6978
7243
// the contextual type, diagnose that.
6979
7244
if (CE->hasExplicitResultType () &&
6980
7245
CE->getExplicitResultTypeLoc ().getTypeRepr ()) {
6981
7246
auto explicitResultTy = CE->getExplicitResultTypeLoc ().getType ();
6982
- if (fnType && !explicitResultTy->isEqual (fnType-> getResult () )) {
7247
+ if (fnType && !explicitResultTy->isEqual (contextualResultType )) {
6983
7248
auto repr = CE->getExplicitResultTypeLoc ().getTypeRepr ();
6984
7249
diagnose (repr->getStartLoc (), diag::incorrect_explicit_closure_result,
6985
7250
explicitResultTy, fnType->getResult ())
0 commit comments