Skip to content

Commit 7bebc84

Browse files
authored
Merge pull request swiftlang#10426 from huonw/number-function
[Parse] Provide better diagnostics for `func 1() {}`.
2 parents fc18cb8 + 61606a6 commit 7bebc84

File tree

3 files changed

+100
-1
lines changed

3 files changed

+100
-1
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ ERROR(expected_decl,none,
182182
"expected declaration", ())
183183
ERROR(expected_identifier_in_decl,none,
184184
"expected identifier in %0 declaration", (StringRef))
185+
ERROR(number_cant_start_decl_name,none,
186+
"%0 name can only start with a letter or underscore, not a number",
187+
(StringRef))
185188
ERROR(expected_identifier_after_case_comma,none,
186189
"expected identifier after comma in enum 'case' declaration", ())
187190
ERROR(decl_redefinition,none,

lib/Parse/ParseDecl.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2766,6 +2766,23 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc,
27662766

27672767
P.checkForInputIncomplete();
27682768

2769+
if (P.Tok.is(tok::integer_literal) || P.Tok.is(tok::floating_literal) ||
2770+
(P.Tok.is(tok::unknown) && isdigit(P.Tok.getText()[0]))) {
2771+
// Per rdar://problem/32316666, using numbers for identifiers is a common
2772+
// error for beginners, so it's worth handling this in a special way.
2773+
P.diagnose(P.Tok, diag::number_cant_start_decl_name, DeclKindName);
2774+
2775+
// Pretend this works as an identifier, which shouldn't be observable since
2776+
// actual uses of it will hit random other errors, e.g. `1()` won't be
2777+
// callable.
2778+
Result = P.Context.getIdentifier(P.Tok.getText());
2779+
Loc = P.Tok.getLoc();
2780+
P.consumeToken();
2781+
2782+
// We recovered, so this is a success.
2783+
return makeParserSuccess();
2784+
}
2785+
27692786
if (P.Tok.isKeyword()) {
27702787
P.diagnose(P.Tok, diag::keyword_cant_be_identifier, P.Tok.getText());
27712788
P.diagnose(P.Tok, diag::backticks_to_escape)
@@ -4708,7 +4725,12 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
47084725
Token NameTok = Tok;
47094726
SourceLoc NameLoc;
47104727

4711-
if (Tok.is(tok::identifier) || Tok.isKeyword()) {
4728+
if (Tok.isAny(tok::identifier, tok::integer_literal, tok::floating_literal,
4729+
tok::unknown) ||
4730+
Tok.isKeyword()) {
4731+
// This non-operator path is quite accepting of what tokens might be a name,
4732+
// because we're aggressive about recovering/providing good diagnostics for
4733+
// beginners.
47124734
ParserStatus NameStatus =
47134735
parseIdentifierDeclName(*this, SimpleName, NameLoc, "function",
47144736
tok::l_paren, tok::arrow, tok::l_brace,
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// Per rdar://problem/32316666 , it is a common mistake for beginners
4+
// to start a function name with a number, so it's worth
5+
// special-casing the diagnostic to make it clearer.
6+
7+
func 1() {}
8+
// expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
9+
func 2.0() {}
10+
// expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
11+
func 3func() {}
12+
// expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
13+
// expected-error@-2 {{expected a digit after integer literal prefix}}
14+
15+
protocol 4 {
16+
// expected-error@-1 {{protocol name can only start with a letter or underscore, not a number}}
17+
associatedtype 5
18+
// expected-error@-1 {{associatedtype name can only start with a letter or underscore, not a number}}
19+
}
20+
protocol 6.0 {
21+
// expected-error@-1 {{protocol name can only start with a letter or underscore, not a number}}
22+
associatedtype 7.0
23+
// expected-error@-1 {{associatedtype name can only start with a letter or underscore, not a number}}
24+
}
25+
protocol 8protocol {
26+
// expected-error@-1 {{protocol name can only start with a letter or underscore, not a number}}
27+
// expected-error@-2 {{expected a digit after integer literal prefix}}
28+
associatedtype 9associatedtype
29+
// expected-error@-1 {{associatedtype name can only start with a letter or underscore, not a number}}
30+
// expected-error@-2 {{expected a digit after integer literal prefix}}
31+
}
32+
33+
typealias 10 = Int
34+
// expected-error@-1 {{typealias name can only start with a letter or underscore, not a number}}
35+
typealias 11.0 = Int
36+
// expected-error@-1 {{typealias name can only start with a letter or underscore, not a number}}
37+
typealias 12typealias = Int
38+
// expected-error@-1 {{typealias name can only start with a letter or underscore, not a number}}
39+
// expected-error@-2 {{expected a digit after integer literal prefix}}
40+
41+
struct 13 {}
42+
// expected-error@-1 {{struct name can only start with a letter or underscore, not a number}}
43+
struct 14.0 {}
44+
// expected-error@-1 {{struct name can only start with a letter or underscore, not a number}}
45+
struct 15struct {}
46+
// expected-error@-1 {{struct name can only start with a letter or underscore, not a number}}
47+
// expected-error@-2 {{expected a digit after integer literal prefix}}
48+
49+
enum 16 {}
50+
// expected-error@-1 {{enum name can only start with a letter or underscore, not a number}}
51+
enum 17.0 {}
52+
// expected-error@-1 {{enum name can only start with a letter or underscore, not a number}}
53+
enum 18enum {}
54+
// expected-error@-1 {{enum name can only start with a letter or underscore, not a number}}
55+
// expected-error@-2 {{expected a digit in floating point exponent}}
56+
57+
class 19 {
58+
// expected-error@-1 {{class name can only start with a letter or underscore, not a number}}
59+
func 20() {}
60+
// expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
61+
}
62+
class 21.0 {
63+
// expected-error@-1 {{class name can only start with a letter or underscore, not a number}}
64+
func 22.0() {}
65+
// expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
66+
}
67+
68+
class 23class {
69+
// expected-error@-1 {{class name can only start with a letter or underscore, not a number}}
70+
// expected-error@-2 {{expected a digit after integer literal prefix}}
71+
func 24method() {}
72+
// expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
73+
// expected-error@-2 {{expected a digit after integer literal prefix}}
74+
}

0 commit comments

Comments
 (0)