Skip to content

Commit 4c604b4

Browse files
authored
Merge pull request #70777 from xedin/diagnostic-improvements-for-closures
[ConstraintSystem] Closure type-checking improvements
2 parents 597fb21 + 61d5ae9 commit 4c604b4

File tree

7 files changed

+66
-18
lines changed

7 files changed

+66
-18
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ ERROR(cannot_convert_argument_value_for_swift_func,none,
388388
NOTE(candidate_has_invalid_argument_at_position,none,
389389
"candidate expects %select{|in-out }2value of type %0 for parameter #%1 (got %3)",
390390
(Type, unsigned, bool, Type))
391+
NOTE(candidate_has_invalid_closure_at_position,none,
392+
"closure passed to parameter of type %0 that does not "
393+
"accept a closure", (Type))
391394

392395
ERROR(cannot_convert_array_to_variadic,none,
393396
"cannot pass array of type %0 as variadic arguments of type %1",
@@ -1547,9 +1550,9 @@ ERROR(extra_argument_to_nullary_call,none,
15471550
ERROR(extra_trailing_closure_in_call,none,
15481551
"extra trailing closure passed in "
15491552
"%select{call|subscript|macro expansion}0", (unsigned))
1550-
ERROR(trailing_closure_bad_param,none,
1551-
"trailing closure passed to parameter of type %0 that does not "
1552-
"accept a closure", (Type))
1553+
ERROR(closure_bad_param,none,
1554+
"%select{|trailing }1closure passed to parameter of type %0 that does not "
1555+
"accept a closure", (Type, bool))
15531556
WARNING(unlabeled_trailing_closure_deprecated,Deprecation,
15541557
"backward matching of the unlabeled trailing closure is deprecated; label the argument with %0 to suppress this warning",
15551558
(Identifier))

lib/Sema/CSDiagnostics.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5580,6 +5580,12 @@ bool MissingArgumentsFailure::isMisplacedMissingArgument(
55805580
auto argType = solution.simplifyType(solution.getType(unaryArg));
55815581
auto paramType = fnType->getParams()[1].getPlainType();
55825582

5583+
if (isExpr<ClosureExpr>(unaryArg) && argType->is<UnresolvedType>()) {
5584+
auto unwrappedParamTy = paramType->lookThroughAllOptionalTypes();
5585+
if (unwrappedParamTy->is<FunctionType>() || unwrappedParamTy->isAny())
5586+
return true;
5587+
}
5588+
55835589
return TypeChecker::isConvertibleTo(argType, paramType, solution.getDC());
55845590
}
55855591

@@ -7292,7 +7298,7 @@ bool ArgumentMismatchFailure::diagnoseAsError() {
72927298
if (diagnoseAttemptedRegexBuilder())
72937299
return true;
72947300

7295-
if (diagnoseTrailingClosureMismatch())
7301+
if (diagnoseClosureMismatch())
72967302
return true;
72977303

72987304
if (diagnoseKeyPathAsFunctionResultMismatch())
@@ -7346,10 +7352,15 @@ bool ArgumentMismatchFailure::diagnoseAsError() {
73467352
bool ArgumentMismatchFailure::diagnoseAsNote() {
73477353
auto *locator = getLocator();
73487354
if (auto *callee = getCallee()) {
7349-
emitDiagnosticAt(callee, diag::candidate_has_invalid_argument_at_position,
7350-
getToType(), getParamPosition(),
7351-
locator->isLastElement<LocatorPathElt::LValueConversion>(),
7352-
getFromType());
7355+
if (isExpr<ClosureExpr>(getAnchor())) {
7356+
emitDiagnosticAt(callee, diag::candidate_has_invalid_closure_at_position,
7357+
getToType());
7358+
} else {
7359+
emitDiagnosticAt(callee, diag::candidate_has_invalid_argument_at_position,
7360+
getToType(), getParamPosition(),
7361+
locator->isLastElement<LocatorPathElt::LValueConversion>(),
7362+
getFromType());
7363+
}
73537364
return true;
73547365
}
73557366

@@ -7633,15 +7644,16 @@ bool ArgumentMismatchFailure::diagnoseAttemptedRegexBuilder() const {
76337644
return true;
76347645
}
76357646

7636-
bool ArgumentMismatchFailure::diagnoseTrailingClosureMismatch() const {
7637-
if (!Info.isTrailingClosure())
7647+
bool ArgumentMismatchFailure::diagnoseClosureMismatch() const {
7648+
if (!isExpr<ClosureExpr>(getAnchor()))
76387649
return false;
76397650

76407651
auto paramType = getToType();
76417652
if (paramType->lookThroughAllOptionalTypes()->is<AnyFunctionType>())
76427653
return false;
76437654

7644-
emitDiagnostic(diag::trailing_closure_bad_param, paramType)
7655+
emitDiagnostic(diag::closure_bad_param, paramType,
7656+
Info.isTrailingClosure())
76457657
.highlight(getSourceRange());
76467658

76477659
if (auto overload = getCalleeOverloadChoiceIfAvailable(getLocator())) {

lib/Sema/CSDiagnostics.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,9 +2120,9 @@ class ArgumentMismatchFailure : public ContextualFailure {
21202120
/// or now deprecated `init(initialValue:)`.
21212121
bool diagnosePropertyWrapperMismatch() const;
21222122

2123-
/// Tailored diagnostics for argument mismatches associated with trailing
2123+
/// Tailored diagnostics for argument mismatches associated with (trailing)
21242124
/// closures being passed to non-closure parameters.
2125-
bool diagnoseTrailingClosureMismatch() const;
2125+
bool diagnoseClosureMismatch() const;
21262126

21272127
/// Tailored key path as function diagnostics for argument mismatches where
21282128
/// argument is a keypath expression that has a root type that matches a

lib/Sema/CSSimplify.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11554,6 +11554,28 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
1155411554
return true;
1155511555
};
1155611556

11557+
// If contextual type is not a function type or `Any` and this
11558+
// closure is used as an argument, let's skip resolution.
11559+
//
11560+
// Doing so improves performance if closure is passed as an argument
11561+
// to a (heavily) overloaded declaration, avoid unrelated errors,
11562+
// propagate holes, and record a more impactful fix.
11563+
if (!contextualType->isTypeVariableOrMember() &&
11564+
!(contextualType->is<FunctionType>() || contextualType->isAny()) &&
11565+
locator.endsWith<LocatorPathElt::ApplyArgToParam>()) {
11566+
if (!shouldAttemptFixes())
11567+
return false;
11568+
11569+
assignFixedType(typeVar, PlaceholderType::get(getASTContext(), typeVar),
11570+
closureLocator);
11571+
recordTypeVariablesAsHoles(inferredClosureType);
11572+
11573+
return !recordFix(
11574+
AllowArgumentMismatch::create(*this, typeVar, contextualType,
11575+
getConstraintLocator(locator)),
11576+
/*impact=*/15);
11577+
}
11578+
1155711579
// Determine whether a result builder will be applied.
1155811580
auto resultBuilderType = getOpenedResultBuilderTypeFor(*this, locator);
1155911581

test/Constraints/closures.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1153,7 +1153,7 @@ struct R_76250381<Result, Failure: Error> {
11531153
func rdar77022842(argA: Bool? = nil, argB: Bool? = nil) {
11541154
if let a = argA ?? false, if let b = argB ?? {
11551155
// expected-error@-1 {{initializer for conditional binding must have Optional type, not 'Bool'}}
1156-
// expected-error@-2 {{cannot convert value of type '() -> ()' to expected argument type 'Bool?'}}
1156+
// expected-error@-2 {{closure passed to parameter of type 'Bool?' that does not accept a closure}}
11571157
// expected-error@-3 {{cannot convert value of type 'Void' to expected condition type 'Bool'}}
11581158
} // expected-error {{expected '{' after 'if' condition}}
11591159
}
@@ -1247,3 +1247,14 @@ do {
12471247

12481248

12491249
}
1250+
1251+
do {
1252+
func test(_: Int, _: Int) {}
1253+
// expected-note@-1 {{closure passed to parameter of type 'Int' that does not accept a closure}}
1254+
func test(_: Int, _: String) {}
1255+
// expected-note@-1 {{closure passed to parameter of type 'String' that does not accept a closure}}
1256+
1257+
test(42) { // expected-error {{no exact matches in call to local function 'test'}}
1258+
print($0)
1259+
}
1260+
}

test/Sema/property_wrapper_parameter_invalid.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,12 +262,12 @@ struct ProjectionWrapper<Value> {
262262

263263
func testInvalidWrapperInference() {
264264
struct S<V> {
265-
static func test(_ keyPath: KeyPath<V, String>) {} // expected-note {{'test' declared here}}
265+
static func test(_ keyPath: KeyPath<V, String>) {} // expected-note 2 {{'test' declared here}}
266266
}
267267

268268
// expected-error@+1 {{trailing closure passed to parameter of type 'KeyPath<Int, String>' that does not accept a closure}}
269269
S<Int>.test { $value in }
270-
// expected-error@+1 {{cannot convert value of type '(_) -> ()' to expected argument type 'KeyPath<Int, String>'}}
270+
// expected-error@+1 {{closure passed to parameter of type 'KeyPath<Int, String>' that does not accept a closure}}
271271
S<Int>.test({ $value in })
272272

273273
func testGenericClosure<T>(_ closure: T) {}

test/expr/closure/closures.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ func funcdecl5(_ a: Int, _ y: Int) {
4242
func6({($0) + $0}) // // expected-error {{contextual closure type '(Int, Int) -> Int' expects 2 arguments, but 1 was used in closure body}}
4343

4444

45-
var testfunc : ((), Int) -> Int // expected-note {{'testfunc' declared here}}
45+
var testfunc : ((), Int) -> Int // expected-note 2 {{'testfunc' declared here}}
4646
testfunc({$0+1}) // expected-error {{missing argument for parameter #2 in call}}
47-
// expected-error@-1 {{cannot convert value of type '(Int) -> Int' to expected argument type '()'}}
47+
// expected-error@-1 {{closure passed to parameter of type '()' that does not accept a closure}}
4848

4949
funcdecl5(1, 2) // recursion.
5050

0 commit comments

Comments
 (0)