Skip to content

[Parse] Provide a diagnostic when a closure parameter is declared with type sugar #28315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions lib/Parse/ParsePattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ static bool startsParameterName(Parser &parser, bool isClosure) {
if (nextTok.is(tok::colon) || nextTok.canBeArgumentLabel())
return true;

if (parser.isOptionalToken(nextTok)
|| parser.isImplicitlyUnwrappedOptionalToken(nextTok))
return false;

// The identifier could be a name or it could be a type. In a closure, we
// assume it's a name, because the type can be inferred. Elsewhere, we
// assume it's a type.
Expand Down Expand Up @@ -373,8 +377,16 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
// SE-110 depending on the kind of declaration. We now need to
// warn about the misuse of this syntax and offer to
// fix it.
diagnose(typeStartLoc, diag::parameter_unnamed_warn)
.fixItInsert(typeStartLoc, "_: ");
// An exception to this rule is when the type is declared with type sugar
// Reference: SR-11724
if (isa<OptionalTypeRepr>(param.Type)
|| isa<ImplicitlyUnwrappedOptionalTypeRepr>(param.Type)) {
diagnose(typeStartLoc, diag::parameter_unnamed)
.fixItInsert(typeStartLoc, "_: ");
} else {
diagnose(typeStartLoc, diag::parameter_unnamed_warn)
.fixItInsert(typeStartLoc, "_: ");
}
}
}
} else {
Expand Down
15 changes: 7 additions & 8 deletions test/decl/func/functions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ func recover_colon_arrow_7() :Int { } // expected-error {{expected '->' after f

func recover_missing_body_1() // expected-error {{expected '{' in body of function declaration}}
func recover_missing_body_2() // expected-error {{expected '{' in body of function declaration}}
-> Int
-> Int

// Ensure that we don't skip over the 'func g' over to the right paren in
// function g, while recovering from parse error in f() parameter tuple. We
// should produce the error about missing right paren.
//
// FIXME: The errors are awful. We should produce just the error about paren.
func f_recover_missing_tuple_paren(_ a: Int // expected-note {{to match this opening '('}} expected-error{{expected '{' in body of function declaration}} expected-error {{expected ')' in parameter}}
func f_recover_missing_tuple_paren(_ a: Int // expected-note {{to match this opening '('}} expected-error{{expected '{' in body of function declaration}} expected-error {{expected ')' in parameter}}
func g_recover_missing_tuple_paren(_ b: Int) {
}

Expand Down Expand Up @@ -187,14 +187,13 @@ func bogusDestructuring() {
struct Bar {}

struct Foo {
func registerCallback(_ callback: @escaping ([Bar]) -> Void) {} // expected-note {{found this candidate}}
func registerCallback(_ callback: @escaping ([String: Bar]) -> Void) {} // expected-note {{found this candidate}}
func registerCallback(_ callback: @escaping (Bar?) -> Void) {} // expected-note {{found this candidate}}
func registerCallback(_ callback: @escaping ([Bar]) -> Void) {}
func registerCallback(_ callback: @escaping ([String: Bar]) -> Void) {}
func registerCallback(_ callback: @escaping (Bar?) -> Void) {}
}

Foo().registerCallback { ([Bar]) in } // expected-warning {{unnamed parameters must be written with the empty name '_'}} {{29-29=_: }}
Foo().registerCallback { ([String: Bar]) in }// expected-warning {{unnamed parameters must be written with the empty name '_'}} {{29-29=_: }}
Foo().registerCallback { (Bar?) in } // expected-error {{ambiguous use of 'registerCallback'}}
// expected-error@-1 {{expected parameter name followed by ':'}}
// expected-error@-2 {{expected ',' separator}}
Foo().registerCallback { (Bar?) in } // expected-error {{unnamed parameters must be written with the empty name '_'}}

}