Skip to content

Commit 833c25c

Browse files
committed
Parser: Generalize : lookahead to disambiguate all parameter specifiers as argument labels
1 parent 2a187f2 commit 833c25c

File tree

6 files changed

+64
-19
lines changed

6 files changed

+64
-19
lines changed

include/swift/Parse/Parser.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1150,7 +1150,6 @@ class Parser {
11501150
// the following token is something that can introduce a type. Thankfully
11511151
// none of these tokens overlap with the set of tokens that can follow an
11521152
// identifier in a type production.
1153-
11541153
return Tok.is(tok::identifier)
11551154
&& peekToken().isAny(tok::at_sign,
11561155
tok::kw_inout,

lib/AST/ASTPrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1182,7 +1182,7 @@ void PrintAST::printAttributes(const Decl *D) {
11821182
}
11831183
}
11841184

1185-
// We will handle 'mutating' and 'nonmutating' separately.
1185+
// We will handle ownership specifiers separately.
11861186
if (isa<FuncDecl>(D)) {
11871187
Options.ExcludeAttrList.push_back(DAK_Mutating);
11881188
Options.ExcludeAttrList.push_back(DAK_NonMutating);

lib/Parse/ParsePattern.cpp

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,14 @@ bool Parser::startsParameterName(bool isClosure) {
171171
!Tok.is(tok::kw_repeat))
172172
return true;
173173

174-
// "isolated" can be an argument label, but it's also a contextual keyword,
175-
// so look ahead one more token (two total) see if we have a ':' that would
174+
// Parameter specifiers can be an argument label, but they're also
175+
// contextual keywords, so look ahead one more token (two total) and see
176+
// if we have a ':' that would
176177
// indicate that this is an argument label.
177178
return lookahead<bool>(2, [&](CancellableBacktrackingScope &) {
178179
if (Tok.is(tok::colon))
179180
return true; // isolated :
180181

181-
// isolated x :
182182
return Tok.canBeArgumentLabel() && nextTok.is(tok::colon);
183183
});
184184
}
@@ -262,6 +262,17 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
262262
|| Tok.isContextualKeyword("consuming")
263263
|| Tok.isContextualKeyword("isolated")
264264
|| Tok.isContextualKeyword("_const")))) {
265+
// is this token the identifier of an argument label?
266+
bool partOfArgumentLabel = lookahead<bool>(1, [&](CancellableBacktrackingScope &) {
267+
if (Tok.is(tok::colon))
268+
return true; // isolated :
269+
270+
return Tok.canBeArgumentLabel() && peekToken().is(tok::colon);
271+
});
272+
273+
if (partOfArgumentLabel)
274+
break;
275+
265276
if (Tok.isContextualKeyword("isolated")) {
266277
// did we already find an 'isolated' type modifier?
267278
if (param.IsolatedLoc.isValid()) {
@@ -271,18 +282,6 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
271282
continue;
272283
}
273284

274-
// is this 'isolated' token the identifier of an argument label?
275-
bool partOfArgumentLabel = lookahead<bool>(1, [&](CancellableBacktrackingScope &) {
276-
if (Tok.is(tok::colon))
277-
return true; // isolated :
278-
279-
// isolated x :
280-
return Tok.canBeArgumentLabel() && peekToken().is(tok::colon);
281-
});
282-
283-
if (partOfArgumentLabel)
284-
break;
285-
286285
// consume 'isolated' as type modifier
287286
param.IsolatedLoc = consumeToken();
288287
continue;

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3573,7 +3573,7 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
35733573
if (AdopterIsClass || !isa<AbstractStorageDecl>(Requirement))
35743574
Options.ExcludeAttrList.push_back(DAK_NonMutating);
35753575

3576-
// FIXME: Once we support move-only types, remove this if the
3576+
// FIXME: Once we support move-only types in generics, remove this if the
35773577
// conforming type is move-only. Until then, don't suggest printing
35783578
// __consuming on a protocol requirement.
35793579
Options.ExcludeAttrList.push_back(DAK_Consuming);

om.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
struct borrowing {}
4+
struct consuming {}
5+
6+
struct Foo {}
7+
8+
func foo(x: borrowing Foo) {}
9+
func bar(x: consuming Foo) {}
10+
func baz(x: (borrowing Foo, consuming Foo) -> ()) {}
11+
12+
//func bad(x: borrowing borrowing Foo) {} // expected-error{{at most one}}
13+
//func worse(x: borrowing consuming Foo) {} // expected-error{{at most one}}
14+
//func worst(x: (borrowing consuming Foo) -> ()) {} // expected-error{{at most one}}
15+
16+
// `borrowing` and `consuming` are contextual keywords, so they should also
17+
// continue working as type and/or parameter names
18+
19+
func zim(x: borrowing) {}
20+
func zang(x: consuming) {}
21+
func zung(x: borrowing consuming) {}
22+
func zip(x: consuming borrowing) {}
23+
func zap(x: (borrowing, consuming) -> ()) {}
24+
func zoop(x: (borrowing consuming, consuming borrowing) -> ()) {}
25+
26+
//func worster(x: borrowing borrowing borrowing) {} // expected-error{{at most one}}
27+
//func worstest(x: (borrowing borrowing borrowing) -> ()) {} // expected-error{{at most one}}

test/Parse/ownership_modifiers.swift

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// TODO: implement new parser support for borrowing and consuming modifiers
21
// RUN: %target-typecheck-verify-swift
32

43
struct borrowing {}
@@ -26,3 +25,24 @@ func zoop(x: (borrowing consuming, consuming borrowing) -> ()) {}
2625

2726
func worster(x: borrowing borrowing borrowing) {} // expected-error{{at most one}}
2827
func worstest(x: (borrowing borrowing borrowing) -> ()) {} // expected-error{{at most one}}
28+
29+
// Parameter specifier names are regular identifiers in other positions,
30+
// including argument labels.
31+
32+
func argumentLabel(borrowing consuming: Int) {}
33+
func argumentLabel(consuming borrowing: Int) {}
34+
func argumentLabel(__shared __owned: Int) {}
35+
func argumentLabel(__owned __shared: Int) {}
36+
37+
// We should parse them as argument labels in function types, even though that
38+
// isn't currently supported.
39+
40+
func argumentLabel(borrowingInClosure: (borrowing consuming: Int) -> ()) {} // expected-error{{function types cannot have argument labels}}
41+
func argumentLabel(consumingInClosure: (consuming borrowing: Int) -> ()) {} // expected-error{{function types cannot have argument labels}}
42+
func argumentLabel(sharedInClosure: (__shared __owned: Int) -> ()) {} // expected-error{{function types cannot have argument labels}}
43+
func argumentLabel(ownedInClosure: (__shared __owned: Int) -> ()) {} // expected-error{{function types cannot have argument labels}}
44+
45+
func argumentLabel(anonBorrowingInClosure: (_ consuming: Int) -> ()) {}
46+
func argumentLabel(anonConsumingInClosure: (_ borrowing: Int) -> ()) {}
47+
func argumentLabel(anonSharedInClosure: (_ __owned: Int) -> ()) {}
48+
func argumentLabel(anonOwnedInClosure: (_ __owned: Int) -> ()) {}

0 commit comments

Comments
 (0)