1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
// RUN: %target-swift-emit-sil -sil-verify-all -verify -enable-experimental-feature MoveOnlyClasses -enable-experimental-feature MoveOnlyTuples %s
// This test validates that we properly emit errors if we partially invalidate
// through a type with a deinit.
//////////////////
// Declarations //
//////////////////
class Klass {}
@_moveOnly
class MoveOnlyKlass {
var value: Int = 0
}
struct KlassPair : ~Copyable {
var lhs: Klass
var rhs: MoveOnlyKlass
}
struct AggStruct : ~Copyable {
var pair: KlassPair
}
struct KlassPair2 : ~Copyable {
var lhs: MoveOnlyKlass
var rhs: MoveOnlyKlass
}
struct AggStruct2 : ~Copyable {
var lhs: MoveOnlyKlass
var pair: KlassPair2
var rhs: MoveOnlyKlass
}
struct SingleIntContainingStruct : ~Copyable {
var value: Int = 0
}
struct MoveOnlyPair : ~Copyable {
var first = SingleIntContainingStruct()
var second = SingleIntContainingStruct()
}
protocol P {
static var value: Self { get }
}
func consume<T : P>(_ x: consuming T) {}
func consume(_ x: consuming SingleIntContainingStruct) {}
func consume(_ x: consuming MoveOnlyKlass) {}
func consume(_ x: consuming MoveOnlyPair) {}
func consume(_ x: consuming Klass) {}
////////////////////
// MARK: Loadable //
////////////////////
struct DeinitStruct : ~Copyable {
var first: Klass
var second: (Klass, Klass)
var third: KlassPair
var fourth: (MoveOnlyKlass, MoveOnlyKlass)
var fifth: MoveOnlyKlass
deinit {} // expected-note 10{{deinitializer declared here}}
}
func testConsumeCopyable(_ x: consuming DeinitStruct) {
consume(x.first)
consume(x.second.0)
consume(x.third.lhs)
}
func testConsumeNonCopyable1(_ x: consuming DeinitStruct) {
// expected-error @+1 {{cannot partially consume 'x' when it has a deinitializer}}
consume(x.third.rhs)
}
func testConsumeNonCopyable2(_ x: consuming DeinitStruct) {
// expected-error @+1 {{cannot partially consume 'x' when it has a deinitializer}}
consume(x.fourth.0)
}
func testConsumeNonCopyable3(_ x: consuming DeinitStruct) {
// expected-error @+1 {{cannot partially consume 'x' when it has a deinitializer}}
consume(x.fourth.1)
}
func testConsumeNonCopyable4(_ x: consuming DeinitStruct) {
// expected-error @+1 {{cannot partially consume 'x' when it has a deinitializer}}
consume(x.fifth)
}
///////////////////////////
// MARK: Loadable Fields //
///////////////////////////
struct StructContainDeinitStruct : ~Copyable {
var first: DeinitStruct
var second: (DeinitStruct, DeinitStruct)
var third: Klass
var fourth: (Klass, Klass)
var fifth: MoveOnlyKlass
var sixth: (MoveOnlyKlass, MoveOnlyKlass)
}
func testStructContainDeinitStructConsumeCopyable1(_ x: consuming StructContainDeinitStruct) {
consume(x.first.first)
consume(x.first.second.0)
consume(x.first.third.lhs)
consume(x.second.0.first)
consume(x.second.1.second.0)
consume(x.second.0.third.lhs)
consume(x.sixth.0)
}
func testStructContainStructContainDeinitStructConsumeNonCopyable1(_ xyz: consuming StructContainDeinitStruct) {
// expected-error @+1 {{cannot partially consume 'xyz.first' when it has a deinitializer}}
consume(xyz.first.third.rhs)
}
func testStructContainStructContainDeinitStructConsumeNonCopyable1a(_ x: consuming StructContainDeinitStruct) {
// expected-error @+1 {{cannot partially consume 'x.second.0' when it has a deinitializer}}
consume(x.second.0.third.rhs)
}
func testStructContainStructContainDeinitStructConsumeNonCopyable2(_ x: consuming StructContainDeinitStruct) {
// expected-error @+1 {{cannot partially consume 'x.first' when it has a deinitializer}}
consume(x.first.fourth.0)
}
func testStructContainStructContainDeinitStructConsumeNonCopyable2a(_ x: consuming StructContainDeinitStruct) {
// expected-error @+1 {{cannot partially consume 'x.second.1' when it has a deinitializer}}
consume(x.second.1.fourth.0)
}
func testStructContainStructContainDeinitStructConsumeNonCopyable3(_ x: consuming StructContainDeinitStruct) {
// expected-error @+1 {{cannot partially consume 'x.first' when it has a deinitializer}}
consume(x.first.fourth.1)
}
func testStructContainStructContainDeinitStructConsumeNonCopyable4(_ x: consuming StructContainDeinitStruct) {
// expected-error @+1 {{cannot partially consume 'x.first' when it has a deinitializer}}
consume(x.first.fifth)
}
////////////////////////
// MARK: Address Only //
////////////////////////
struct AddressOnlyDeinitStruct<T : P> : ~Copyable {
var copyable: T = T.value
var moveOnly = SingleIntContainingStruct()
var moveOnlyPair = MoveOnlyPair()
deinit {} // expected-note 5{{deinitializer declared here}}
}
func consume<T : P>(_ x: consuming AddressOnlyDeinitStruct<T>) {}
func testAddressOnlyCanConsumeEntireType<T : P>(_ x: consuming AddressOnlyDeinitStruct<T>) {
// This is ok since we are consuming a copyable value.
consume(x.copyable)
// This is ok since we are consuming the entire value.
consume(x)
}
func testAddressOnlyCannotPartialConsume<T : P>(_ x: consuming AddressOnlyDeinitStruct<T>) {
consume(x.moveOnly) // expected-error {{cannot partially consume 'x' when it has a deinitializer}}
consume(x.moveOnlyPair.first) // expected-error {{cannot partially consume 'x' when it has a deinitializer}}
consume(x.copyable)
}
struct AddressOnlyContainingDeinitStruct<T : P> : ~Copyable {
var a = AddressOnlyDeinitStruct<T>()
}
func testAddressOnlyCannotPartialConsumeEvenIfSingleElt<T : P>(_ x: consuming AddressOnlyContainingDeinitStruct<T>) {
// We do not error here since we can partially consume x, but not x.a
consume(x.a)
consume(x.a.moveOnlyPair) // expected-error {{cannot partially consume 'x.a' when it has a deinitializer}}
}
struct AddressOnlyContainingDeinitSingleField<T : P> : ~Copyable {
var moveOnly = SingleIntContainingStruct()
deinit {} // expected-note {{deinitializer declared here}}
}
struct AddressOnlyContainingDeinitStruct3<T : P> : ~Copyable {
var a = AddressOnlyContainingDeinitSingleField<T>()
}
func consume<T : P>(_ x: consuming AddressOnlyContainingDeinitSingleField<T>) {}
func testAddressOnlyCannotPartialConsumeEvenIfSingleElt<T : P>(_ x: consuming AddressOnlyContainingDeinitStruct3<T>) {
// We do not error here since we can partially consume x, but not x.a
consume(x.a)
consume(x.a.moveOnly) // expected-error {{cannot partially consume 'x.a' when it has a deinitializer}}
}
struct AddressOnlyContainingDeinitStructPair<T : P> : ~Copyable {
var first = AddressOnlyDeinitStruct<T>()
var second = AddressOnlyDeinitStruct<T>()
}
// Make sure that if the deinit is in an intermediate element of the path that
// we still handle it appropriately.
func testAddressOnlyDeinitInMiddlePath<T : P>(_ x: consuming AddressOnlyContainingDeinitStructPair<T>) {
consume(x.first.moveOnly) // expected-error {{cannot partially consume 'x.first' when it has a deinitializer}}
consume(x.first.moveOnlyPair.first) // expected-error {{cannot partially consume 'x.first' when it has a deinitializer}}
consume(x.first.copyable)
}
|