Skip to content

Commit 96d16b1

Browse files
authored
Merge pull request #68716 from kavon/inverse-parsing
permit parsing of `~` in general type syntaxes
2 parents 4036246 + 0944d46 commit 96d16b1

File tree

8 files changed

+109
-27
lines changed

8 files changed

+109
-27
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,8 +2347,8 @@ ERROR(inferred_opaque_type,none,
23472347
"return type of another declaration", (Type))
23482348

23492349
// Inverse Constraints
2350-
ERROR(inverse_type_not_invertable,none,
2351-
"type %0 is not invertable", (Type))
2350+
ERROR(inverse_type_not_invertible,none,
2351+
"type %0 is not invertible", (Type))
23522352

23532353
// Extensions
23542354
ERROR(non_nominal_extension,none,

include/swift/AST/KnownProtocols.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ using KnownProtocolSet = FixedBitSet<NumKnownProtocols, KnownProtocolKind>;
4646

4747
/// Produces a set of all protocols that have an inverse, i.e., for every
4848
/// known protocol KP in the set, ~KP exists.
49-
KnownProtocolSet getInvertableProtocols();
49+
KnownProtocolSet getInvertibleProtocols();
5050

5151
/// Retrieve the name of the given known protocol.
5252
llvm::StringRef getProtocolName(KnownProtocolKind kind);

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ llvm::StringRef swift::getProtocolName(KnownProtocolKind kind) {
102102
llvm_unreachable("bad KnownProtocolKind");
103103
}
104104

105-
KnownProtocolSet swift::getInvertableProtocols() {
105+
KnownProtocolSet swift::getInvertibleProtocols() {
106106
return { KnownProtocolKind::Copyable };
107107
}
108108

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ void swift::rewriting::realizeInheritedRequirements(
732732
auto inheritedTypes = decl->getInherited();
733733
auto *dc = decl->getInnermostDeclContext();
734734
auto *moduleForInference = dc->getParentModule();
735-
auto defaults = getInvertableProtocols();
735+
auto defaults = getInvertibleProtocols();
736736

737737
for (auto index : inheritedTypes.getIndices()) {
738738
Type inheritedType =

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);

lib/Sema/TypeCheckType.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5040,10 +5040,10 @@ NeverNullType TypeResolver::resolveInverseType(InverseTypeRepr *repr,
50405040
if (auto protoTy = ty->getAs<ProtocolType>())
50415041
if (auto protoDecl = protoTy->getDecl())
50425042
if (auto kp = protoDecl->getKnownProtocolKind())
5043-
if (getInvertableProtocols().contains(*kp))
5043+
if (getInvertibleProtocols().contains(*kp))
50445044
return ty;
50455045

5046-
diagnoseInvalid(repr, repr->getLoc(), diag::inverse_type_not_invertable, ty);
5046+
diagnoseInvalid(repr, repr->getLoc(), diag::inverse_type_not_invertible, ty);
50475047
return ErrorType::get(getASTContext());
50485048
}
50495049

test/Interop/Cxx/class/protocol-conformance-typechecker.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ protocol HasReturnNonNull {
2828
extension ReturnsNonNullValue: HasReturnNonNull {}
2929

3030

31-
protocol Invertable {
31+
protocol Invertible {
3232
static prefix func !(obj: Self) -> Self
3333
}
3434

35-
extension HasOperatorExclaim: Invertable {}
35+
extension HasOperatorExclaim: Invertible {}
3636

3737
extension HasOperatorEqualEqual: Equatable {}
3838

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 invertible}}
13+
14+
let _: any (~Copyable & ~Equatable) // expected-error{{type 'Equatable' is not invertible}}
15+
16+
let _: ~Any // expected-error {{type 'Any' is not invertible}}
17+
let _: ~AnyObject // expected-error {{type 'AnyObject' is not invertible}}
18+
}
19+
20+
struct S4: ~(Copyable & Equatable) {} // expected-error {{type 'Copyable & Equatable' is not invertible}}
21+
22+
func blah<T>(_ t: T) where T: ~Copyable,
23+
T: ~Hashable {} // expected-error@:31 {{type 'Hashable' is not invertible}}
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 invertible}}
31+
}
32+
33+
protocol Sando { func make() }
34+
35+
class C: ~Copyable,
36+
~Sando // expected-error {{type 'Sando' is not invertible}}
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 invertible}}
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 invertible}}
77+
typealias Z2 = ~A.B.C // expected-error {{type 'A.B.C' is not invertible}}
78+
typealias Z3 = ~A? // expected-error {{type 'A?' is not invertible}}
79+
typealias Z4 = ~Rope<Int> // expected-error {{type 'Rope<Int>' is not invertible}}
80+
typealias Z5 = (~Int) -> Void // expected-error {{type 'Int' is not invertible}}
81+
typealias Z6 = ~() -> () // expected-error {{single argument function types require parentheses}}
82+
// expected-error@-1 {{type '()' is not invertible}}
83+
typealias Z7 = ~(Copyable & Hashable) // expected-error {{type 'Copyable & Hashable' is not invertible}}
84+
typealias Z8 = ~Copyable & Hashable

0 commit comments

Comments
 (0)