Skip to content

Commit 124b293

Browse files
authored
Merge pull request #8252 from huonw/underscore-label
[Parser] Don't warn about unescaping the _ in foo(`_`: 3).
2 parents 2c19ceb + 49277e4 commit 124b293

File tree

3 files changed

+44
-39
lines changed

3 files changed

+44
-39
lines changed

include/swift/Parse/Parser.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,9 +1145,12 @@ class Parser {
11451145
ParserResult<Expr> parseExprStringLiteral();
11461146
ParserResult<Expr> parseExprTypeOf();
11471147

1148-
/// If the token is an escaped identifier being used as an argument
1149-
/// label, but doesn't need to be, diagnose it.
1150-
void diagnoseEscapedArgumentLabel(const Token &tok);
1148+
/// Parse an argument label `identifier ':'`, if it exists.
1149+
///
1150+
/// \param name The parsed name of the label (empty if it doesn't exist, or is
1151+
/// _)
1152+
/// \param loc The location of the label (empty if it doesn't exist)
1153+
void parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc);
11511154

11521155
/// Parse an unqualified-decl-name.
11531156
///

lib/Parse/ParseExpr.cpp

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,15 +1771,31 @@ ParserResult<Expr> Parser::parseExprStringLiteral() {
17711771
Loc, Context.AllocateCopy(Exprs)));
17721772
}
17731773

1774-
void Parser::diagnoseEscapedArgumentLabel(const Token &tok) {
1775-
assert(tok.isEscapedIdentifier() && "Only for escaped identifiers");
1776-
if (!canBeArgumentLabel(tok.getText())) return;
1777-
1778-
SourceLoc start = tok.getLoc();
1779-
SourceLoc end = start.getAdvancedLoc(tok.getLength());
1780-
diagnose(tok, diag::escaped_parameter_name, tok.getText())
1781-
.fixItRemoveChars(start, start.getAdvancedLoc(1))
1782-
.fixItRemoveChars(end.getAdvancedLoc(-1), end);
1774+
void Parser::parseOptionalArgumentLabel(Identifier &name, SourceLoc &loc) {
1775+
// Check to see if there is an argument label.
1776+
if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) {
1777+
auto text = Tok.getText();
1778+
1779+
// If this was an escaped identifier that need not have been escaped, say
1780+
// so. Only _ needs escaping, because we take foo(_: 3) to be equivalent
1781+
// to foo(3), to be more uniform with _ in function declaration as well as
1782+
// the syntax for referring to the function pointer (foo(_:)),
1783+
auto escaped = Tok.isEscapedIdentifier();
1784+
auto underscore = Tok.is(tok::kw__) || (escaped && text == "_");
1785+
if (escaped && !underscore && canBeArgumentLabel(text)) {
1786+
SourceLoc start = Tok.getLoc();
1787+
SourceLoc end = start.getAdvancedLoc(Tok.getLength());
1788+
diagnose(Tok, diag::escaped_parameter_name, text)
1789+
.fixItRemoveChars(start, start.getAdvancedLoc(1))
1790+
.fixItRemoveChars(end.getAdvancedLoc(-1), end);
1791+
}
1792+
1793+
auto unescapedUnderscore = underscore && !escaped;
1794+
if (!unescapedUnderscore)
1795+
name = Context.getIdentifier(text);
1796+
loc = consumeToken();
1797+
consumeToken(tok::colon);
1798+
}
17831799
}
17841800

17851801
DeclName Parser::parseUnqualifiedDeclName(bool afterDot,
@@ -1834,20 +1850,12 @@ DeclName Parser::parseUnqualifiedDeclName(bool afterDot,
18341850
argumentLabelLocs.push_back(consumeToken(tok::colon));
18351851
}
18361852

1837-
// If we see a potential argument label followed by a ':', consume
1838-
// it.
1839-
if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) {
1840-
// If this was an escaped identifier that need not have been escaped,
1841-
// say so.
1842-
if (Tok.isEscapedIdentifier())
1843-
diagnoseEscapedArgumentLabel(Tok);
1844-
1845-
if (Tok.is(tok::kw__))
1846-
argumentLabels.push_back(Identifier());
1847-
else
1848-
argumentLabels.push_back(Context.getIdentifier(Tok.getText()));
1849-
argumentLabelLocs.push_back(consumeToken());
1850-
(void)consumeToken(tok::colon);
1853+
Identifier argName;
1854+
SourceLoc argLoc;
1855+
parseOptionalArgumentLabel(argName, argLoc);
1856+
if (argLoc.isValid()) {
1857+
argumentLabels.push_back(argName);
1858+
argumentLabelLocs.push_back(argLoc);
18511859
continue;
18521860
}
18531861

@@ -2569,19 +2577,7 @@ ParserStatus Parser::parseExprList(tok leftTok, tok rightTok,
25692577
[&] () -> ParserStatus {
25702578
Identifier FieldName;
25712579
SourceLoc FieldNameLoc;
2572-
2573-
// Check to see if there is an argument label.
2574-
if (Tok.canBeArgumentLabel() && peekToken().is(tok::colon)) {
2575-
// If this was an escaped identifier that need not have been escaped,
2576-
// say so.
2577-
if (Tok.isEscapedIdentifier())
2578-
diagnoseEscapedArgumentLabel(Tok);
2579-
2580-
if (!Tok.is(tok::kw__))
2581-
FieldName = Context.getIdentifier(Tok.getText());
2582-
FieldNameLoc = consumeToken();
2583-
consumeToken(tok::colon);
2584-
}
2580+
parseOptionalArgumentLabel(FieldName, FieldNameLoc);
25852581

25862582
// See if we have an operator decl ref '(<op>)'. The operator token in
25872583
// this case lexes as a binary operator because it neither leads nor

test/decl/func/keyword-argument-labels.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,9 @@ func testCalls(_ range: SomeRange) {
4949
// Fix-Its
5050
paramName(0, `in`: range) // expected-warning{{keyword 'in' does not need to be escaped in argument list}}{{16-17=}}{{19-20=}}
5151
}
52+
53+
// rdar://problem/31077797
54+
func foo(`_`: Int) {}
55+
foo(`_`: 3)
56+
let f = foo(`_`:)
57+
f(3)

0 commit comments

Comments
 (0)