Skip to content

Commit 54643c1

Browse files
committed
[Parser] allow ~Copyable to appear in more places
With `NoncopyableGenerics` enabled, we want to permit the syntax `any ~Copyable`, and `~Copyable` generally anywhere a type can be written. We also want to give proper error messages and deal with typealiases of `Copyable` correctly when `~` precedes some token other than `Copyable`. This patch defines the `~` operator to attach rather tightly to simple types like identifier-like types. The precedence order is roughly like this within the syntax of types, from higher to lower: 1. `.` (member lookup) 2. postfix optionals: `?`, `!` 3. inverse `~` 4. postfix `...`, etc. It's also invalid to write something like `~ any T`, as we'll treat `any` as if it were a type identifier. You must parenthesize such types to say `~(any T)`. Similarly, we parse `~T.Type` as `~(T.Type)` and not `(~T).Type`. That might be controversial, but I don't think inverses can ever support metatypes; they're not even "real" types. rdar://115913356
1 parent a69bcf8 commit 54643c1

File tree

2 files changed

+100
-18
lines changed

2 files changed

+100
-18
lines changed

lib/Parse/ParseType.cpp

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ LayoutConstraint Parser::parseLayoutConstraint(Identifier LayoutConstraintID) {
147147
/// type-simple '.Protocol'
148148
/// type-simple '?'
149149
/// type-simple '!'
150+
/// '~' type-simple
150151
/// type-collection
151152
/// type-array
152153
/// '_'
@@ -155,15 +156,6 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
155156
Diag<> MessageID, ParseTypeReason reason) {
156157
ParserResult<TypeRepr> ty;
157158

158-
159-
// Prevent the use of ~ as prefix for a type. We specially parse them
160-
// in inheritance clauses elsewhere.
161-
if (!EnabledNoncopyableGenerics && Tok.isTilde()) {
162-
auto tildeLoc = consumeToken();
163-
diagnose(tildeLoc, diag::cannot_suppress_here)
164-
.fixItRemoveChars(tildeLoc, tildeLoc);
165-
}
166-
167159
if (Tok.is(tok::kw_inout)
168160
|| (canHaveParameterSpecifierContextualKeyword()
169161
&& (Tok.getRawText().equals("__shared")
@@ -176,6 +168,15 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
176168
consumeToken();
177169
}
178170

171+
// Eat any '~' preceding the type.
172+
SourceLoc tildeLoc;
173+
if (Tok.isTilde() && !isInSILMode()) {
174+
tildeLoc = consumeToken();
175+
if (!EnabledNoncopyableGenerics)
176+
diagnose(tildeLoc, diag::cannot_suppress_here)
177+
.fixItRemoveChars(tildeLoc, tildeLoc);
178+
}
179+
179180
switch (Tok.getKind()) {
180181
case tok::kw_Self:
181182
case tok::identifier:
@@ -308,6 +309,12 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(
308309
break;
309310
}
310311

312+
// Wrap in an InverseTypeRepr if needed.
313+
if (EnabledNoncopyableGenerics && tildeLoc) {
314+
ty = makeParserResult(ty,
315+
new(Context) InverseTypeRepr(tildeLoc, ty.get()));
316+
}
317+
311318
return ty;
312319
}
313320

@@ -639,19 +646,10 @@ ParserResult<TypeRepr> Parser::parseType(
639646
new (Context) PackExpansionTypeRepr(repeatLoc, ty.get()));
640647
}
641648

642-
// Parse inverse '~'
643-
SourceLoc tildeLoc;
644-
if (EnabledNoncopyableGenerics && Tok.isTilde())
645-
tildeLoc = consumeToken();
646-
647649
auto ty = parseTypeScalar(MessageID, reason);
648650
if (ty.isNull())
649651
return ty;
650652

651-
// Attach `~` tightly to the parsed type.
652-
if (tildeLoc)
653-
ty = makeParserResult(ty, new(Context) InverseTypeRepr(tildeLoc, ty.get()));
654-
655653
// Parse vararg type 'T...'.
656654
if (Tok.isEllipsis()) {
657655
Tok.setKind(tok::ellipsis);

test/Parse/inverses.swift

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature NoncopyableGenerics
2+
3+
// REQUIRES: asserts
4+
5+
protocol U {}
6+
7+
enum Maybe<Thing: ~Copyable> : ~Copyable {}
8+
9+
func more() {
10+
let _: any ~Copyable = 19
11+
12+
let _: any ~Equatable = 19 // expected-error@:14 {{type 'Equatable' is not invertable}}
13+
14+
let _: any (~Copyable & ~Equatable) // expected-error{{type 'Equatable' is not invertable}}
15+
16+
let _: ~Any // expected-error {{type 'Any' is not invertable}}
17+
let _: ~AnyObject // expected-error {{type 'AnyObject' is not invertable}}
18+
}
19+
20+
struct S4: ~(Copyable & Equatable) {} // expected-error {{type 'Copyable & Equatable' is not invertable}}
21+
22+
func blah<T>(_ t: T) where T: ~Copyable,
23+
T: ~Hashable {} // expected-error@:31 {{type 'Hashable' is not invertable}}
24+
25+
func foo<T: ~Copyable>(x: T) {}
26+
27+
struct Buurap<T: ~Copyable> {}
28+
29+
protocol Foo where Self: ~Copyable {
30+
func test<T>(_ t: T) where T: ~Self // expected-error {{type 'Self' is not invertable}}
31+
}
32+
33+
protocol Sando { func make() }
34+
35+
class C: ~Copyable,
36+
~Sando // expected-error {{type 'Sando' is not invertable}}
37+
{}
38+
39+
public struct MoveOnlyS1<T> : ~Copyable { /*deinit {}*/ }
40+
public struct MoveOnlyS2<T: Equatable> : ~Copyable { /*deinit {}*/ }
41+
public struct MoveOnlyS3<T: ~Copyable> : ~Copyable { /*deinit {}*/ }
42+
43+
protocol Rope<Element>: Hashable, ~ Copyable {
44+
45+
associatedtype Element: ~Copyable
46+
}
47+
48+
extension S: ~Copyable {}
49+
50+
struct S: ~U, // expected-error {{type 'U' is not invertable}}
51+
~Copyable {}
52+
53+
func greenBay<each T: ~Copyable>(_ r: repeat each T) {}
54+
55+
typealias Clone = Copyable
56+
func dup<D: ~Clone>(_ d: D) {}
57+
58+
func superb(_ thing: some ~Copyable, thing2: some ~Clone) {}
59+
60+
func ownership1(_ t: borrowing any ~Equatable) {} // expected-error {{type 'Equatable' is not invertible}}
61+
62+
func ownership2(_ t: ~ borrowing Int) {} // expected-error {{cannot find type 'borrowing' in scope}}
63+
// expected-error@-1 {{unnamed parameters must be written with the empty name '_'}}
64+
// expected-error@-2 {{expected ',' separator}}
65+
66+
func ownership3(_ t: consuming some ~Clone) {}
67+
68+
func what(one: ~Copyable..., // expected-error {{type 'any Copyable' is not invertible}}
69+
two: ~(Copyable...) // expected-error {{variadic parameter cannot appear outside of a function parameter list}}
70+
// expected-error@-1 {{type 'any Copyable' is not invertible}}
71+
) {}
72+
73+
struct A { struct B { struct C {} } }
74+
75+
typealias Z1 = (~Copyable).Type // FIXME: should be an error
76+
typealias Z1 = ~Copyable.Type // expected-error {{type 'any Copyable.Type' is not invertable}}
77+
typealias Z2 = ~A.B.C // expected-error {{type 'A.B.C' is not invertable}}
78+
typealias Z3 = ~A? // expected-error {{type 'A?' is not invertable}}
79+
typealias Z4 = ~Rope<Int> // expected-error {{type 'Rope<Int>' is not invertable}}
80+
typealias Z5 = (~Int) -> Void // expected-error {{type 'Int' is not invertable}}
81+
typealias Z6 = ~() -> () // expected-error {{single argument function types require parentheses}}
82+
// expected-error@-1 {{type '()' is not invertable}}
83+
typealias Z7 = ~(Copyable & Hashable) // expected-error {{type 'Copyable & Hashable' is not invertable}}
84+
typealias Z8 = ~Copyable & Hashable

0 commit comments

Comments
 (0)