Skip to content

Commit 7882ddc

Browse files
[DiagnosticsQoI] SR-3600: Better recovery for trying to name an initializer, deinitializer, or subscript
Add a diagnostic to remove the name of an initializer, deinitializer, or subscript. The identifier token is consumed and skipped to prevent the parser from emitting additional error messages. Add tests to verify that the name is removed from initializers, deinitializers, and subscripts declared with a name.
1 parent 4db0ac6 commit 7882ddc

File tree

6 files changed

+37
-11
lines changed

6 files changed

+37
-11
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,8 @@ ERROR(subscript_decl_wrong_scope,none,
338338
"'subscript' functions may only be declared within a type", ())
339339
ERROR(expected_lparen_subscript,PointsToFirstBadToken,
340340
"expected '(' for subscript parameters", ())
341+
ERROR(subscript_has_name,PointsToFirstBadToken,
342+
"subscripts cannot have a name", ())
341343
ERROR(expected_arrow_subscript,PointsToFirstBadToken,
342344
"expected '->' for subscript element type", ())
343345
ERROR(expected_type_subscript,PointsToFirstBadToken,
@@ -360,12 +362,17 @@ ERROR(initializer_decl_wrong_scope,none,
360362
"initializers may only be declared within a type", ())
361363
ERROR(expected_lparen_initializer,PointsToFirstBadToken,
362364
"expected '(' for initializer parameters", ())
365+
ERROR(initializer_has_name,PointsToFirstBadToken,
366+
"initializers cannot have a name", ())
363367

364368
// Destructor
365369
ERROR(destructor_decl_outside_class,none,
366370
"deinitializers may only be declared within a class", ())
367371
ERROR(expected_lbrace_destructor,PointsToFirstBadToken,
368372
"expected '{' for deinitializer", ())
373+
ERROR(destructor_has_name,PointsToFirstBadToken,
374+
"deinitializers cannot have a name", ())
375+
369376
ERROR(opened_destructor_expected_rparen,none,
370377
"expected ')' to close parameter list", ())
371378
ERROR(destructor_params,none,

lib/Parse/ParseDecl.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5515,7 +5515,12 @@ parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
55155515
// '{'
55165516
if (!Tok.is(tok::l_brace)) {
55175517
if (!Tok.is(tok::l_brace) && !isInSILMode()) {
5518-
diagnose(Tok, diag::expected_lbrace_destructor);
5518+
if (Tok.is(tok::identifier)) {
5519+
diagnose(Tok, diag::destructor_has_name).fixItRemove(Tok.getLoc());
5520+
}
5521+
else {
5522+
diagnose(Tok, diag::expected_lbrace_destructor);
5523+
}
55195524
return nullptr;
55205525
}
55215526
}

lib/Parse/ParsePattern.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,16 +476,21 @@ Parser::parseSingleParameterClause(ParameterContextKind paramContext,
476476
if (!Tok.is(tok::l_paren)) {
477477
// If we don't have the leading '(', complain.
478478
Diag<> diagID;
479+
bool skipIdentifier = false;
479480
switch (paramContext) {
480481
case ParameterContextKind::Function:
481482
case ParameterContextKind::Operator:
482483
diagID = diag::func_decl_without_paren;
483484
break;
484485
case ParameterContextKind::Subscript:
485-
diagID = diag::expected_lparen_subscript;
486+
skipIdentifier = Tok.is(tok::identifier);
487+
diagID = skipIdentifier ? diag::subscript_has_name
488+
: diag::expected_lparen_subscript;
486489
break;
487490
case ParameterContextKind::Initializer:
488-
diagID = diag::expected_lparen_initializer;
491+
skipIdentifier = Tok.is(tok::identifier);
492+
diagID = skipIdentifier ? diag::initializer_has_name
493+
: diag::expected_lparen_initializer;
489494
break;
490495
case ParameterContextKind::Closure:
491496
case ParameterContextKind::Curried:
@@ -496,6 +501,12 @@ Parser::parseSingleParameterClause(ParameterContextKind paramContext,
496501
if (Tok.isAny(tok::l_brace, tok::arrow, tok::kw_throws, tok::kw_rethrows))
497502
diag.fixItInsertAfter(PreviousLoc, "()");
498503

504+
if (skipIdentifier) {
505+
diag.fixItRemove(Tok.getLoc());
506+
consumeToken();
507+
skipSingle();
508+
}
509+
499510
// Create an empty parameter list to recover.
500511
return makeParserErrorResult(
501512
ParameterList::createEmpty(Context, PreviousLoc, PreviousLoc));

test/Parse/init_deinit.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ struct FooStructConstructorC {
1717

1818
struct FooStructDeinitializerA {
1919
deinit // expected-error {{expected '{' for deinitializer}}
20+
deinit x // expected-error {{deinitializers cannot have a name}} {{10-12=}}
21+
deinit x() // expected-error {{deinitializers cannot have a name}} {{10-11=}}
2022
}
2123

2224
struct FooStructDeinitializerB {

test/Parse/recovery.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,10 @@ func a(s: S[{{g) -> Int {}
537537
// expected-error@+1{{expected an identifier to name generic parameter}}
538538
func F() { init<( } )} // expected-note {{did you mean 'F'?}}
539539

540+
struct InitializerWithName {
541+
init x() {} // expected-error {{initializers cannot have a name}} {{8-9=}}
542+
}
543+
540544
// rdar://20337695
541545
func f1() {
542546

test/Parse/subscripting.swift

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,8 @@ let y2 = Y2() // expected-note{{change 'let' to 'var' to make it mutable}}{{1-4=
8080
_ = y2[0] // expected-error{{cannot use mutating getter on immutable value: 'y2' is a 'let' constant}}
8181

8282
// Parsing errors
83-
// FIXME: Recovery here is horrible
8483
struct A0 {
85-
subscript // expected-error{{expected '(' for subscript parameters}}
84+
subscript // expected-error {{subscripts cannot have a name}} {{5-7=}}
8685
i : Int
8786
-> Int {
8887
get {
@@ -92,6 +91,10 @@ struct A0 {
9291
stored = value
9392
}
9493
}
94+
95+
subscript -> Int { // expected-error {{expected '(' for subscript parameters}} {{12-12=()}}
96+
return 1
97+
}
9598
}
9699

97100
struct A1 {
@@ -173,9 +176,3 @@ struct A8 {
173176
}
174177
}
175178
} // expected-error{{extraneous '}' at top level}} {{1-3=}}
176-
177-
struct A9 {
178-
subscript -> Int { // expected-error {{expected '(' for subscript parameters}} {{12-12=()}}
179-
return 1
180-
}
181-
}

0 commit comments

Comments
 (0)