Skip to content

Commit dec7f9f

Browse files
authored
Merge pull request #6863 from matthewcarroll/SR-3600-Better-recovery-for-naming-an-initializer-deinitializer-or-subscript
[DiagnosticsQoI] SR-3600: Better recovery for trying to name an initializer, deinitializer, or subscript
2 parents e43bc7e + f8f147e commit dec7f9f

File tree

6 files changed

+65
-8
lines changed

6 files changed

+65
-8
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: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5650,7 +5650,10 @@ parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
56505650
// '{'
56515651
if (!Tok.is(tok::l_brace)) {
56525652
if (!Tok.is(tok::l_brace) && !isInSILMode()) {
5653-
diagnose(Tok, diag::expected_lbrace_destructor);
5653+
if (Tok.is(tok::identifier)) {
5654+
diagnose(Tok, diag::destructor_has_name).fixItRemove(Tok.getLoc());
5655+
} else
5656+
diagnose(Tok, diag::expected_lbrace_destructor);
56545657
return nullptr;
56555658
}
56565659
}

lib/Parse/ParsePattern.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,16 +476,23 @@ 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+
peekToken().is(tok::l_paren);
488+
diagID = skipIdentifier ? diag::subscript_has_name
489+
: diag::expected_lparen_subscript;
486490
break;
487491
case ParameterContextKind::Initializer:
488-
diagID = diag::expected_lparen_initializer;
492+
skipIdentifier = Tok.is(tok::identifier) &&
493+
peekToken().is(tok::l_paren);
494+
diagID = skipIdentifier ? diag::initializer_has_name
495+
: diag::expected_lparen_initializer;
489496
break;
490497
case ParameterContextKind::Closure:
491498
case ParameterContextKind::Curried:
@@ -496,6 +503,12 @@ Parser::parseSingleParameterClause(ParameterContextKind paramContext,
496503
if (Tok.isAny(tok::l_brace, tok::arrow, tok::kw_throws, tok::kw_rethrows))
497504
diag.fixItInsertAfter(PreviousLoc, "()");
498505

506+
if (skipIdentifier) {
507+
diag.fixItRemove(Tok.getLoc());
508+
consumeToken();
509+
skipSingle();
510+
}
511+
499512
// Create an empty parameter list to recover.
500513
return makeParserErrorResult(
501514
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: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,22 @@ 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+
544+
struct InitializerWithNameAndParam {
545+
init a(b: Int) {} // expected-error {{initializers cannot have a name}} {{8-9=}}
546+
}
547+
548+
struct InitializerWithLabels {
549+
init c d: Int {}
550+
// expected-error @-1 {{expected '(' for initializer parameters}}
551+
// expected-error @-2 {{expected declaration}}
552+
// expected-error @-3 {{consecutive declarations on a line must be separated by ';'}}
553+
// expected-note @-5 {{in declaration of 'InitializerWithLabels'}}
554+
}
555+
540556
// rdar://20337695
541557
func f1() {
542558

test/Parse/subscripting.swift

Lines changed: 21 additions & 5 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 {{expected '(' for subscript parameters}}
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 {
@@ -172,10 +175,23 @@ struct A8 {
172175
stored = value
173176
}
174177
}
175-
} // expected-error{{extraneous '}' at top level}} {{1-3=}}
176178

177179
struct A9 {
178-
subscript -> Int { // expected-error {{expected '(' for subscript parameters}} {{12-12=()}}
179-
return 1
180+
subscript x() -> Int { // expected-error {{subscripts cannot have a name}} {{13-14=}}
181+
return 0
182+
}
183+
}
184+
185+
struct A10 {
186+
subscript x(i: Int) -> Int { // expected-error {{subscripts cannot have a name}} {{13-14=}}
187+
return 0
180188
}
181189
}
190+
191+
struct A11 {
192+
subscript x y : Int -> Int { // expected-error {{expected '(' for subscript parameters}}
193+
return 0
194+
}
195+
}
196+
197+
} // expected-error{{extraneous '}' at top level}} {{1-3=}}

0 commit comments

Comments
 (0)