Skip to content

Commit 51e90ee

Browse files
committed
[move-only] Ban creating protocol conformances on move only nominal types.
I added code to the type checker that both bans this when one adds the conformance on the nominal type declaration as well as on extensions. I was careful to ensure we can still add extensions without an inherited clause. Doing this until we get the full generics model. rdar://101874019
1 parent b95b19b commit 51e90ee

File tree

5 files changed

+71
-18
lines changed

5 files changed

+71
-18
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6710,13 +6710,11 @@ NOTE(moveonly_copyable_type_that_contains_moveonly_type_location, none,
67106710
"contained move-only %0 '%1.%2'",
67116711
(DescriptiveDeclKind, StringRef, StringRef))
67126712
ERROR(moveonly_cannot_conform_to_protocol, none,
6713-
"Move only type %0 cannot conform yet to any protocols",
6714-
(DeclName))
6713+
"move-only %0 %1 cannot conform yet to any protocols",
6714+
(DescriptiveDeclKind, DeclName))
67156715
ERROR(moveonly_cannot_conform_to_protocol_with_name, none,
6716-
"Move only type %0 cannot conform to protocol %1. Move only types are "
6717-
"unable to conform to protocols yet",
6718-
(DeclName, DeclName))
6719-
6716+
"move-only %0 %1 cannot conform to protocol %2",
6717+
(DescriptiveDeclKind, DeclName, DeclName))
67206718
#define UNDEFINE_DIAGNOSTIC_MACROS
67216719
#include "DefineDiagnosticMacros.h"
67226720

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4470,6 +4470,13 @@ ProtocolConformance *GetImplicitSendableRequest::evaluate(
44704470
if (isa<ProtocolDecl>(nominal))
44714471
return nullptr;
44724472

4473+
// Move only nominal types are currently never sendable since we have not yet
4474+
// finished the generics model for them.
4475+
//
4476+
// TODO: Remove this once this is complete!
4477+
if (nominal->isMoveOnly())
4478+
return nullptr;
4479+
44734480
// Actor types are always Sendable; they don't get it via this path.
44744481
auto classDecl = dyn_cast<ClassDecl>(nominal);
44754482
if (classDecl && classDecl->isActor())

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2492,6 +2492,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
24922492
}
24932493

24942494
diagnoseCopyableTypeContainingMoveOnlyType(ED);
2495+
diagnoseMoveOnlyNominalDeclDoesntConformToProtocols(ED);
24952496

24962497
checkExplicitAvailability(ED);
24972498

@@ -2535,6 +2536,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
25352536
// If this struct is not move only, check that all vardecls of nominal type
25362537
// are not move only.
25372538
diagnoseCopyableTypeContainingMoveOnlyType(SD);
2539+
2540+
diagnoseMoveOnlyNominalDeclDoesntConformToProtocols(SD);
25382541
}
25392542

25402543
/// Check whether the given properties can be @NSManaged in this class.
@@ -2636,6 +2639,17 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
26362639
}
26372640
}
26382641

2642+
void diagnoseMoveOnlyNominalDeclDoesntConformToProtocols(
2643+
NominalTypeDecl *nomDecl) {
2644+
if (!nomDecl->isMoveOnly())
2645+
return;
2646+
2647+
for (auto *prot : nomDecl->getAllProtocols()) {
2648+
nomDecl->diagnose(diag::moveonly_cannot_conform_to_protocol_with_name,
2649+
nomDecl->getDescriptiveKind(),
2650+
nomDecl->getBaseName(), prot->getBaseName());
2651+
}
2652+
}
26392653

26402654
void visitClassDecl(ClassDecl *CD) {
26412655
checkUnsupportedNestedType(CD);
@@ -2799,6 +2813,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
27992813
TypeChecker::checkConformancesInContext(CD);
28002814

28012815
maybeDiagnoseClassWithoutInitializers(CD);
2816+
2817+
diagnoseMoveOnlyNominalDeclDoesntConformToProtocols(CD);
28022818
}
28032819

28042820
void visitProtocolDecl(ProtocolDecl *PD) {
@@ -3253,6 +3269,12 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
32533269

32543270
if (nominal->isDistributedActor())
32553271
TypeChecker::checkDistributedActor(SF, nominal);
3272+
3273+
// If we have a move only type and allow it to extend any protocol, error.
3274+
if (nominal->isMoveOnly() && ED->getInherited().size()) {
3275+
ED->diagnose(diag::moveonly_cannot_conform_to_protocol,
3276+
nominal->getDescriptiveKind(), nominal->getBaseName());
3277+
}
32563278
}
32573279

32583280
void visitTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {

test/Interpreter/moveonly_bufferview.swift

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,15 @@
1010
public struct BufferView<T> {
1111
var ptr: UnsafeBufferPointer<T>
1212

13-
deinit {}
14-
}
15-
16-
extension BufferView : Sequence {
17-
public typealias Iterator = UnsafeBufferPointer<T>.Iterator
18-
public typealias Element = UnsafeBufferPointer<T>.Element
13+
var count: Int {
14+
return ptr.count
15+
}
1916

20-
public func makeIterator() -> Self.Iterator {
21-
return ptr.makeIterator()
17+
subscript(_ x: Int) -> T {
18+
return ptr[x]
2219
}
20+
21+
deinit {}
2322
}
2423

2524
extension Array {
@@ -36,8 +35,8 @@ func testBufferView(_ x: __owned [Int]) {
3635
// CHECK: 2
3736
// CHECK: 3
3837
y.withBufferView {
39-
for x in $0 {
40-
print(x)
38+
for i in 0..<$0.count {
39+
print($0[i])
4140
}
4241
}
4342
}
@@ -52,8 +51,8 @@ func testConditionalBufferView(_ x: __owned [Int]) {
5251
// CHECK: 5
5352
// CHECK: 6
5453
if getBool() {
55-
for z in y {
56-
print(z)
54+
for i in 0..<y.count {
55+
print(y[i])
5756
}
5857
}
5958
}

test/Sema/moveonly_restrictions.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,30 @@ struct UnsafePointerWithOwner<T> {
132132
func doNothing() {}
133133
}
134134

135+
// Make sure we error whenever we attempt to conform a move only type to a
136+
// protocol.
137+
protocol P {}
138+
@_moveOnly class ProtocolCheckMoveOnlyKlass {} // expected-error {{move-only class 'ProtocolCheckMoveOnlyKlass' cannot conform to protocol 'P'}}
139+
@_moveOnly struct ProtocolCheckMoveOnlyStruct { // expected-error {{move-only struct 'ProtocolCheckMoveOnlyStruct' cannot conform to protocol 'P'}}
140+
var k: MoveOnlyKlass
141+
}
142+
@_moveOnly enum ProtocolCheckMoveOnlyEnum {} // expected-error {{move-only enum 'ProtocolCheckMoveOnlyEnum' cannot conform to protocol 'P'}}
143+
144+
extension ProtocolCheckMoveOnlyKlass : P {} // expected-error {{move-only class 'ProtocolCheckMoveOnlyKlass' cannot conform yet to any protocols}}
145+
extension ProtocolCheckMoveOnlyStruct : P {} // expected-error {{move-only struct 'ProtocolCheckMoveOnlyStruct' cannot conform yet to any protocols}}
146+
extension ProtocolCheckMoveOnlyEnum : P {} // expected-error {{move-only enum 'ProtocolCheckMoveOnlyEnum' cannot conform yet to any protocols}}
147+
148+
// But a normal extension is ok.
149+
extension ProtocolCheckMoveOnlyKlass {}
150+
extension ProtocolCheckMoveOnlyStruct {}
151+
extension ProtocolCheckMoveOnlyEnum {}
152+
153+
// Check if we define a move only type and make it conform on the base type
154+
@_moveOnly
155+
class MoveOnlyKlassP : P {} // expected-error {{move-only class 'MoveOnlyKlassP' cannot conform to protocol 'P'}}
156+
@_moveOnly
157+
struct MoveOnlyStructP : P { // expected-error {{move-only struct 'MoveOnlyStructP' cannot conform to protocol 'P'}}
158+
var mv: MoveOnlyKlass
159+
}
160+
@_moveOnly
161+
enum MoveOnlyEnumP : P {} // expected-error {{move-only enum 'MoveOnlyEnumP' cannot conform to protocol 'P'}}

0 commit comments

Comments
 (0)