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
diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def
index 634aac2..3cc5824 100644
--- a/include/swift/AST/DiagnosticsParse.def
+++ b/include/swift/AST/DiagnosticsParse.def
@@ -338,6 +338,8 @@
"'subscript' functions may only be declared within a type", ())
ERROR(expected_lparen_subscript,PointsToFirstBadToken,
"expected '(' for subscript parameters", ())
+ERROR(subscript_has_name,PointsToFirstBadToken,
+ "subscripts cannot have a name", ())
ERROR(expected_arrow_subscript,PointsToFirstBadToken,
"expected '->' for subscript element type", ())
ERROR(expected_type_subscript,PointsToFirstBadToken,
@@ -360,12 +362,17 @@
"initializers may only be declared within a type", ())
ERROR(expected_lparen_initializer,PointsToFirstBadToken,
"expected '(' for initializer parameters", ())
+ERROR(initializer_has_name,PointsToFirstBadToken,
+ "initializers cannot have a name", ())
// Destructor
ERROR(destructor_decl_outside_class,none,
"deinitializers may only be declared within a class", ())
ERROR(expected_lbrace_destructor,PointsToFirstBadToken,
"expected '{' for deinitializer", ())
+ERROR(destructor_has_name,PointsToFirstBadToken,
+ "deinitializers cannot have a name", ())
+
ERROR(opened_destructor_expected_rparen,none,
"expected ')' to close parameter list", ())
ERROR(destructor_params,none,
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 5089b87..a78a5a3 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -5650,7 +5650,10 @@
// '{'
if (!Tok.is(tok::l_brace)) {
if (!Tok.is(tok::l_brace) && !isInSILMode()) {
- diagnose(Tok, diag::expected_lbrace_destructor);
+ if (Tok.is(tok::identifier)) {
+ diagnose(Tok, diag::destructor_has_name).fixItRemove(Tok.getLoc());
+ } else
+ diagnose(Tok, diag::expected_lbrace_destructor);
return nullptr;
}
}
diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp
index be068c4..e896c97 100644
--- a/lib/Parse/ParsePattern.cpp
+++ b/lib/Parse/ParsePattern.cpp
@@ -476,16 +476,23 @@
if (!Tok.is(tok::l_paren)) {
// If we don't have the leading '(', complain.
Diag<> diagID;
+ bool skipIdentifier = false;
switch (paramContext) {
case ParameterContextKind::Function:
case ParameterContextKind::Operator:
diagID = diag::func_decl_without_paren;
break;
case ParameterContextKind::Subscript:
- diagID = diag::expected_lparen_subscript;
+ skipIdentifier = Tok.is(tok::identifier) &&
+ peekToken().is(tok::l_paren);
+ diagID = skipIdentifier ? diag::subscript_has_name
+ : diag::expected_lparen_subscript;
break;
case ParameterContextKind::Initializer:
- diagID = diag::expected_lparen_initializer;
+ skipIdentifier = Tok.is(tok::identifier) &&
+ peekToken().is(tok::l_paren);
+ diagID = skipIdentifier ? diag::initializer_has_name
+ : diag::expected_lparen_initializer;
break;
case ParameterContextKind::Closure:
case ParameterContextKind::Curried:
@@ -496,6 +503,12 @@
if (Tok.isAny(tok::l_brace, tok::arrow, tok::kw_throws, tok::kw_rethrows))
diag.fixItInsertAfter(PreviousLoc, "()");
+ if (skipIdentifier) {
+ diag.fixItRemove(Tok.getLoc());
+ consumeToken();
+ skipSingle();
+ }
+
// Create an empty parameter list to recover.
return makeParserErrorResult(
ParameterList::createEmpty(Context, PreviousLoc, PreviousLoc));
diff --git a/test/Parse/init_deinit.swift b/test/Parse/init_deinit.swift
index 5497275..0df5060 100644
--- a/test/Parse/init_deinit.swift
+++ b/test/Parse/init_deinit.swift
@@ -17,6 +17,8 @@
struct FooStructDeinitializerA {
deinit // expected-error {{expected '{' for deinitializer}}
+ deinit x // expected-error {{deinitializers cannot have a name}} {{10-12=}}
+ deinit x() // expected-error {{deinitializers cannot have a name}} {{10-11=}}
}
struct FooStructDeinitializerB {
diff --git a/test/Parse/recovery.swift b/test/Parse/recovery.swift
index a8e0951..0fc3aef 100644
--- a/test/Parse/recovery.swift
+++ b/test/Parse/recovery.swift
@@ -537,6 +537,22 @@
// expected-error@+1{{expected an identifier to name generic parameter}}
func F() { init<( } )} // expected-note {{did you mean 'F'?}}
+struct InitializerWithName {
+ init x() {} // expected-error {{initializers cannot have a name}} {{8-9=}}
+}
+
+struct InitializerWithNameAndParam {
+ init a(b: Int) {} // expected-error {{initializers cannot have a name}} {{8-9=}}
+}
+
+struct InitializerWithLabels {
+ init c d: Int {}
+ // expected-error @-1 {{expected '(' for initializer parameters}}
+ // expected-error @-2 {{expected declaration}}
+ // expected-error @-3 {{consecutive declarations on a line must be separated by ';'}}
+ // expected-note @-5 {{in declaration of 'InitializerWithLabels'}}
+}
+
// rdar://20337695
func f1() {
diff --git a/test/Parse/subscripting.swift b/test/Parse/subscripting.swift
index a0182f9..0351c5b 100644
--- a/test/Parse/subscripting.swift
+++ b/test/Parse/subscripting.swift
@@ -80,9 +80,8 @@
_ = y2[0] // expected-error{{cannot use mutating getter on immutable value: 'y2' is a 'let' constant}}
// Parsing errors
-// FIXME: Recovery here is horrible
struct A0 {
- subscript // expected-error{{expected '(' for subscript parameters}}
+ subscript // expected-error {{expected '(' for subscript parameters}}
i : Int
-> Int {
get {
@@ -92,6 +91,10 @@
stored = value
}
}
+
+ subscript -> Int { // expected-error {{expected '(' for subscript parameters}} {{12-12=()}}
+ return 1
+ }
}
struct A1 {
@@ -172,10 +175,23 @@
stored = value
}
}
-} // expected-error{{extraneous '}' at top level}} {{1-3=}}
struct A9 {
- subscript -> Int { // expected-error {{expected '(' for subscript parameters}} {{12-12=()}}
- return 1
+ subscript x() -> Int { // expected-error {{subscripts cannot have a name}} {{13-14=}}
+ return 0
}
}
+
+struct A10 {
+ subscript x(i: Int) -> Int { // expected-error {{subscripts cannot have a name}} {{13-14=}}
+ return 0
+ }
+}
+
+struct A11 {
+ subscript x y : Int -> Int { // expected-error {{expected '(' for subscript parameters}}
+ return 0
+ }
+}
+
+} // expected-error{{extraneous '}' at top level}} {{1-3=}}