Skip to content

Commit 28c0e4d

Browse files
authored
Merge pull request #71640 from meg-gupta/inferinit
Update diagnostics for lifetime dependence
2 parents 823db1f + 59a401d commit 28c0e4d

13 files changed

+159
-115
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7813,30 +7813,30 @@ ERROR(lifetime_dependence_cannot_use_kind, none,
78137813
(StringRef, StringRef))
78147814
ERROR(lifetime_dependence_only_on_function_method_init_result, none,
78157815
"lifetime dependence specifiers may only be used on result of "
7816-
"functions, methods, initializers",
7817-
())
7816+
"functions, methods, initializers", ())
78187817
ERROR(lifetime_dependence_invalid_return_type, none,
78197818
"lifetime dependence can only be specified on ~Escapable results", ())
78207819
ERROR(lifetime_dependence_missing_ownership_modifier, none,
78217820
"lifetime dependence can only be specified on parameters with ownership "
78227821
"modifiers (borrowing, consuming, inout)", ())
78237822
ERROR(lifetime_dependence_cannot_infer_wo_ownership_modifier_on_method, none,
78247823
"cannot infer lifetime dependence, specify ownership modifier for the "
7825-
"method",
7826-
())
7827-
ERROR(lifetime_dependence_cannot_infer_wo_ambiguous_candidate, none,
7824+
"method", ())
7825+
ERROR(lifetime_dependence_cannot_infer_ambiguous_candidate, none,
78287826
"cannot infer lifetime dependence, multiple ~Escapable or ~Copyable "
78297827
"parameters with ownership modifiers, specify explicit lifetime "
7830-
"dependence",
7831-
())
7828+
"dependence", ())
78327829
ERROR(lifetime_dependence_cannot_infer_no_candidates, none,
7833-
"cannot infer lifetime dependence, no ~Escapable or ~Copyable "
7834-
"parameters with ownership modifiers present",
7835-
())
7830+
"cannot infer lifetime dependence, no parameters with ownership "
7831+
"modifiers present", ())
78367832
ERROR(lifetime_dependence_ctor_non_self_or_nil_return, none,
78377833
"expected nil or self as return values in an initializer with "
7838-
"lifetime dependent specifiers",
7839-
())
7834+
"lifetime dependent specifiers", ())
7835+
ERROR(lifetime_dependence_cannot_use_infer, none,
7836+
"invalid use of %0 lifetime dependence on Escapable type",
7837+
(StringRef))
7838+
ERROR(lifetime_dependence_on_bitwise_copyable, none,
7839+
"invalid lifetime dependence on bitwise copyable type", ())
78407840

78417841
//===----------------------------------------------------------------------===//
78427842
// MARK: Transferring

lib/Sema/LifetimeDependence.cpp

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
107107
bool allowIndex) {
108108
auto *dc = afd->getDeclContext();
109109
auto &ctx = dc->getASTContext();
110+
auto *mod = afd->getModuleContext();
110111
auto &diags = ctx.Diags;
111112
auto capacity = afd->getParameters()->size() + 1;
112113
auto lifetimeDependentRepr =
@@ -116,7 +117,7 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
116117
SmallBitVector scopeLifetimeParamIndices(capacity);
117118

118119
auto updateLifetimeDependenceInfo = [&](LifetimeDependenceSpecifier specifier,
119-
unsigned paramIndexToSet,
120+
unsigned paramIndexToSet, Type type,
120121
ValueOwnership ownership) {
121122
auto loc = specifier.getLoc();
122123
auto kind = specifier.getLifetimeDependenceKind();
@@ -148,6 +149,24 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
148149
getOwnershipSpelling(ownership));
149150
return true;
150151
}
152+
if (kind == LifetimeDependenceKind::Consume ||
153+
kind == LifetimeDependenceKind::Copy) {
154+
if (type->isEscapable()) {
155+
diags.diagnose(loc, diag::lifetime_dependence_cannot_use_infer,
156+
specifier.getLifetimeDependenceKindString());
157+
return true;
158+
}
159+
}
160+
161+
if (ctx.LangOpts.hasFeature(Feature::BitwiseCopyable)) {
162+
auto *bitwiseCopyableProtocol =
163+
ctx.getProtocol(KnownProtocolKind::BitwiseCopyable);
164+
if (bitwiseCopyableProtocol && mod->checkConformance(type, bitwiseCopyableProtocol)) {
165+
diags.diagnose(loc, diag::lifetime_dependence_on_bitwise_copyable);
166+
return true;
167+
}
168+
}
169+
151170
if (inheritLifetimeParamIndices.test(paramIndexToSet) ||
152171
scopeLifetimeParamIndices.test(paramIndexToSet)) {
153172
diags.diagnose(loc, diag::lifetime_dependence_duplicate_param_id);
@@ -168,17 +187,20 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
168187
switch (specifier.getSpecifierKind()) {
169188
case LifetimeDependenceSpecifier::SpecifierKind::Named: {
170189
bool foundParamName = false;
171-
unsigned paramIndexToSet = 1;
190+
unsigned paramIndex = 0;
172191
for (auto *param : *afd->getParameters()) {
173192
if (param->getParameterName() == specifier.getName()) {
174193
foundParamName = true;
175-
if (updateLifetimeDependenceInfo(specifier, paramIndexToSet,
176-
param->getValueOwnership())) {
194+
if (updateLifetimeDependenceInfo(
195+
specifier, paramIndex + 1,
196+
afd->mapTypeIntoContext(
197+
param->toFunctionParam().getParameterType()),
198+
param->getValueOwnership())) {
177199
return llvm::None;
178200
}
179201
break;
180202
}
181-
paramIndexToSet++;
203+
paramIndex++;
182204
}
183205
if (!foundParamName) {
184206
diags.diagnose(specifier.getLoc(),
@@ -189,29 +211,23 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
189211
break;
190212
}
191213
case LifetimeDependenceSpecifier::SpecifierKind::Ordered: {
192-
auto paramIndex = specifier.getIndex();
193-
if (paramIndex > afd->getParameters()->size()) {
214+
auto index = specifier.getIndex();
215+
if (index > afd->getParameters()->size()) {
194216
diags.diagnose(specifier.getLoc(),
195-
diag::lifetime_dependence_invalid_param_index,
196-
paramIndex);
217+
diag::lifetime_dependence_invalid_param_index, index);
197218
return llvm::None;
198219
}
199-
if (paramIndex == 0) {
200-
if (!afd->hasImplicitSelfDecl()) {
201-
diags.diagnose(specifier.getLoc(),
202-
diag::lifetime_dependence_invalid_self);
220+
if (index != 0) {
221+
auto param = afd->getParameters()->get(index - 1);
222+
auto ownership = param->getValueOwnership();
223+
auto type = afd->mapTypeIntoContext(
224+
param->toFunctionParam().getParameterType());
225+
if (updateLifetimeDependenceInfo(specifier, index, type, ownership)) {
203226
return llvm::None;
204227
}
228+
break;
205229
}
206-
auto ownership =
207-
paramIndex == 0
208-
? afd->getImplicitSelfDecl()->getValueOwnership()
209-
: afd->getParameters()->get(paramIndex - 1)->getValueOwnership();
210-
if (updateLifetimeDependenceInfo(
211-
specifier, /*paramIndexToSet*/ specifier.getIndex(), ownership)) {
212-
return llvm::None;
213-
}
214-
break;
230+
LLVM_FALLTHROUGH;
215231
}
216232
case LifetimeDependenceSpecifier::SpecifierKind::Self: {
217233
if (!afd->hasImplicitSelfDecl()) {
@@ -221,6 +237,7 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
221237
}
222238
if (updateLifetimeDependenceInfo(
223239
specifier, /*selfIndex*/ 0,
240+
afd->getImplicitSelfDecl()->getTypeInContext(),
224241
afd->getImplicitSelfDecl()->getValueOwnership())) {
225242
return llvm::None;
226243
}
@@ -293,19 +310,21 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd, Type resultType) {
293310
if (param->getValueOwnership() == ValueOwnership::Default) {
294311
continue;
295312
}
313+
if (param->getValueOwnership() == ValueOwnership::Owned &&
314+
paramTypeInContext->isEscapable()) {
315+
continue;
316+
}
296317

297-
if (!paramTypeInContext->isEscapable() ||
298-
paramTypeInContext->isNoncopyable()) {
299-
if (candidateParam) {
300-
diags.diagnose(
301-
returnLoc,
302-
diag::lifetime_dependence_cannot_infer_wo_ambiguous_candidate);
303-
return llvm::None;
304-
}
305-
candidateParam = param;
306-
lifetimeDependenceInfo = LifetimeDependenceInfo::getForParamIndex(
307-
afd, paramIndex + 1, param->getValueOwnership());
318+
if (candidateParam) {
319+
diags.diagnose(
320+
returnLoc,
321+
diag::lifetime_dependence_cannot_infer_ambiguous_candidate);
322+
return llvm::None;
308323
}
324+
candidateParam = param;
325+
lifetimeDependenceInfo = LifetimeDependenceInfo::getForParamIndex(
326+
afd, paramIndex + 1, param->getValueOwnership());
327+
309328
paramIndex++;
310329
}
311330
if (!candidateParam && !hasParamError) {

test/Parse/explicit_lifetime_dependence_specifiers.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature NonescapableTypes -disable-experimental-parser-round-trip -enable-experimental-feature NoncopyableGenerics -enable-builtin-module
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature NonescapableTypes -disable-experimental-parser-round-trip -enable-experimental-feature NoncopyableGenerics -enable-builtin-module -enable-experimental-lifetime-dependence-inference
2+
// REQUIRES: asserts
23
// REQUIRES: noncopyable_generics
34

45
import Builtin
56

67
struct BufferView : ~Escapable {
78
let ptr: UnsafeRawBufferPointer
9+
@_unsafeNonescapableResult
810
init(_ ptr: UnsafeRawBufferPointer) {
911
self.ptr = ptr
1012
}
13+
@_unsafeNonescapableResult
1114
init?(_ ptr: UnsafeRawBufferPointer, _ i: Int) {
1215
if (i % 2 == 0) {
1316
return nil
@@ -18,15 +21,15 @@ struct BufferView : ~Escapable {
1821
self.ptr = ptr
1922
return self
2023
}
21-
init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array<Double>) -> _consume(a) Self {
24+
init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Wrapper) -> _consume(a) Self {
2225
self.ptr = ptr
2326
return self
2427
}
25-
init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array<Double>, b: borrowing Array<Int>) -> _consume(a) _borrow(b) Self {
28+
init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Wrapper, b: borrowing Array<Int>) -> _consume(a) _borrow(b) Self {
2629
self.ptr = ptr
2730
return self
2831
}
29-
init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array<Double>, b: borrowing Array<Int>, c: Double) -> _consume(a) _borrow(b) Int { // expected-error{{expected Self return type for initializers with lifetime dependence specifiers}}
32+
init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array<Double>, b: borrowing Array<Int>, c: Double) -> _consume(a) _borrow(b) Int { // expected-error{{expected Self return type for initializers with lifetime dependence specifiers}}
3033
self.ptr = ptr
3134
return 0
3235
}
@@ -43,6 +46,7 @@ struct BufferView : ~Escapable {
4346

4447
struct MutableBufferView : ~Escapable, ~Copyable {
4548
let ptr: UnsafeMutableRawBufferPointer
49+
@_unsafeNonescapableResult
4650
init(_ ptr: UnsafeMutableRawBufferPointer) {
4751
self.ptr = ptr
4852
}
@@ -131,6 +135,10 @@ func invalidSpecifier4(_ x: borrowing BufferView) -> _borrow(0) BufferView { //
131135

132136
struct Wrapper : ~Escapable {
133137
let view: BufferView
138+
init(_ view: consuming BufferView) -> _consume(view) Self {
139+
self.view = view
140+
return self
141+
}
134142
borrowing func getView1() -> _borrow(self) BufferView {
135143
return view
136144
}

test/SIL/explicit_lifetime_dependence_specifiers.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ struct BufferView : ~Escapable {
2727
self.ptr = ptr
2828
return self
2929
}
30-
// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_SaySdGYlitcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Array<Double>, @thin BufferView.Type) -> _inherit(2) @owned BufferView {
31-
init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array<Double>) -> _consume(a) Self {
30+
// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_AA7WrapperVYlitcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Wrapper, @thin BufferView.Type) -> _inherit(2) @owned BufferView {
31+
init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Wrapper) -> _consume(a) Self {
3232
self.ptr = ptr
3333
return self
3434
}
35-
// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_SaySdGYliSaySiGhYlstcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Array<Double>, @guaranteed Array<Int>, @thin BufferView.Type) -> _inherit(2)_scope(3) @owned BufferView {
36-
init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Array<Double>, _ b: borrowing Array<Int>) -> _consume(a) _borrow(b) Self {
35+
// CHECK: sil hidden @$s39explicit_lifetime_dependence_specifiers10BufferViewVyACSW_AA7WrapperVYliSaySiGhYlstcfC : $@convention(method) (UnsafeRawBufferPointer, @owned Wrapper, @guaranteed Array<Int>, @thin BufferView.Type) -> _inherit(2)_scope(3) @owned BufferView {
36+
init(_ ptr: UnsafeRawBufferPointer, _ a: consuming Wrapper, _ b: borrowing Array<Int>) -> _consume(a) _borrow(b) Self {
3737
self.ptr = ptr
3838
return self
3939
}
@@ -102,19 +102,20 @@ struct Wrapper : ~Escapable {
102102
}
103103
}
104104

105-
struct Container {
105+
struct Container : ~Escapable {
106106
let ptr: UnsafeRawBufferPointer
107+
@_unsafeNonescapableResult
107108
init(_ ptr: UnsafeRawBufferPointer) {
108109
self.ptr = ptr
109110
}
110111
}
111112

112-
// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16getConsumingViewyAA06BufferG0VAA9ContainerVnYliF : $@convention(thin) (Container) -> _inherit(1) @owned BufferView {
113+
// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16getConsumingViewyAA06BufferG0VAA9ContainerVnYliF : $@convention(thin) (@owned Container) -> _inherit(1) @owned BufferView {
113114
func getConsumingView(_ x: consuming Container) -> _consume(x) BufferView {
114115
return BufferView(x.ptr)
115116
}
116117

117-
// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16getBorrowingViewyAA06BufferG0VAA9ContainerVYlsF : $@convention(thin) (Container) -> _scope(1) @owned BufferView {
118+
// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers16getBorrowingViewyAA06BufferG0VAA9ContainerVYlsF : $@convention(thin) (@guaranteed Container) -> _scope(1) @owned BufferView {
118119
func getBorrowingView(_ x: borrowing Container) -> _borrow(x) BufferView {
119120
return BufferView(x.ptr)
120121
}

test/SIL/implicit_lifetime_dependence.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ struct BufferView : ~Escapable {
2424
init(_ otherBV: consuming BufferView) {
2525
self.ptr = otherBV.ptr
2626
}
27+
// CHECK: sil hidden @$s28implicit_lifetime_dependence10BufferViewVyACSWYls_SaySiGhtcfC : $@convention(method) (UnsafeRawBufferPointer, @guaranteed Array<Int>, @thin BufferView.Type) -> _scope(1) @owned BufferView {
28+
init(_ ptr: UnsafeRawBufferPointer, _ a: borrowing Array<Int>) {
29+
self.ptr = ptr
30+
}
2731
}
2832

2933
struct MutableBufferView : ~Escapable, ~Copyable {

test/SIL/lifetime_dependence_generics.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public struct PView: P {
2525
borrowing func getE() -> _borrow(self) View { return View() }
2626
}
2727

28-
public func test(pview: consuming PView) -> _consume(pview) View {
28+
public func test(pview: borrowing PView) -> _borrow(pview) View {
2929
return pview.getDefault()
3030
}
3131

@@ -35,4 +35,4 @@ public func test(pview: consuming PView) -> _consume(pview) View {
3535

3636
// CHECK: sil private [transparent] [thunk] @$s28lifetime_dependence_generics5PViewVAA1PA2aDP4getE1EQzyYLsFTW : $@convention(witness_method: P) (@in_guaranteed PView) -> _scope(0) @out View {
3737

38-
// CHECK: sil @$s28lifetime_dependence_generics4test5pviewAA4ViewVAA5PViewVnYli_tF : $@convention(thin) (PView) -> _inherit(1) @owned View {
38+
// CHECK: sil @$s28lifetime_dependence_generics4test5pviewAA4ViewVAA5PViewVYls_tF : $@convention(thin) (PView) -> _scope(1) @owned View {

test/SILOptimizer/lifetime_dependence_borrow.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
// RUN: -enable-experimental-feature NonescapableTypes \
88
// RUN: -Xllvm -enable-lifetime-dependence-diagnostics
99

10+
// REQUIRES: asserts
11+
// REQUIRES: noncopyable_generics
1012
// REQUIRES: swift_in_compiler
1113

12-
@_nonescapable
13-
struct BV {
14+
struct BV : ~Escapable {
1415
let p: UnsafeRawPointer
1516
let c: Int
1617

@@ -23,7 +24,7 @@ struct BV {
2324
}
2425
}
2526

26-
struct NC : ~Copyable {
27+
struct NCNE : ~Copyable, ~Escapable {
2728
let p: UnsafeRawPointer
2829
let c: Int
2930

@@ -34,16 +35,16 @@ struct NC : ~Copyable {
3435
}
3536

3637
// Propagate a borrow.
37-
func bv_get_borrow(container: borrowing NC) -> _borrow(container) BV {
38+
func bv_get_borrow(container: borrowing NCNE) -> _borrow(container) BV {
3839
container.getBV()
3940
}
4041

4142
// Copy a borrow.
42-
func bv_get_copy(container: borrowing NC) -> _copy(container) BV {
43+
func bv_get_copy(container: borrowing NCNE) -> _copy(container) BV {
4344
return container.getBV()
4445
}
4546

4647
// Recognize nested accesses as part of the same dependence scope.
47-
func bv_get_mutate(container: inout NC) -> _mutate(container) BV {
48+
func bv_get_mutate(container: inout NCNE) -> _mutate(container) BV {
4849
container.getBV()
4950
}

0 commit comments

Comments
 (0)