Skip to content

Commit 14c7a3d

Browse files
committed
implement SE-0071 - Allow (most) keywords in member references
1 parent 973b2f7 commit 14c7a3d

File tree

7 files changed

+63
-28
lines changed

7 files changed

+63
-28
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ Note: This is in reverse chronological order, so newer entries are added to the
33
Swift 3.0
44
---------
55

6+
* [SE-0071](https://github.com/apple/swift-evolution/blob/master/proposals/0071-member-keywords.md):
7+
"Allow (most) keywords in member references" is implemented. This allows the
8+
use of members after a dot without backticks, e.g. "foo.default".
9+
610
* [SE-0057](https://github.com/apple/swift-evolution/blob/master/proposals/0057-importing-objc-generics.md):
711
Objective-C lightweight generic classes are now imported as generic types
812
in Swift. Because Objective-C generics are not represented at runtime,

include/swift/Parse/Parser.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,11 +1124,11 @@ class Parser {
11241124
/// identifier
11251125
/// identifier '(' ((identifier | '_') ':') + ')'
11261126
///
1127-
///
1128-
/// \param allowInit Whether to allow 'init' for initializers.
1127+
/// \param afterDot Whether this identifier is coming after a period, which
1128+
/// enables '.init' and '.default' like expressions.
11291129
/// \param loc Will be populated with the location of the name.
11301130
/// \param diag The diagnostic to emit if this is not a name.
1131-
DeclName parseUnqualifiedDeclName(bool allowInit, DeclNameLoc &loc,
1131+
DeclName parseUnqualifiedDeclName(bool afterDot, DeclNameLoc &loc,
11321132
const Diagnostic &diag);
11331133

11341134
Expr *parseExprIdentifier();

lib/Parse/ParseExpr.cpp

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -685,9 +685,7 @@ ParserResult<Expr> Parser::parseExprSuper() {
685685
}
686686

687687
DeclNameLoc nameLoc;
688-
DeclName name = parseUnqualifiedDeclName(
689-
/*allowInit=*/true,
690-
nameLoc,
688+
DeclName name = parseUnqualifiedDeclName(/*afterDot=*/true, nameLoc,
691689
diag::expected_identifier_after_super_dot_expr);
692690
if (!name)
693691
return nullptr;
@@ -894,7 +892,7 @@ getMagicIdentifierLiteralKind(tok Kind) {
894892
///
895893
/// expr-dot:
896894
/// expr-postfix '.' 'type'
897-
/// expr-postfix '.' identifier generic-args? expr-call-suffix?
895+
/// expr-postfix '.' (identifier|keyword) generic-args? expr-call-suffix?
898896
/// expr-postfix '.' integer_literal
899897
///
900898
/// expr-subscript:
@@ -1109,7 +1107,7 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
11091107
return Result;
11101108
}
11111109

1112-
Name = parseUnqualifiedDeclName(/*allowInit=*/true, NameLoc,
1110+
Name = parseUnqualifiedDeclName(/*afterDot=*/true, NameLoc,
11131111
diag::expected_identifier_after_dot_expr);
11141112
if (!Name) return nullptr;
11151113

@@ -1307,17 +1305,9 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
13071305
Result.setHasCodeCompletion();
13081306
return Result;
13091307
}
1310-
1311-
// Non-identifier cases.
1312-
if (Tok.isNot(tok::identifier, tok::kw_init)) {
1313-
checkForInputIncomplete();
1314-
diagnose(Tok, diag::expected_member_name);
1315-
return nullptr;
1316-
}
13171308

1318-
assert(Tok.isAny(tok::identifier, tok::kw_init));
13191309
DeclNameLoc NameLoc;
1320-
DeclName Name = parseUnqualifiedDeclName(/*allowInit=*/true,
1310+
DeclName Name = parseUnqualifiedDeclName(/*allowDot=*/true,
13211311
NameLoc,
13221312
diag::expected_member_name);
13231313
if (!Name) return nullptr;
@@ -1600,18 +1590,17 @@ void Parser::diagnoseEscapedArgumentLabel(const Token &tok) {
16001590
.fixItRemoveChars(end.getAdvancedLoc(-1), end);
16011591
}
16021592

1603-
DeclName Parser::parseUnqualifiedDeclName(bool allowInit,
1593+
DeclName Parser::parseUnqualifiedDeclName(bool afterDot,
16041594
DeclNameLoc &loc,
16051595
const Diagnostic &diag) {
16061596
// Consume the base name.
1607-
Identifier baseName;
1597+
Identifier baseName = Context.getIdentifier(Tok.getText());
16081598
SourceLoc baseNameLoc;
1609-
if (Tok.is(tok::kw_init) && allowInit) {
1610-
baseName = Context.Id_init;
1611-
baseNameLoc = consumeToken(tok::kw_init);
1612-
} else if (Tok.is(tok::identifier) || Tok.is(tok::kw_Self) ||
1613-
Tok.is(tok::kw_self)) {
1599+
if (Tok.is(tok::identifier) || Tok.is(tok::kw_Self) ||
1600+
Tok.is(tok::kw_self)) {
16141601
baseNameLoc = consumeIdentifier(&baseName);
1602+
} else if (afterDot && Tok.isKeyword()) {
1603+
baseNameLoc = consumeToken();
16151604
} else {
16161605
checkForInputIncomplete();
16171606
diagnose(Tok, diag);
@@ -1713,7 +1702,7 @@ Expr *Parser::parseExprIdentifier() {
17131702

17141703
// Parse the unqualified-decl-name.
17151704
DeclNameLoc loc;
1716-
DeclName name = parseUnqualifiedDeclName(/*allowInit=*/false, loc,
1705+
DeclName name = parseUnqualifiedDeclName(/*afterDot=*/false, loc,
17171706
diag::expected_expr);
17181707

17191708
SmallVector<TypeRepr*, 8> args;

test/IDE/complete_unresolved_members.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,12 @@ extension C7 {
217217
var cInst1 = C7()
218218
cInst1.extendedf1(.#^UNRESOLVED_26^#
219219

220+
221+
// This #if works around:
222+
// <rdar://problem/26057202> Crash in code completion on invalid input
223+
#if false
224+
#endif
225+
220226
func f() -> SomeEnum1 {
221227
return .#^UNRESOLVED_27^#
222228
}

test/expr/delayed-ident/enum.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ enum E1 {
55
case First
66
case Second(Int)
77
case Third(Int, Double)
8+
case `default`
89
}
910

1011
var e1: E1 = .First
1112
e1 = .Second(5)
1213
e1 = .Third(5, 3.14159)
1314

15+
e1 = .default // SE-0071
16+
1417
// Generic enumeration type
1518
enum E2<T> {
1619
case First

test/expr/postfix/dot/dot_keywords.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,38 @@
33
let x: Int = 1
44
let y: Int = x.self
55
let int: Int.Type = Int.self
6+
7+
8+
// SE-0071 - Allow (most) keywords in member references
9+
// https://github.com/apple/swift-evolution/blob/master/proposals/0071-member-keywords.md
10+
11+
struct SE0071Struct {
12+
var `default` : Int
13+
}
14+
15+
func f1(a : SE0071Struct) -> Int {
16+
return a.default
17+
}
18+
19+
func f2(a : SE0071Struct) -> Int {
20+
return a.`default`
21+
}
22+
23+
24+
enum SE0071Enum {
25+
case `case`
26+
}
27+
28+
func f2() -> SE0071Enum {
29+
return .case
30+
}
31+
32+
class SE0071Base {
33+
func `default`() {}
34+
}
35+
36+
class SE0071Derived : SE0071Base {
37+
func zonk() {
38+
super.default()
39+
}
40+
}

test/expr/unary/selector/selector.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,5 @@ func testParseErrors3(_ c1: C1) {
116116

117117
func testParseErrors4() {
118118
// Subscripts
119-
_ = #selector(C1.subscript) // expected-error{{expected member name following '.'}}
120-
// expected-error@-1{{consecutive statements on a line must be separated by ';'}}
121-
// expected-error@-2{{expected '(' for subscript parameters}}
119+
_ = #selector(C1.subscript) // expected-error{{type 'C1.Type' has no subscript members}}
122120
}

0 commit comments

Comments
 (0)