Skip to content

Commit e7ee507

Browse files
committed
Merge pull request swiftlang#1520 from dduan/SR-852
[Parser][Qol] improve diagnostic with missing "self." in init
2 parents 0d2f585 + ea0a2d3 commit e7ee507

File tree

4 files changed

+43
-15
lines changed

4 files changed

+43
-15
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ ERROR(subscript_static,none,
346346
"subscript cannot be marked %0", (StaticSpellingKind))
347347

348348
// initializer
349+
ERROR(invalid_nested_init,none,
350+
"missing '%select{super.|self.}0' at initializer invocation", (bool))
349351
ERROR(initializer_decl_wrong_scope,none,
350352
"initializers may only be declared within a type", ())
351353
ERROR(expected_lparen_initializer,PointsToFirstBadToken,

lib/Parse/ParseDecl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,11 @@ static bool isParenthesizedUnowned(Parser &P) {
17411741
bool Parser::isStartOfDecl() {
17421742
// If this is obviously not the start of a decl, then we're done.
17431743
if (!isKeywordPossibleDeclStart(Tok)) return false;
1744+
1745+
// 'init' invocation is not start of a declaration
1746+
if (Tok.is(tok::kw_init)) {
1747+
return !isa<ConstructorDecl>(CurDeclContext);
1748+
}
17441749

17451750
// The protocol keyword needs more checking to reject "protocol<Int>".
17461751
if (Tok.is(tok::kw_protocol)) {

lib/Parse/ParseStmt.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -410,22 +410,32 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl<ASTNode> &Entries,
410410
}
411411
} else {
412412
SourceLoc StartLoc = Tok.getLoc();
413-
ParserStatus ExprOrStmtStatus = parseExprOrStmt(Result);
414-
BraceItemsStatus |= ExprOrStmtStatus;
415-
if (ExprOrStmtStatus.isError())
416-
NeedParseErrorRecovery = true;
417-
diagnoseDiscardedClosure(*this, Result);
418-
if (ExprOrStmtStatus.isSuccess() && IsTopLevel) {
419-
// If this is a normal library, you can't have expressions or statements
420-
// outside at the top level.
421-
diagnose(StartLoc,
422-
Result.is<Stmt*>() ? diag::illegal_top_level_stmt
423-
: diag::illegal_top_level_expr);
424-
Result = ASTNode();
425-
}
413+
if (Tok.is(tok::kw_init)) {
414+
if (auto CD = dyn_cast<ConstructorDecl>(CurDeclContext)) {
415+
// Hint at missing 'self.' or 'super.' then skip this statement.
416+
bool isConvenient = CD->isConvenienceInit();
417+
diagnose(StartLoc, diag::invalid_nested_init, isConvenient)
418+
.fixItInsert(StartLoc, isConvenient ? "self." : "super.");
419+
NeedParseErrorRecovery = true;
420+
}
421+
} else {
422+
ParserStatus ExprOrStmtStatus = parseExprOrStmt(Result);
423+
BraceItemsStatus |= ExprOrStmtStatus;
424+
if (ExprOrStmtStatus.isError())
425+
NeedParseErrorRecovery = true;
426+
diagnoseDiscardedClosure(*this, Result);
427+
if (ExprOrStmtStatus.isSuccess() && IsTopLevel) {
428+
// If this is a normal library, you can't have expressions or
429+
// statements outside at the top level.
430+
diagnose(StartLoc,
431+
Result.is<Stmt*>() ? diag::illegal_top_level_stmt
432+
: diag::illegal_top_level_expr);
433+
Result = ASTNode();
434+
}
426435

427-
if (!Result.isNull())
428-
Entries.push_back(Result);
436+
if (!Result.isNull())
437+
Entries.push_back(Result);
438+
}
429439
}
430440

431441
if (!NeedParseErrorRecovery && !PreviousHadSemi && Tok.is(tok::semi)) {

test/Parse/init_deinit.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,14 @@ func barFunc() {
100100
} ()
101101
}
102102

103+
// SR-852
104+
class Aaron {
105+
init(x: Int) {}
106+
convenience init() { init(x: 1) } // expected-error {{missing 'self.' at initializer invocation}}
107+
}
108+
109+
class Theodosia: Aaron {
110+
init() {
111+
init(x: 2) // expected-error {{missing 'super.' at initializer invocation}}
112+
}
113+
}

0 commit comments

Comments
 (0)