[sema] Ban user created read/set accessor that produce noncopyable types.

The reason why we are doing this is that this combination of read/set forces the
compiler to emit a copy if we want to emit a modify operation.

The reason why we are forced to emit such a copy is that:

1. _read provides a guaranteed value in memory
2. performing a modify requires an owned value in memory.

This together implies that the only way we can do this is to copy from the _read
into temporary memory. But we have a noncopyable type so we can't do this.

rdar://112915525
This commit is contained in:
Michael Gottesman
2023-07-25 13:10:34 -07:00
parent 1f99204897
commit 2a1d9199a3
6 changed files with 108 additions and 682 deletions

View File

@@ -7365,6 +7365,9 @@ ERROR(noncopyable_types_cannot_be_resilient, none,
"non-@frozen public and @usableFromInline noncopyable types are not "
"supported",
(const ValueDecl *))
ERROR(noncopyable_cannot_have_read_set_accessor,none,
"noncopyable %select{variable|subscript}0 cannot provide a read and set accessor",
(unsigned))
//------------------------------------------------------------------------------
// MARK: Runtime discoverable attributes (@runtimeMetadata)

View File

@@ -2479,10 +2479,11 @@ public:
}
}
// If this is an init accessor property with a default initializer,
// make sure that it subsumes initializers of all of its "initializes"
// stored properties.
if (auto *var = PBD->getSingleVar()) {
// If this is an init accessor property with a default initializer,
// make sure that it subsumes initializers of all of its "initializes"
// stored properties.
auto *initAccessor = var->getAccessor(AccessorKind::Init);
if (initAccessor && PBD->isInitialized(0)) {
for (auto *property : initAccessor->getInitializedProperties()) {
@@ -2491,6 +2492,26 @@ public:
propertyBinding->setInitializerSubsumed(0);
}
}
// If we have a pure noncopyable type, we cannot have explicit read/set
// accessors since this means that we cannot call mutating methods without
// copying. We do not want to support types that one cannot define a
// modify operation via a get/set or a modify.
if (var->getInterfaceType()->isPureMoveOnly()) {
if (auto *read = var->getAccessor(AccessorKind::Read)) {
if (!read->isImplicit()) {
if (auto *set = var->getAccessor(AccessorKind::Set)) {
if (!set->isImplicit()) {
var->diagnose(diag::noncopyable_cannot_have_read_set_accessor,
0);
PBD->setInvalid();
var->setInvalid();
return;
}
}
}
}
}
}
}
@@ -2562,6 +2583,23 @@ public:
.fixItReplace(SD->getStaticLoc(), "static");
}
// Reject noncopyable typed subscripts with read/set accessors since we
// cannot define modify operations upon them without copying the read.
if (SD->getElementInterfaceType()->isPureMoveOnly()) {
if (auto *read = SD->getAccessor(AccessorKind::Read)) {
if (!read->isImplicit()) {
if (auto *set = SD->getAccessor(AccessorKind::Set)) {
if (!set->isImplicit()) {
SD->diagnose(diag::noncopyable_cannot_have_read_set_accessor,
1);
SD->setInvalid();
return;
}
}
}
}
}
// Now check all the accessors.
SD->visitEmittedAccessors([&](AccessorDecl *accessor) {
visit(accessor);

View File

@@ -1818,477 +1818,6 @@ public func testSubscriptGetSetThroughParentClass_BaseLoadable_ResultAddressOnly
m.computedTester2[0].mutatingFunc()
}
// MARK: read and setter
// This is different since adding a setter changes how we codegen.
public struct LoadableSubscriptReadSetTester : ~Copyable {
subscript(_ i: Int) -> AddressOnlyProtocol {
_read {
fatalError()
}
set {
fatalError()
}
}
}
// CHECK-LABEL: sil [ossa] @$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () {
// CHECK: [[BOX:%.*]] = alloc_box $
// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]]
// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]]
//
// The read call
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
// CHECK: [[LOAD:%.*]] = load_borrow [[MARK]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
// CHECK: apply {{%.*}}([[CORO_RESULT]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD]]
// CHECK: end_access [[ACCESS]]
//
// The assignment:
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}) : $@convention(method) (@thin AddressOnlyProtocol.Type) -> @out AddressOnlyProtocol
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[PROJECT]]
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[MARK]])
// CHECK: end_access [[ACCESS]]
//
// The mutating function call.
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[PROJECT]]
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: [[LOAD:%.*]] = load_borrow [[MARK]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD]]
// CHECK: apply {{%.*}}([[MARK_TEMP]])
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[MARK]])
// CHECK: end_access [[ACCESS]]
//
// CHECK: } // end sil function '$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_VaryyF'
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Var() {
var m = LoadableSubscriptReadSetTester()
m = LoadableSubscriptReadSetTester()
m[0].nonMutatingFunc()
m[0] = AddressOnlyProtocol()
m[0].mutatingFunc()
}
// CHECK-LABEL: sil [ossa] @$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () {
// CHECK: [[BOX:%.*]] = alloc_box $
// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]]
// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]]
//
// The get call
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]]
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[MARK]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[TEMP]]
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: apply {{%.*}}([[TEMP]])
// CHECK: destroy_addr [[TEMP]]
// CHECK: end_borrow [[LOAD_BORROW]]
// CHECK: } // end sil function '$s8moveonly55testSubscriptReadSet_BaseLoadable_ResultAddressOnly_LetyyF'
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Let() {
let m = LoadableSubscriptReadSetTester()
m[0].nonMutatingFunc()
}
// CHECK-LABEL: sil [ossa] @$s8moveonly57testSubscriptReadSet_BaseLoadable_ResultAddressOnly_InOut1myAA0gcdE6TesterVz_tF : $@convention(thin) (@inout LoadableSubscriptReadSetTester) -> () {
// CHECK: bb0([[ARG:%.*]] : $*
// CHECK: [[MARK:%.*]] = mark_must_check [consumable_and_assignable] [[ARG]]
//
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[MARK]]
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[ACCESS]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
// CHECK: apply {{%.*}}([[CORO_RESULT]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD_BORROW]]
// CHECK: end_access [[ACCESS]]
//
// The assignment:
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[MARK]]
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[ACCESS]])
// CHECK: end_access [[ACCESS]]
//
// The mutating function call.
// Getter
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[MARK]]
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: [[LOAD:%.*]] = load_borrow [[ACCESS]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
// CHECK: end_apply [[CORO_TOKEN]]
// Mutating Func
// CHECK: apply {{%.*}}([[MARK_TEMP]])
// Setter
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[ACCESS]])
// CHECK: end_access [[ACCESS]]
//
// CHECK: } // end sil function '$s8moveonly57testSubscriptReadSet_BaseLoadable_ResultAddressOnly_InOut1myAA0gcdE6TesterVz_tF
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_InOut(m: inout LoadableSubscriptReadSetTester) {
m[0].nonMutatingFunc()
m[0] = AddressOnlyProtocol()
m[0].mutatingFunc()
}
// CHECK-LABEL: sil [ossa] @$s8moveonly58testSubscriptReadSet_BaseLoadable_ResultAddressOnly_GlobalyyF : $@convention(thin) () -> () {
// CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s8moveonly36globalLoadableSubscriptReadSetTesterAA0cdefG0Vvp
//
// The get call
// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[GLOBAL_ADDR]]
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[MARK]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
// CHECK: apply {{%.*}}([[CORO_RESULT]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD_BORROW]]
// CHECK: end_access [[ACCESS]]
//
// The assignment:
// CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s8moveonly36globalLoadableSubscriptReadSetTesterAA0cdefG0Vvp
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}) : $@convention(method) (@thin AddressOnlyProtocol.Type) -> @out AddressOnlyProtocol
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL_ADDR]]
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[MARK]])
// CHECK: end_access [[ACCESS]]
//
// The mutating function call.
// CHECK: [[GLOBAL_ADDR:%.*]] = global_addr @$s8moveonly36globalLoadableSubscriptReadSetTesterAA0cdefG0Vvp
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL_ADDR]]
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[MARK]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD_BORROW]]
// CHECK: apply {{%.*}}([[MARK_TEMP]])
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[MARK]])
// CHECK: end_access [[ACCESS]]
//
// CHECK: } // end sil function '$s8moveonly58testSubscriptReadSet_BaseLoadable_ResultAddressOnly_GlobalyyF'
var globalLoadableSubscriptReadSetTester = LoadableSubscriptReadSetTester()
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Global() {
globalLoadableSubscriptReadSetTester[0].nonMutatingFunc()
globalLoadableSubscriptReadSetTester[0] = AddressOnlyProtocol()
globalLoadableSubscriptReadSetTester[0].mutatingFunc()
}
// Make sure that we get the same behavior when we access through another noncopyable struct.
public struct LoadableSubscriptReadSetTesterNonCopyableStructParent : ~Copyable {
var tester = LoadableSubscriptReadSetTester()
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
}
// CHECK-LABEL: sil [ossa] @$s8moveonly85testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () {
// CHECK: [[BOX:%.*]] = alloc_box $
// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]]
// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]]
//
// The first get call
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
// CHECK: [[GEP:%.*]] = struct_element_addr [[MARK]]
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[GEP]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
// CHECK: apply {{%.*}}([[CORO_RESULT]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD_BORROW]]
// CHECK: end_access [[ACCESS]]
//
// The mutating call.
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[PROJECT]]
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
// CHECK: [[GEP:%.*]] = struct_element_addr [[MARK]]
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: [[LOAD:%.*]] = load_borrow [[GEP]]
// TODO: Another case where we need to expand coroutines
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD]]
// CHECK: apply {{%.*}}([[MARK_TEMP]])
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[GEP]])
// CHECK: end_access [[ACCESS]]
//
// The second get call.
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[MARK]]
// CHECK: [[TESTER:%.*]] = apply {{%.*}}([[LOAD_BORROW]])
// CHECK: end_borrow [[LOAD_BORROW]]
// CHECK: end_access [[ACCESS]]
// CHECK: [[BORROWED_TESTER:%.*]] = begin_borrow [[TESTER]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[BORROWED_TESTER]])
// CHECK: apply {{%.*}}([[CORO_RESULT]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[BORROWED_TESTER]]
// } // end sil function '$s8moveonly077testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressE4_VaryyF'
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Var() {
var m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
m.tester[0].nonMutatingFunc()
m.tester[0].mutatingFunc()
m.computedTester[0].nonMutatingFunc()
}
// CHECK-LABEL: sil [ossa] @$s8moveonly85testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF : $@convention(thin) () -> () {
// CHECK: [[BOX:%.*]] = alloc_box ${ let L
// CHECK: [[BOX_LIFETIME:%.*]] = begin_borrow [lexical] [[BOX]]
// CHECK: [[PROJECT:%.*]] = project_box [[BOX_LIFETIME]]
//
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[PROJECT]]
// CHECK: [[LOAD:%.*]] = load_borrow [[MARK]]
// CHECK: [[EXT:%.*]] = struct_extract [[LOAD]]
// CHECK: [[COPY:%.*]] = copy_value [[EXT]]
// CHECK: [[BORROW:%.*]] = begin_borrow [[COPY]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[BORROW]])
// CHECK: apply {{%.*}}([[CORO_RESULT]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: } // end sil function '$s8moveonly85testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_LetyyF'
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Let() {
let m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
m.tester[0].nonMutatingFunc()
}
// CHECK-LABEL: sil [ossa] @$s8moveonly87testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_InOut1myAA0lcde6TesterghjI0Vz_tF : $@convention(thin) (@inout LoadableSubscriptReadSetTesterNonCopyableStructParent) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK: [[MARK:%.*]] = mark_must_check [consumable_and_assignable] [[ARG]]
//
// Call to non_mutating
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[MARK]]
// CHECK: [[GEP:%.*]] = struct_element_addr [[ACCESS]]
// CHECK: [[LOAD_BORROW:%.*]] = load_borrow [[GEP]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD_BORROW]])
// CHECK: apply {{%.*}}([[CORO_RESULT]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD_BORROW]]
// CHECK: end_access [[ACCESS]]
//
// Modify
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[MARK]]
// CHECK: [[GEP:%.*]] = struct_element_addr [[ACCESS]]
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: [[LOAD:%.*]] = load_borrow [[GEP]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD]]
// CHECK: apply {{%.*}}([[MARK_TEMP]])
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[GEP]])
// CHECK: end_access [[ACCESS]]
// CHECK: } // end sil function '$s8moveonly87testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_InOut1myAA0lcde6TesterghjI0Vz_tF'
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_InOut(m: inout LoadableSubscriptReadSetTesterNonCopyableStructParent) {
m.tester[0].nonMutatingFunc()
m.tester[0].mutatingFunc()
}
// CHECK-LABEL: sil [ossa] @$s8moveonly88testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_GlobalyyF : $@convention(thin) () -> () {
// CHECK: [[GLOBAL:%.*]] = global_addr @$s8moveonly59globalLoadableSubscriptReadSetTesterNonCopyableStructParentAA0cdefghijK0Vvp :
// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[GLOBAL]]
// CHECK: [[MARK:%.*]] = mark_must_check [no_consume_or_assign] [[ACCESS]]
// CHECK: [[GEP:%.*]] = struct_element_addr [[MARK]]
// CHECK: [[LOAD:%.*]] = load_borrow [[GEP]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
// CHECK: apply {{%.*}}([[CORO_RESULT]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD]]
// CHECK: end_access [[ACCESS]]
//
// CHECK: [[GLOBAL:%.*]] = global_addr @$s8moveonly59globalLoadableSubscriptReadSetTesterNonCopyableStructParentAA0cdefghijK0Vvp :
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]]
// CHECK: [[MARK:%.*]] = mark_must_check [assignable_but_not_consumable] [[ACCESS]]
// CHECK: [[GEP:%.*]] = struct_element_addr [[MARK]]
// CHECK: [[TEMP:%.*]] = alloc_stack $AddressOnlyProtocol
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: [[LOAD:%.*]] = load_borrow [[GEP]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
// CHECK: copy_addr [[CORO_RESULT]] to [init] [[MARK_TEMP]]
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[LOAD]]
// CHECK: apply {{%.*}}([[MARK_TEMP]])
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[GEP]])
// CHECK: end_access [[ACCESS]]
// CHECK: } // end sil function '$s8moveonly88testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_GlobalyyF'
var globalLoadableSubscriptReadSetTesterNonCopyableStructParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Global() {
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].nonMutatingFunc()
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].mutatingFunc()
}
public class LoadableSubscriptReadSetTesterClassParent {
var tester = LoadableSubscriptReadSetTester()
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
var computedTester2: LoadableSubscriptReadSetTester {
get { fatalError() }
set { fatalError() }
}
var testerParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
}
// CHECK-LABEL: sil [ossa] @$s8moveonly73testSubscriptReadSetThroughParentClass_BaseLoadable_ResultAddressOnly_VaryyF : $@convention(thin) () -> () {
// CHECK: [[BOX:%.*]] = alloc_box $
// CHECK: [[BORROW:%.*]] = begin_borrow [lexical] [[BOX]]
// CHECK: [[PROJECT:%.*]] = project_box [[BORROW]]
//
// First read.
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
// CHECK: end_access [[ACCESS]]
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[CORO_RESULT]])
// CHECK: apply {{%.*}}([[CORO_RESULT_2]])
// CHECK: end_apply [[CORO_TOKEN_2]]
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[BORROW_COPYABLE_CLASS]]
// CHECK: destroy_value [[COPYABLE_CLASS]]
//
// First mutation.
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
// CHECK: end_access [[ACCESS]]
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
// CHECK: [[TEMP:%.*]] = alloc_stack $
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: [[LOAD:%.*]] = load_borrow [[CORO_RESULT]]
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
// CHECK: copy_addr [[CORO_RESULT_2]] to [init] [[MARK_TEMP]]
// CHECK: end_apply [[CORO_TOKEN_2]]
// Mutating Func
// CHECK: apply {{%.*}}([[MARK_TEMP]])
// Setter
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[CORO_RESULT]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[BORROW_COPYABLE_CLASS]]
// CHECK: destroy_value [[COPYABLE_CLASS]]
//
// Second read.
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
// CHECK: end_access [[ACCESS]]
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
// CHECK: [[EXT:%.*]] = struct_extract [[CORO_RESULT]]
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[EXT]])
// CHECK: apply {{%.*}}([[CORO_RESULT_2]])
// CHECK: end_apply [[CORO_TOKEN_2]]
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[BORROW_COPYABLE_CLASS]]
// CHECK: destroy_value [[COPYABLE_CLASS]]
//
// Second mutate
//
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
// CHECK: end_access [[ACCESS]]
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
// CHECK: [[GEP:%.*]] = struct_element_addr [[CORO_RESULT]]
// CHECK: [[TEMP:%.*]] = alloc_stack $
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: [[LOAD:%.*]] = load_borrow [[GEP]]
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
// CHECK: copy_addr [[CORO_RESULT_2]] to [init] [[MARK_TEMP]]
// CHECK: end_apply [[CORO_TOKEN_2]]
// Mutating Func
// CHECK: apply {{%.*}}([[MARK_TEMP]])
// Setter
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[GEP]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[BORROW_COPYABLE_CLASS]]
// CHECK: destroy_value [[COPYABLE_CLASS]]
//
// Third read. This is a case that we can't handle today due to the way the AST
// looks:
//
// (subscript_expr type='AddressOnlyProtocol'
// (member_ref_expr type='LoadableSubscriptReadSetTester'
// (load_expr implicit type='LoadableSubscriptReadSetTesterClassParent'
// (declref_expr type='@lvalue LoadableSubscriptReadSetTesterClassParent'
// (argument_list
// (argument
// (integer_literal_expr type='Int'
//
// due to the load_expr in the subscript base, SILGen emits a base rvalue for
// the load_expr and copies it, ending the coroutine. What we need is the
// ability to have an lvalue pseudo-component that treats the declref_expr (and
// any member_ref_expr) as a base and allows for a load_expr to be followed by N
// member_ref_expr.
//
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
// CHECK: end_access [[ACCESS]]
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
// CHECK: [[CORO_RESULT_COPY:%.*]] = copy_value [[CORO_RESULT]]
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: [[BORROW:%.*]] = begin_borrow [[CORO_RESULT_COPY]]
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[BORROW]])
// CHECK: apply {{%.*}}([[CORO_RESULT_2]])
// CHECK: end_apply [[CORO_TOKEN_2]]
//
// Fourth read
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
// CHECK: end_access [[ACCESS]]
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[CORO_RESULT]])
// CHECK: apply {{%.*}}([[CORO_RESULT_2]])
// CHECK: end_apply [[CORO_TOKEN_2]]
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: end_borrow [[BORROW_COPYABLE_CLASS]]
// CHECK: destroy_value [[COPYABLE_CLASS]]
//
// Fourth Mutation
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]]
// CHECK: [[COPYABLE_CLASS:%.*]] = load [copy] [[ACCESS]]
// CHECK: end_access [[ACCESS]]
// CHECK: [[BORROW_COPYABLE_CLASS:%.*]] = begin_borrow [[COPYABLE_CLASS]]
// CHECK: ([[CORO_RESULT:%.*]], [[CORO_TOKEN:%.*]]) = begin_apply {{%.*}}([[BORROW_COPYABLE_CLASS]])
// CHECK: [[TEMP:%.*]] = alloc_stack $
// CHECK: [[MARK_TEMP:%.*]] = mark_must_check [consumable_and_assignable] [[TEMP]]
// CHECK: [[LOAD:%.*]] = load_borrow [[CORO_RESULT]]
// CHECK: ([[CORO_RESULT_2:%.*]], [[CORO_TOKEN_2:%.*]]) = begin_apply {{%.*}}({{%.*}}, [[LOAD]])
// CHECK: copy_addr [[CORO_RESULT_2]] to [init] [[MARK_TEMP]]
// CHECK: end_apply [[CORO_TOKEN_2]]
// CHECK: end_borrow [[LOAD]]
// Mutating Func
// CHECK: apply {{%.*}}([[MARK_TEMP]])
// Setter
// CHECK: apply {{%.*}}([[MARK_TEMP]], {{%.*}}, [[CORO_RESULT]])
// CHECK: end_apply [[CORO_TOKEN]]
// CHECK: } // end sil function '$s8moveonly73testSubscriptReadSetThroughParentClass_BaseLoadable_ResultAddressOnly_VaryyF'
public func testSubscriptReadSetThroughParentClass_BaseLoadable_ResultAddressOnly_Var() {
var m = LoadableSubscriptReadSetTesterClassParent()
m = LoadableSubscriptReadSetTesterClassParent()
m.tester[0].nonMutatingFunc()
m.tester[0].mutatingFunc()
m.testerParent.tester[0].nonMutatingFunc()
m.testerParent.tester[0].mutatingFunc()
m.computedTester[0].nonMutatingFunc()
m.computedTester2[0].nonMutatingFunc()
m.computedTester2[0].mutatingFunc()
}
// MARK: _read and _modify
public struct LoadableSubscriptReadModifyTester : ~Copyable {

View File

@@ -183,110 +183,6 @@ public func testSubscriptGetSetThroughParentClass_BaseLoadable_ResultAddressOnly
m.computedTester2[0].mutatingFunc()
}
// MARK: read and setter
// This is different since adding a setter changes how we codegen.
public struct LoadableSubscriptReadSetTester : ~Copyable {
subscript(_ i: Int) -> AddressOnlyMoveOnlyContainingProtocol {
_read {
fatalError()
}
set {
fatalError()
}
}
}
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Var() {
var m = LoadableSubscriptReadSetTester()
m = LoadableSubscriptReadSetTester()
m[0].nonMutatingFunc()
m[0] = AddressOnlyMoveOnlyContainingProtocol()
m[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Let() {
let m = LoadableSubscriptReadSetTester()
m[0].nonMutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_InOut(m: inout LoadableSubscriptReadSetTester) {
m[0].nonMutatingFunc()
m[0] = AddressOnlyMoveOnlyContainingProtocol()
m[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
var globalLoadableSubscriptReadSetTester = LoadableSubscriptReadSetTester()
public func testSubscriptReadSet_BaseLoadable_ResultAddressOnly_Global() {
globalLoadableSubscriptReadSetTester[0].nonMutatingFunc()
globalLoadableSubscriptReadSetTester[0] = AddressOnlyMoveOnlyContainingProtocol()
globalLoadableSubscriptReadSetTester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
// Make sure that we get the same behavior when we access through another noncopyable struct.
public struct LoadableSubscriptReadSetTesterNonCopyableStructParent : ~Copyable {
var tester = LoadableSubscriptReadSetTester()
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
}
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Var() {
var m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
m.tester[0].nonMutatingFunc()
m.tester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
m.computedTester[0].nonMutatingFunc()
}
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Let() {
let m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
m.tester[0].nonMutatingFunc()
}
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_InOut(m: inout LoadableSubscriptReadSetTesterNonCopyableStructParent) {
m.tester[0].nonMutatingFunc()
m.tester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
var globalLoadableSubscriptReadSetTesterNonCopyableStructParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultAddressOnly_Global() {
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].nonMutatingFunc()
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
public class LoadableSubscriptReadSetTesterClassParent {
var tester = LoadableSubscriptReadSetTester()
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
var computedTester2: LoadableSubscriptReadSetTester {
get { fatalError() }
set { fatalError() }
}
var testerParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
}
public func testSubscriptReadSetThroughParentClass_BaseLoadable_ResultAddressOnly_Var() {
var m = LoadableSubscriptReadSetTesterClassParent()
m = LoadableSubscriptReadSetTesterClassParent()
m.tester[0].nonMutatingFunc()
m.tester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
m.testerParent.tester[0].nonMutatingFunc()
m.testerParent.tester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
m.computedTester[0].nonMutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
m.computedTester2[0].nonMutatingFunc()
m.computedTester2[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
// MARK: _read and _modify
public struct LoadableSubscriptReadModifyTester : ~Copyable {

View File

@@ -180,110 +180,6 @@ public func testSubscriptGetSetThroughParentClass_BaseLoadable_ResultLoadable_Va
m.computedTester2[0].mutatingFunc()
}
// MARK: read and setter
// This is different since adding a setter changes how we codegen.
public struct LoadableSubscriptReadSetTester : ~Copyable {
subscript(_ i: Int) -> LoadableMoveOnlyContainingProtocol {
_read {
fatalError()
}
set {
fatalError()
}
}
}
public func testSubscriptReadSet_BaseLoadable_ResultLoadable_Var() {
var m = LoadableSubscriptReadSetTester()
m = LoadableSubscriptReadSetTester()
m[0].nonMutatingFunc()
m[0] = LoadableMoveOnlyContainingProtocol()
m[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
public func testSubscriptReadSet_BaseLoadable_ResultLoadable_Let() {
let m = LoadableSubscriptReadSetTester()
m[0].nonMutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
public func testSubscriptReadSet_BaseLoadable_ResultLoadable_InOut(m: inout LoadableSubscriptReadSetTester) {
m[0].nonMutatingFunc()
m[0] = LoadableMoveOnlyContainingProtocol()
m[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
var globalLoadableSubscriptReadSetTester = LoadableSubscriptReadSetTester()
public func testSubscriptReadSet_BaseLoadable_ResultLoadable_Global() {
globalLoadableSubscriptReadSetTester[0].nonMutatingFunc()
globalLoadableSubscriptReadSetTester[0] = LoadableMoveOnlyContainingProtocol()
globalLoadableSubscriptReadSetTester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
// Make sure that we get the same behavior when we access through another noncopyable struct.
public struct LoadableSubscriptReadSetTesterNonCopyableStructParent : ~Copyable {
var tester = LoadableSubscriptReadSetTester()
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
}
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultLoadable_Var() {
var m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
m.tester[0].nonMutatingFunc()
m.tester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
m.computedTester[0].nonMutatingFunc()
}
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultLoadable_Let() {
let m = LoadableSubscriptReadSetTesterNonCopyableStructParent()
m.tester[0].nonMutatingFunc()
}
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultLoadable_InOut(m: inout LoadableSubscriptReadSetTesterNonCopyableStructParent) {
m.tester[0].nonMutatingFunc()
m.tester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
var globalLoadableSubscriptReadSetTesterNonCopyableStructParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
public func testSubscriptReadSetThroughNonCopyableParentStruct_BaseLoadable_ResultLoadable_Global() {
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].nonMutatingFunc()
globalLoadableSubscriptReadSetTesterNonCopyableStructParent.tester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
public class LoadableSubscriptReadSetTesterClassParent {
var tester = LoadableSubscriptReadSetTester()
var computedTester: LoadableSubscriptReadSetTester { fatalError() }
var computedTester2: LoadableSubscriptReadSetTester {
get { fatalError() }
set { fatalError() }
}
var testerParent = LoadableSubscriptReadSetTesterNonCopyableStructParent()
}
public func testSubscriptReadSetThroughParentClass_BaseLoadable_ResultLoadable_Var() {
var m = LoadableSubscriptReadSetTesterClassParent()
m = LoadableSubscriptReadSetTesterClassParent()
m.tester[0].nonMutatingFunc()
m.tester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
m.testerParent.tester[0].nonMutatingFunc()
m.testerParent.tester[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
m.computedTester[0].nonMutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
m.computedTester2[0].nonMutatingFunc()
m.computedTester2[0].mutatingFunc()
// expected-error @-1 {{copy of noncopyable typed value}}
}
// MARK: _read and _modify
public struct LoadableSubscriptReadModifyTester : ~Copyable {

View File

@@ -0,0 +1,64 @@
// RUN: %target-typecheck-verify-swift
// RUN: %target-typecheck-verify-swift -enable-library-evolution
@frozen
public struct NonCopyableS : ~Copyable {}
@frozen
public enum NonCopyableE : ~Copyable {}
public struct S {
public var x: NonCopyableS { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
public var x2: NonCopyableE { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
public subscript(x x: Int) -> NonCopyableS { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
public subscript(y y: Int) -> NonCopyableE { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
}
public class C {
public var x: NonCopyableS { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
public var x2: NonCopyableE { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
public subscript(x x: Int) -> NonCopyableS { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
public subscript(y y: Int) -> NonCopyableE { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
}
public enum E {
public var x: NonCopyableS { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
public var x2: NonCopyableE { // expected-error {{noncopyable variable cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
public subscript(x x: Int) -> NonCopyableS { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
public subscript(y y: Int) -> NonCopyableE { // expected-error {{noncopyable subscript cannot provide a read and set accessor}}
_read { fatalError() }
set { fatalError() }
}
}