Skip to content

Commit 4dcda84

Browse files
committed
Infer lifetime dependence info for functions that return ~Escapable type
1 parent fb993bf commit 4dcda84

File tree

6 files changed

+177
-6
lines changed

6 files changed

+177
-6
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7811,5 +7811,18 @@ ERROR(pack_iteration_where_clause_not_supported, none,
78117811
ERROR(lifetime_dependence_missing_ownership_modifier, none,
78127812
"lifetime dependence can only be specified on parameters with ownership "
78137813
"modifiers (borrowing, consuming, inout)", ())
7814+
ERROR(lifetime_dependence_cannot_infer_wo_ownership_modifier_on_method, none,
7815+
"cannot infer lifetime dependence, specify ownership modifier for the "
7816+
"method",
7817+
())
7818+
ERROR(lifetime_dependence_cannot_infer_wo_ambiguous_candidate, none,
7819+
"cannot infer lifetime dependence, multiple ~Escapable or ~Copyable "
7820+
"parameters with ownership modifiers, specify explicit lifetime "
7821+
"dependence",
7822+
())
7823+
ERROR(lifetime_dependence_cannot_infer_no_candidates, none,
7824+
"cannot infer lifetime dependence, no ~Escapable or ~Copyable "
7825+
"parameters with ownership modifiers present",
7826+
())
78147827
#define UNDEFINE_DIAGNOSTIC_MACROS
78157828
#include "DefineDiagnosticMacros.h"

include/swift/AST/LifetimeDependence.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "swift/AST/Identifier.h"
2121
#include "swift/AST/IndexSubset.h"
22+
#include "swift/AST/Ownership.h"
2223
#include "swift/Basic/Debug.h"
2324
#include "swift/Basic/OptionSet.h"
2425
#include "swift/Basic/SourceLoc.h"
@@ -133,9 +134,16 @@ class LifetimeDependenceInfo {
133134
IndexSubset *borrowLifetimeParamIndices;
134135
IndexSubset *mutateLifetimeParamIndices;
135136

137+
static LifetimeDependenceInfo getForParamIndex(AbstractFunctionDecl *afd,
138+
unsigned index,
139+
ValueOwnership ownership);
140+
136141
static llvm::Optional<LifetimeDependenceInfo>
137142
fromTypeRepr(AbstractFunctionDecl *afd, Type resultType, bool allowIndex);
138143

144+
static llvm::Optional<LifetimeDependenceInfo> infer(AbstractFunctionDecl *afd,
145+
Type resultType);
146+
139147
public:
140148
LifetimeDependenceInfo()
141149
: inheritLifetimeParamIndices(nullptr),

lib/Sema/LifetimeDependence.cpp

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "swift/AST/LifetimeDependence.h"
1413
#include "TypeChecker.h"
14+
1515
#include "swift/AST/ASTContext.h"
1616
#include "swift/AST/Decl.h"
17+
#include "swift/AST/LifetimeDependence.h"
1718
#include "swift/AST/ParameterList.h"
1819
#include "swift/AST/Type.h"
1920
#include "swift/AST/TypeRepr.h"
@@ -62,6 +63,28 @@ void LifetimeDependenceInfo::Profile(llvm::FoldingSetNodeID &ID) const {
6263
}
6364
}
6465

66+
LifetimeDependenceInfo LifetimeDependenceInfo::getForParamIndex(
67+
AbstractFunctionDecl *afd, unsigned index, ValueOwnership ownership) {
68+
auto *dc = afd->getDeclContext();
69+
auto &ctx = dc->getASTContext();
70+
unsigned capacity = afd->getParameters()->size() + 1;
71+
auto indexSubset = IndexSubset::get(ctx, capacity, {index});
72+
if (ownership == ValueOwnership::Owned) {
73+
return LifetimeDependenceInfo{/*inheritLifetimeParamIndices*/ indexSubset,
74+
/*borrowLifetimeParamIndices*/ nullptr,
75+
/*mutateLifetimeParamIndices*/ nullptr};
76+
}
77+
if (ownership == ValueOwnership::Shared) {
78+
return LifetimeDependenceInfo{/*inheritLifetimeParamIndices*/ nullptr,
79+
/*borrowLifetimeParamIndices*/ indexSubset,
80+
/*mutateLifetimeParamIndices*/ nullptr};
81+
}
82+
assert(ownership == ValueOwnership::InOut);
83+
return LifetimeDependenceInfo{/*inheritLifetimeParamIndices*/ nullptr,
84+
/*borrowLifetimeParamIndices*/ nullptr,
85+
/*mutateLifetimeParamIndices*/ indexSubset};
86+
}
87+
6588
llvm::Optional<LifetimeDependenceInfo>
6689
LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
6790
bool allowIndex) {
@@ -81,8 +104,8 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
81104
ValueOwnership ownership) {
82105
auto loc = specifier.getLoc();
83106
auto kind = specifier.getLifetimeDependenceKind();
84-
85-
if (resultType->isEscapable()) {
107+
Type resultTypeInContext = afd->mapTypeIntoContext(resultType);
108+
if (resultTypeInContext->isEscapable()) {
86109
diags.diagnose(loc, diag::lifetime_dependence_invalid_return_type);
87110
return true;
88111
}
@@ -187,6 +210,78 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
187210
IndexSubset::get(ctx, mutateLifetimeParamIndices));
188211
}
189212

213+
llvm::Optional<LifetimeDependenceInfo>
214+
LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd, Type resultType) {
215+
auto *dc = afd->getDeclContext();
216+
auto &ctx = dc->getASTContext();
217+
218+
if (!ctx.LangOpts.hasFeature(Feature::NonescapableTypes)) {
219+
return llvm::None;
220+
}
221+
222+
auto &diags = ctx.Diags;
223+
auto returnTypeRepr = afd->getResultTypeRepr();
224+
auto returnLoc = returnTypeRepr->getLoc();
225+
Type returnTyInContext = afd->mapTypeIntoContext(resultType);
226+
227+
if (returnTyInContext->isEscapable()) {
228+
return llvm::None;
229+
}
230+
if (afd->getAttrs().hasAttribute<UnsafeNonEscapableResultAttr>()) {
231+
return llvm::None;
232+
}
233+
234+
if (afd->hasImplicitSelfDecl()) {
235+
auto ownership = afd->getImplicitSelfDecl()->getValueOwnership();
236+
if (ownership == ValueOwnership::Default) {
237+
diags.diagnose(
238+
returnLoc,
239+
diag::
240+
lifetime_dependence_cannot_infer_wo_ownership_modifier_on_method);
241+
return llvm::None;
242+
}
243+
return LifetimeDependenceInfo::getForParamIndex(afd, /*selfIndex*/ 0,
244+
ownership);
245+
}
246+
247+
LifetimeDependenceInfo lifetimeDependenceInfo;
248+
ParamDecl *candidateParam = nullptr;
249+
unsigned paramIndex = 0;
250+
bool hasParamError = false;
251+
for (auto *param : *afd->getParameters()) {
252+
Type paramTypeInContext =
253+
afd->mapTypeIntoContext(param->getInterfaceType());
254+
255+
if (paramTypeInContext->hasError()) {
256+
hasParamError = true;
257+
continue;
258+
}
259+
if (param->getValueOwnership() == ValueOwnership::Default) {
260+
continue;
261+
}
262+
263+
if (!paramTypeInContext->isEscapable() ||
264+
paramTypeInContext->isNoncopyable()) {
265+
if (candidateParam) {
266+
diags.diagnose(
267+
returnLoc,
268+
diag::lifetime_dependence_cannot_infer_wo_ambiguous_candidate);
269+
return llvm::None;
270+
}
271+
candidateParam = param;
272+
lifetimeDependenceInfo = LifetimeDependenceInfo::getForParamIndex(
273+
afd, paramIndex + 1, param->getValueOwnership());
274+
}
275+
paramIndex++;
276+
}
277+
if (!candidateParam && !hasParamError) {
278+
diags.diagnose(returnLoc,
279+
diag::lifetime_dependence_cannot_infer_no_candidates);
280+
return llvm::None;
281+
}
282+
return lifetimeDependenceInfo;
283+
}
284+
190285
llvm::Optional<LifetimeDependenceInfo>
191286
LifetimeDependenceInfo::get(AbstractFunctionDecl *afd, Type resultType,
192287
bool allowIndex) {
@@ -195,7 +290,7 @@ LifetimeDependenceInfo::get(AbstractFunctionDecl *afd, Type resultType,
195290
return llvm::None;
196291
}
197292
if (!isa<LifetimeDependentReturnTypeRepr>(returnTypeRepr)) {
198-
return llvm::None;
293+
return LifetimeDependenceInfo::infer(afd, resultType);
199294
}
200295
return LifetimeDependenceInfo::fromTypeRepr(afd, resultType, allowIndex);
201296
}

test/Generics/inverse_generics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ func conflict4(_ t: some NeedsCopyable & ~Copyable) {}
298298
// expected-error@-1 {{'some NeedsCopyable & ~Copyable' required to be 'Copyable' but is marked with '~Copyable'}}
299299

300300
protocol Conflict5: ~Copyable {
301-
func whatever() -> AlwaysCopyable<Self> // expected-error {{type 'Self' does not conform to protocol 'Copyable'}}
301+
borrowing func whatever() -> AlwaysCopyable<Self> // expected-error {{type 'Self' does not conform to protocol 'Copyable'}}
302302
}
303303

304304
// expected-warning@+1 {{same-type requirement makes generic parameters 'U' and 'T' equivalent}}

test/SIL/explicit_lifetime_dependence_specifiers.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend %s -emit-sil -enable-builtin-module -enable-experimental-feature NonescapableTypes -disable-experimental-parser-round-trip -enable-experimental-feature NoncopyableGenerics
1+
// RUN: %target-swift-frontend %s -emit-sil -enable-builtin-module -enable-experimental-feature NonescapableTypes -disable-experimental-parser-round-trip -enable-experimental-feature NoncopyableGenerics | %FileCheck %s
22
// REQUIRES: asserts
33

44
import Builtin
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %target-swift-frontend %s -emit-sil -enable-builtin-module -enable-experimental-feature NonescapableTypes -disable-experimental-parser-round-trip -enable-experimental-feature NoncopyableGenerics | %FileCheck %s
2+
// REQUIRES: asserts
3+
4+
import Builtin
5+
6+
struct BufferView : ~Escapable {
7+
let ptr: UnsafeRawBufferPointer
8+
init(_ ptr: UnsafeRawBufferPointer) {
9+
self.ptr = ptr
10+
}
11+
}
12+
13+
struct MutableBufferView : ~Escapable, ~Copyable {
14+
let ptr: UnsafeMutableRawBufferPointer
15+
init(_ ptr: UnsafeMutableRawBufferPointer) {
16+
self.ptr = ptr
17+
}
18+
}
19+
20+
func testBasic() {
21+
let capacity = 4
22+
let a = Array(0..<capacity)
23+
a.withUnsafeBytes {
24+
let view = BufferView($0)
25+
let derivedView = derive(view)
26+
let newView = consumeAndCreate(derivedView)
27+
use(newView)
28+
}
29+
}
30+
31+
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _borrow(1) @owned BufferView {
32+
func derive(_ x: borrowing BufferView) -> BufferView {
33+
return BufferView(x.ptr)
34+
}
35+
36+
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> _inherit(1) @owned BufferView {
37+
func consumeAndCreate(_ x: consuming BufferView) -> BufferView {
38+
return BufferView(x.ptr)
39+
}
40+
41+
func use(_ x: borrowing BufferView) {}
42+
43+
struct Wrapper : ~Escapable {
44+
let view: BufferView
45+
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView1AA10BufferViewVyF : $@convention(method) (@guaranteed Wrapper) -> _borrow(0) @owned BufferView {
46+
borrowing func getView1() -> BufferView {
47+
return view
48+
}
49+
50+
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence7WrapperV8getView2AA10BufferViewVyF : $@convention(method) (@owned Wrapper) -> _inherit(0) @owned BufferView {
51+
consuming func getView2() -> BufferView {
52+
return view
53+
}
54+
}
55+

0 commit comments

Comments
 (0)