-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathimplicit_lifetime_dependence.swift
250 lines (225 loc) · 9.05 KB
/
implicit_lifetime_dependence.swift
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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
// RUN: %target-swift-frontend %s \
// RUN: -emit-sil -target %target-swift-5.1-abi-triple \
// RUN: -enable-experimental-feature LifetimeDependence \
// RUN: | %FileCheck %s
// REQUIRES: swift_feature_LifetimeDependence
@_unsafeNonescapableResult
@lifetime(borrow source)
internal func _overrideLifetime<
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
>(
_ dependent: consuming T, borrowing source: borrowing U
) -> T {
// TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence
// should be expressed by a builtin that is hidden within the function body.
dependent
}
@_unsafeNonescapableResult
@lifetime(copy source)
internal func _overrideLifetime<
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
>(
_ dependent: consuming T, copying source: borrowing U
) -> T {
// TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence
// should be expressed by a builtin that is hidden within the function body.
dependent
}
struct BufferView : ~Escapable {
let ptr: UnsafeRawBufferPointer
let c: Int
@lifetime(borrow ptr)
init(_ ptr: UnsafeRawBufferPointer, _ c: Int) {
self.ptr = ptr
self.c = c
}
@lifetime(borrow ptr)
init(independent ptr: UnsafeRawBufferPointer, _ c: Int) {
self.ptr = ptr
self.c = c
}
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyA2ChcfC : $@convention(method) (@guaranteed BufferView, @thin BufferView.Type) -> @lifetime(copy 0) @owned BufferView {
@lifetime(copy otherBV)
init(_ otherBV: borrowing BufferView) {
self.ptr = otherBV.ptr
self.c = otherBV.c
}
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyA2CcfC : $@convention(method) (@owned BufferView, @thin BufferView.Type) -> @lifetime(copy 0) @owned BufferView {
@lifetime(copy otherBV)
init(_ otherBV: consuming BufferView) {
self.ptr = otherBV.ptr
self.c = otherBV.c
}
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyACSW_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array<Int>, @thin BufferView.Type) -> @lifetime(borrow 0) @owned BufferView {
@lifetime(borrow ptr)
init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array<Int>) {
self.ptr = ptr
self.c = a.count
}
}
struct MutableBufferView : ~Escapable, ~Copyable {
let ptr: UnsafeMutableRawBufferPointer
let c: Int
@lifetime(borrow ptr)
init(_ ptr: UnsafeMutableRawBufferPointer, _ c: Int) {
self.ptr = ptr
self.c = c
}
}
func testBasic() {
let a = [Int](repeating: 0, count: 4)
a.withUnsafeBytes {
let view = BufferView($0, a.count)
let derivedView = derive(view)
let newView = consumeAndCreate(derivedView)
use(newView)
}
}
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(copy 0) @owned BufferView {
@lifetime(copy x)
func derive(_ x: borrowing BufferView) -> BufferView {
return BufferView(x.ptr, x.c)
}
@lifetime(copy x)
func derive(_ unused: Int, _ x: borrowing BufferView) -> BufferView {
return BufferView(independent: x.ptr, x.c)
}
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> @lifetime(copy 0) @owned BufferView {
@lifetime(copy x)
func consumeAndCreate(_ x: consuming BufferView) -> BufferView {
let bv = BufferView(independent: x.ptr, x.c)
return _overrideLifetime(bv, copying: x)
}
func use(_ x: borrowing BufferView) {}
struct Wrapper : ~Escapable {
var _view: BufferView
var view: BufferView {
// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvr : $@yield_once @convention(method) (@guaranteed Wrapper) -> @lifetime(copy 0) @yields @guaranteed BufferView {
@lifetime(copy self)
_read {
yield _view
}
// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvM : $@yield_once @convention(method) (@inout Wrapper) -> @lifetime(borrow 0) @yields @inout BufferView {
@lifetime(borrow self)
_modify {
yield &_view
}
}
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperVyAcA10BufferViewVcfC : $@convention(method) (@owned BufferView, @thin Wrapper.Type) -> @lifetime(copy 0) @owned Wrapper {
@lifetime(copy view)
init(_ view: consuming BufferView) {
self._view = view
}
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView1AA10BufferViewVyKF : $@convention(method) (@guaranteed Wrapper) -> @lifetime(copy 0) (@owned BufferView, @error any Error) {
@lifetime(copy self)
borrowing func getView1() throws -> BufferView {
return _view
}
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView2AA10BufferViewVyYaKF : $@convention(method) @async (@owned Wrapper) -> @lifetime(copy 0) (@owned BufferView, @error any Error) {
@lifetime(copy self)
consuming func getView2() async throws -> BufferView {
return _view
}
}
struct Container1 : ~Copyable {
let ptr: UnsafeRawBufferPointer
let c: Int
// CHECK: sil hidden @$s28implicit_lifetime_dependence10Container1V4viewAA10BufferViewVvg : $@convention(method) (@guaranteed Container1) -> @lifetime(borrow 0) @owned BufferView {
var view: BufferView {
get {
return BufferView(ptr, c)
}
}
}
struct Container2 : ~Copyable {
let ptr: UnsafeMutableRawBufferPointer
let c: Int
// CHECK: sil hidden @$s28implicit_lifetime_dependence10Container2V11mutableViewAA013MutableBufferF0Vvr : $@yield_once @convention(method) (@guaranteed Container2) -> @lifetime(borrow 0) @yields @guaranteed MutableBufferView {
var mutableView: MutableBufferView {
_read {
yield MutableBufferView(ptr, c)
}
}
}
struct FakeRange<Bound> {
public let lowerBound: Bound
public let upperBound: Bound
}
struct GenericBufferView<Element> : ~Escapable {
typealias Index = Int
typealias Pointer = UnsafeRawPointer
let baseAddress: Pointer
let count: Int
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence17GenericBufferViewV11baseAddress5countACyxGSV_SitcfC : $@convention(method) <Element> (UnsafeRawPointer, Int, @thin GenericBufferView<Element>.Type) -> @lifetime(borrow 0) @owned GenericBufferView<Element> {
@lifetime(borrow baseAddress)
init<Storage>(baseAddress: Pointer,
count: Int,
dependsOn: borrowing Storage) {
self = GenericBufferView<Element>(baseAddress: baseAddress,
count: count)
}
// unsafe private API
@lifetime(borrow baseAddress)
init(baseAddress: Pointer, count: Int) {
precondition(count >= 0, "Count must not be negative")
self.baseAddress = baseAddress
self.count = count
}
subscript(position: Pointer) -> Element {
get {
if _isPOD(Element.self) {
return position.loadUnaligned(as: Element.self)
}
else {
return position.load(as: Element.self)
}
}
}
// CHECK: sil hidden @$s28implicit_lifetime_dependence17GenericBufferViewVyACyxGAA9FakeRangeVySVGcig : $@convention(method) <Element> (FakeRange<UnsafeRawPointer>, @guaranteed GenericBufferView<Element>) -> @lifetime(copy 1) @owned GenericBufferView<Element> {
subscript(bounds: FakeRange<Pointer>) -> Self {
@lifetime(copy self)
get {
let pointer = UnsafeRawPointer(bounds.lowerBound)
let result = GenericBufferView(
baseAddress: pointer,
count: bounds.upperBound.distance(to:bounds.lowerBound) / MemoryLayout<Element>.stride
)
// assuming that bounds is within self
return _overrideLifetime(result, copying: self)
}
}
}
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence23tupleLifetimeDependenceyAA10BufferViewV_ADtADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(copy 0) (@owned BufferView, @owned BufferView) {
@lifetime(copy x)
func tupleLifetimeDependence(_ x: borrowing BufferView) -> (BufferView, BufferView) {
return (BufferView(x.ptr, x.c), BufferView(x.ptr, x.c))
}
public struct OuterNE: ~Escapable {
// A public property generates an implicit setter with an infered dependence on 'newValue'.
//
// [inner1.setter]
// CHECK-LABEL: sil [transparent] @$s28implicit_lifetime_dependence7OuterNEV6inner1AC05InnerE0Vvs : $@convention(method) (@owned OuterNE.InnerNE, @lifetime(copy 0, copy 1) @inout OuterNE) -> () {
public var inner1: InnerNE
// Explicit setter with an infered dependence on 'newValue'.
public var inner2: InnerNE {
@lifetime(copy self)
get { inner1 }
@lifetime(self: copy newValue)
set { inner1 = newValue }
}
public struct InnerNE: ~Escapable {
@lifetime(copy owner)
init<Owner: ~Escapable & ~Copyable>(
owner: borrowing Owner
) {}
}
@lifetime(copy owner)
init<Owner: ~Copyable & ~Escapable>(owner: borrowing Owner) {
self.inner1 = InnerNE(owner: owner)
}
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7OuterNEV8setInner5valueyAC0gE0V_tF : $@convention(method) (@guaranteed OuterNE.InnerNE, @lifetime(copy 0) @inout OuterNE) -> () {
@lifetime(self: copy value)
mutating func setInner(value: InnerNE) {
self.inner1 = value
}
}