Skip to content

Commit 2118585

Browse files
committed
QoI: Provide a fix-it for repeated identifiers in function declarations
A function declaration like: func dog cow() {} ... yields a bunch of noisy diagnostics about expecting certain tokens, like "expected '(' in argument list of function declaration", or the dreaded "consecutive statements on a line must be separated by ';'". Instead, look for a repeated identifier in this position and affirm that the repeated identifier wasn't expected, suggesting that maybe this was a single identifier with a break in it. rdar://problem/25761940
1 parent 805b150 commit 2118585

File tree

3 files changed

+22
-0
lines changed

3 files changed

+22
-0
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,8 @@ ERROR(expected_pattern,PointsToFirstBadToken,
661661
"expected pattern", ())
662662
ERROR(keyword_cant_be_identifier,none,
663663
"keyword '%0' cannot be used as an identifier here", (StringRef))
664+
ERROR(repeated_identifier,none,
665+
"found an unexpected second identifier in %0 declaration; is there an accidental break?", (StringRef))
664666
NOTE(backticks_to_escape,none,
665667
"if this name is unavoidable, use backticks to escape it", ())
666668
ERROR(expected_rparen_tuple_pattern_list,none,

lib/Parse/ParseDecl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4458,6 +4458,16 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
44584458
diag::invalid_diagnostic);
44594459
if (NameStatus.isError())
44604460
return nullptr;
4461+
} else {
4462+
// We parsed an identifier for the function declaration. If we see another
4463+
// identifier, it might've been a single identifier that got broken by a
4464+
// space or newline accidentally.
4465+
if (Tok.isIdentifierOrUnderscore() && SimpleName.str().back() != '<') {
4466+
diagnose(Tok.getLoc(), diag::repeated_identifier, "function")
4467+
.fixItReplace(SourceRange(NameLoc, Tok.getLoc()),
4468+
NameTok.getText().str() + Tok.getText().str());
4469+
consumeToken();
4470+
}
44614471
}
44624472

44634473
DebuggerContextChange DCC(*this, SimpleName, DeclKind::Func);

test/Parse/invalid.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,13 @@ func repeat() {}
9797
let for = 2
9898
// expected-error @-1 {{keyword 'for' cannot be used as an identifier here}}
9999
// expected-note @-2 {{if this name is unavoidable, use backticks to escape it}} {{5-8=`for`}}
100+
101+
func dog cow() {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}} {{6-13=dogcow}}
102+
func friend ship<T>(x: T) {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}} {{6-17=friendship}}
103+
func were
104+
wolf() {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}} {{6-5=werewolf}}
105+
func hammer
106+
leavings<T>(x: T) {} // expected-error {{found an unexpected second identifier in function declaration; is there an accidental break?}} {{6-9=hammerleavings}}
107+
108+
prefix operator % {}
109+
prefix func %<T>(x: T) -> T { return x } // No error expected - the < is considered an identifier but is peeled off by the parser.

0 commit comments

Comments
 (0)