Skip to content

Commit 8209294

Browse files
committed
Add support for lifetime dependence inference for _read/_modify accessors
1 parent d35dcc8 commit 8209294

4 files changed

+121
-52
lines changed

lib/Sema/LifetimeDependence.cpp

+23-11
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,16 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd, Type resultType) {
274274
auto returnTypeRepr = afd->getResultTypeRepr();
275275
auto returnLoc = returnTypeRepr ? returnTypeRepr->getLoc() : afd->getLoc();
276276
Type returnTyInContext = afd->mapTypeIntoContext(resultType);
277+
std::optional<Type> yieldTyInContext;
277278

278-
if (returnTyInContext->isEscapable()) {
279+
if (auto *accessor = dyn_cast<AccessorDecl>(afd)) {
280+
if (accessor->isCoroutine()) {
281+
yieldTyInContext = accessor->getStorage()->getValueInterfaceType();
282+
yieldTyInContext = accessor->mapTypeIntoContext(*yieldTyInContext);
283+
}
284+
}
285+
if (returnTyInContext->isEscapable() &&
286+
(!yieldTyInContext.has_value() || (*yieldTyInContext)->isEscapable())) {
279287
return llvm::None;
280288
}
281289
if (afd->getAttrs().hasAttribute<UnsafeNonEscapableResultAttr>()) {
@@ -285,21 +293,25 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd, Type resultType) {
285293
if (afd->getKind() != DeclKind::Constructor && afd->hasImplicitSelfDecl()) {
286294
ValueOwnership ownership = ValueOwnership::Default;
287295
if (auto *AD = dyn_cast<AccessorDecl>(afd)) {
288-
if (AD->getAccessorKind() == AccessorKind::Get) {
296+
if (AD->getAccessorKind() == AccessorKind::Get ||
297+
AD->getAccessorKind() == AccessorKind::Read) {
289298
// We don't support "borrowing/consuming" ownership modifiers on
290-
// getters, by default they are guaranteed for now.
299+
// getters/_read accessors, they are guaranteed by default for now.
291300
ownership = ValueOwnership::Shared;
292301
}
302+
if (AD->getAccessorKind() == AccessorKind::Modify) {
303+
ownership = ValueOwnership::InOut;
304+
}
293305
} else {
306+
assert(afd->getKind() == DeclKind::Func);
294307
ownership = afd->getImplicitSelfDecl()->getValueOwnership();
295-
}
296-
297-
if (ownership == ValueOwnership::Default) {
298-
diags.diagnose(
299-
returnLoc,
300-
diag::
301-
lifetime_dependence_cannot_infer_wo_ownership_modifier_on_method);
302-
return llvm::None;
308+
if (ownership == ValueOwnership::Default) {
309+
diags.diagnose(
310+
returnLoc,
311+
diag::
312+
lifetime_dependence_cannot_infer_wo_ownership_modifier_on_method);
313+
return llvm::None;
314+
}
303315
}
304316
return LifetimeDependenceInfo::getForParamIndex(afd, /*selfIndex*/ 0,
305317
ownership);

test/SIL/implicit_lifetime_dependence.swift

+43-17
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,43 @@ import Builtin
1212

1313
struct BufferView : ~Escapable {
1414
let ptr: UnsafeRawBufferPointer
15+
let c: Int
1516
@_unsafeNonescapableResult
16-
init(_ ptr: UnsafeRawBufferPointer) {
17+
init(_ ptr: UnsafeRawBufferPointer, _ c: Int) {
1718
self.ptr = ptr
19+
self.c = c
1820
}
1921
// CHECK: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyA2ChYlscfC : $@convention(method) (@guaranteed BufferView, @thin BufferView.Type) -> _scope(1) @owned BufferView {
2022
init(_ otherBV: borrowing BufferView) {
2123
self.ptr = otherBV.ptr
24+
self.c = otherBV.c
2225
}
2326
// CHECK: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyA2CYlicfC : $@convention(method) (@owned BufferView, @thin BufferView.Type) -> _inherit(1) @owned BufferView {
2427
init(_ otherBV: consuming BufferView) {
2528
self.ptr = otherBV.ptr
29+
self.c = otherBV.c
2630
}
2731
// CHECK: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyACSWYls_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array<Int>, @thin BufferView.Type) -> _scope(1) @owned BufferView {
2832
init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array<Int>) {
2933
self.ptr = ptr
34+
self.c = a.count
3035
}
3136
}
3237

3338
struct MutableBufferView : ~Escapable, ~Copyable {
3439
let ptr: UnsafeMutableRawBufferPointer
40+
let c: Int
3541
@_unsafeNonescapableResult
36-
init(_ ptr: UnsafeMutableRawBufferPointer) {
42+
init(_ ptr: UnsafeMutableRawBufferPointer, _ c: Int) {
3743
self.ptr = ptr
44+
self.c = c
3845
}
3946
}
4047

4148
func testBasic() {
42-
let capacity = 4
43-
let a = Array(0..<capacity)
49+
let a = [Int](repeating: 0, count: 4)
4450
a.withUnsafeBytes {
45-
let view = BufferView($0)
51+
let view = BufferView($0, a.count)
4652
let derivedView = derive(view)
4753
let newView = consumeAndCreate(derivedView)
4854
use(newView)
@@ -51,42 +57,62 @@ func testBasic() {
5157

5258
// CHECK: sil hidden @$s28implicit_lifetime_dependence6deriveyAA10BufferViewVADYlsF : $@convention(thin) (@guaranteed BufferView) -> _scope(1) @owned BufferView {
5359
func derive(_ x: borrowing BufferView) -> BufferView {
54-
return BufferView(x.ptr)
60+
return BufferView(x.ptr, x.c)
5561
}
5662

5763
// CHECK: sil hidden @$s28implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnYliF : $@convention(thin) (@owned BufferView) -> _inherit(1) @owned BufferView {
5864
func consumeAndCreate(_ x: consuming BufferView) -> BufferView {
59-
return BufferView(x.ptr)
65+
return BufferView(x.ptr, x.c)
6066
}
6167

6268
func use(_ x: borrowing BufferView) {}
6369

6470
struct Wrapper : ~Escapable {
65-
let view: BufferView
71+
var _view: BufferView
72+
var view: BufferView {
73+
// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvr : $@yield_once @convention(method) (@guaranteed Wrapper) -> _scope(0) @yields @guaranteed BufferView {
74+
_read {
75+
yield _view
76+
}
77+
// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvM : $@yield_once @convention(method) (@inout Wrapper) -> _scope(0) @yields @inout BufferView {
78+
_modify {
79+
yield &_view
80+
}
81+
}
6682
// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperVyAcA10BufferViewVYlicfC : $@convention(method) (@owned BufferView, @thin Wrapper.Type) -> _inherit(1) @owned Wrapper {
6783
init(_ view: consuming BufferView) {
68-
self.view = view
84+
self._view = view
6985
}
7086
// CHECK: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView1AA10BufferViewVyYLsF : $@convention(method) (@guaranteed Wrapper) -> _scope(0) @owned BufferView {
7187
borrowing func getView1() -> BufferView {
72-
return view
88+
return _view
7389
}
7490

7591
// CHECK:sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView2AA10BufferViewVyYLiF : $@convention(method) (@owned Wrapper) -> _inherit(0) @owned BufferView {
7692
consuming func getView2() -> BufferView {
77-
return view
93+
return _view
7894
}
7995
}
8096

81-
struct Container : ~Copyable {
82-
var ptr: UnsafeRawBufferPointer
83-
// CHECK: sil hidden @$s28implicit_lifetime_dependence9ContainerV4viewAA10BufferViewVvg : $@convention(method) (@guaranteed Container) -> _scope(0) @owned BufferView {
97+
struct Container1 : ~Copyable {
98+
let ptr: UnsafeRawBufferPointer
99+
let c: Int
100+
// CHECK: sil hidden @$s28implicit_lifetime_dependence10Container1V4viewAA10BufferViewVvg : $@convention(method) (@guaranteed Container1) -> _scope(0) @owned BufferView {
84101
var view: BufferView {
85102
get {
86-
return BufferView(ptr)
103+
return BufferView(ptr, c)
87104
}
88-
set(newView) {
89-
ptr = newView.ptr
105+
}
106+
}
107+
108+
struct Container2 : ~Copyable {
109+
let ptr: UnsafeMutableRawBufferPointer
110+
let c: Int
111+
// CHECK: sil hidden @$s28implicit_lifetime_dependence10Container2V11mutableViewAA013MutableBufferF0Vvr : $@yield_once @convention(method) (@guaranteed Container2) -> _scope(0) @yields @guaranteed MutableBufferView {
112+
var mutableView: MutableBufferView {
113+
_read {
114+
yield MutableBufferView(ptr, c)
90115
}
91116
}
92117
}
118+
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,66 @@
11
public struct BufferView : ~Escapable {
22
let ptr: UnsafeRawBufferPointer
3+
let c: Int
34
@_unsafeNonescapableResult
4-
public init(_ ptr: UnsafeRawBufferPointer) {
5+
public init(_ ptr: UnsafeRawBufferPointer, _ c: Int) {
56
self.ptr = ptr
7+
self.c = c
68
}
79
public init(_ otherBV: borrowing BufferView) {
810
self.ptr = otherBV.ptr
11+
self.c = otherBV.c
912
}
1013
}
1114

1215
public struct MutableBufferView : ~Escapable, ~Copyable {
1316
let ptr: UnsafeMutableRawBufferPointer
17+
let c: Int
1418
@_unsafeNonescapableResult
15-
public init(_ ptr: UnsafeMutableRawBufferPointer) {
19+
public init(_ ptr: UnsafeMutableRawBufferPointer, _ c: Int) {
1620
self.ptr = ptr
21+
self.c = c
1722
}
1823
}
1924

2025
public func derive(_ x: borrowing BufferView) -> BufferView {
21-
return BufferView(x.ptr)
26+
return BufferView(x.ptr, x.c)
2227
}
2328

24-
public func use(_ x: borrowing BufferView) {}
25-
2629
public func borrowAndCreate(_ view: borrowing BufferView) -> BufferView {
27-
return BufferView(view.ptr)
30+
return BufferView(view.ptr, view.c )
2831
}
2932

3033
public func consumeAndCreate(_ view: consuming BufferView) -> BufferView {
31-
return BufferView(view.ptr)
34+
return BufferView(view.ptr, view.c)
3235
}
3336

3437
public struct Container : ~Copyable {
35-
var ptr: UnsafeRawBufferPointer
36-
37-
public init(_ ptr: UnsafeRawBufferPointer) {
38+
let ptr: UnsafeRawBufferPointer
39+
let c: Int
40+
public init(_ ptr: UnsafeRawBufferPointer, _ c: Int) {
3841
self.ptr = ptr
42+
self.c = c
3943
}
4044

4145
public var view: BufferView {
4246
get {
43-
return BufferView(ptr)
47+
return BufferView(ptr, c)
48+
}
49+
}
50+
}
51+
52+
public struct Wrapper : ~Escapable {
53+
var _view: BufferView
54+
public var view: BufferView {
55+
_read {
56+
yield _view
4457
}
45-
set(newView) {
46-
ptr = newView.ptr
58+
_modify {
59+
yield &_view
4760
}
4861
}
62+
public init(_ view: consuming BufferView) {
63+
self._view = view
64+
}
4965
}
66+

test/Serialization/implicit_lifetime_dependence.swift

+25-11
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
import def_implicit_lifetime_dependence
1818

19+
func use(_ x: borrowing BufferView) {}
20+
func mutate(_ x: inout BufferView) {}
21+
1922
func testBasic() {
20-
let capacity = 4
21-
let a = Array(0..<capacity)
23+
let a = [Int](repeating: 0, count: 4)
2224
a.withUnsafeBytes {
23-
let view = BufferView($0)
25+
let view = BufferView($0, a.count)
2426
let derivedView = derive(view)
2527
let consumedView = consumeAndCreate(derivedView)
2628
let borrowedView = borrowAndCreate(consumedView)
@@ -29,33 +31,41 @@ func testBasic() {
2931
}
3032

3133
func testInitializers() {
32-
let capacity = 4
33-
let a = Array(0..<capacity)
34+
let a = [Int](repeating: 0, count: 4)
3435
a.withUnsafeBytes {
35-
let view1 = BufferView($0)
36+
let view1 = BufferView($0, a.count)
3637
let view2 = BufferView(view1)
3738
let view3 = BufferView(view2)
3839
use(view3)
3940
}
4041
}
4142

42-
func unsafetest(_ ptr: UnsafeRawBufferPointer) {
43-
let view1 = BufferView(ptr)
43+
func unsafetest(_ ptr: UnsafeRawBufferPointer, _ c: Int) {
44+
let view1 = BufferView(ptr, c)
4445
let view2 = BufferView(view1)
4546
let view3 = BufferView(view2)
4647
use(view3)
4748
}
4849

4950
func testGetter() {
50-
let capacity = 4
51-
let a = Array(0..<capacity)
51+
let a = [Int](repeating: 0, count: 4)
5252
a.withUnsafeBytes {
53-
let c = Container($0)
53+
let c = Container($0, a.count)
5454
let view = c.view
5555
use(view)
5656
}
5757
}
5858

59+
func testReadmutateAccessors() {
60+
let a = [Int](repeating: 0, count: 4)
61+
a.withUnsafeBytes {
62+
let view = BufferView($0, a.count)
63+
var c = Wrapper(view)
64+
use(c.view)
65+
mutate(&c.view)
66+
}
67+
}
68+
5969
// CHECK: sil @$s32def_implicit_lifetime_dependence6deriveyAA10BufferViewVADYlsF : $@convention(thin) (@guaranteed BufferView) -> _scope(1) @owned BufferView
6070

6171
// CHECK: sil @$s32def_implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnYliF : $@convention(thin) (@owned BufferView) -> _inherit(1) @owned BufferView
@@ -65,3 +75,7 @@ func testGetter() {
6575
// CHECK: sil @$s32def_implicit_lifetime_dependence10BufferViewVyA2ChYlscfC : $@convention(method) (@guaranteed BufferView, @thin BufferView.Type) -> _scope(1) @owned BufferView
6676

6777
// CHECK: sil @$s32def_implicit_lifetime_dependence9ContainerV4viewAA10BufferViewVvg : $@convention(method) (@guaranteed Container) -> _scope(0) @owned BufferView
78+
79+
// CHECK: sil @$s32def_implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvr : $@yield_once @convention(method) (@guaranteed Wrapper) -> _scope(0) @yields @guaranteed BufferView
80+
81+
// CHECK: sil @$s32def_implicit_lifetime_dependence7WrapperV4viewAA10BufferViewVvM : $@yield_once @convention(method) (@inout Wrapper) -> _scope(0) @yields @inout BufferView

0 commit comments

Comments
 (0)