Skip to content

Commit 5aaa17f

Browse files
authored
Merge pull request #71295 from meg-gupta/lifetimedepserialization
Serialize/deserialize lifetime dependence when present
2 parents bd3c15e + 9afe0d1 commit 5aaa17f

14 files changed

+301
-7
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7797,6 +7797,9 @@ class FuncDecl : public AbstractFunctionDecl {
77977797
SourceRange getSourceRange() const;
77987798

77997799
TypeRepr *getResultTypeRepr() const { return FnRetType.getTypeRepr(); }
7800+
7801+
void setDeserializedResultTypeLoc(TypeLoc ResultTyR);
7802+
78007803
SourceRange getResultTypeSourceRange() const {
78017804
return FnRetType.getSourceRange();
78027805
}

include/swift/AST/LifetimeDependence.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,19 @@ class LifetimeDependenceInfo {
164164
mutateLifetimeParamIndices == nullptr;
165165
}
166166

167+
bool hasInheritLifetimeParamIndices() const {
168+
return inheritLifetimeParamIndices != nullptr;
169+
}
170+
bool hasBorrowLifetimeParamIndices() const {
171+
return borrowLifetimeParamIndices != nullptr;
172+
}
173+
bool hasMutateLifetimeParamIndices() const {
174+
return mutateLifetimeParamIndices != nullptr;
175+
}
176+
167177
std::string getString() const;
168178
void Profile(llvm::FoldingSetNodeID &ID) const;
179+
void getConcatenatedData(SmallVectorImpl<bool> &concatenatedData) const;
169180

170181
static llvm::Optional<LifetimeDependenceInfo>
171182
get(AbstractFunctionDecl *decl, Type resultType, bool allowIndex = false);

lib/AST/Decl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9976,6 +9976,10 @@ void FuncDecl::setResultInterfaceType(Type type) {
99769976
std::move(type));
99779977
}
99789978

9979+
void FuncDecl::setDeserializedResultTypeLoc(TypeLoc ResultTyR) {
9980+
FnRetType = ResultTyR;
9981+
}
9982+
99799983
FuncDecl *FuncDecl::createImpl(ASTContext &Context,
99809984
SourceLoc StaticLoc,
99819985
StaticSpellingKind StaticSpelling,

lib/Sema/LifetimeDependence.cpp

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,33 @@ LifetimeDependenceInfo LifetimeDependenceInfo::getForParamIndex(
8585
/*mutateLifetimeParamIndices*/ indexSubset};
8686
}
8787

88+
void LifetimeDependenceInfo::getConcatenatedData(
89+
SmallVectorImpl<bool> &concatenatedData) const {
90+
auto pushData = [&](IndexSubset *paramIndices) {
91+
if (paramIndices == nullptr) {
92+
return;
93+
}
94+
assert(!paramIndices->isEmpty());
95+
96+
for (unsigned i = 0; i < paramIndices->getCapacity(); i++) {
97+
if (paramIndices->contains(i)) {
98+
concatenatedData.push_back(true);
99+
continue;
100+
}
101+
concatenatedData.push_back(false);
102+
}
103+
};
104+
if (hasInheritLifetimeParamIndices()) {
105+
pushData(inheritLifetimeParamIndices);
106+
}
107+
if (hasBorrowLifetimeParamIndices()) {
108+
pushData(borrowLifetimeParamIndices);
109+
}
110+
if (hasMutateLifetimeParamIndices()) {
111+
pushData(mutateLifetimeParamIndices);
112+
}
113+
}
114+
88115
llvm::Optional<LifetimeDependenceInfo>
89116
LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
90117
bool allowIndex) {
@@ -181,9 +208,19 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
181208
paramIndex);
182209
return llvm::None;
183210
}
211+
if (paramIndex == 0) {
212+
if (!afd->hasImplicitSelfDecl()) {
213+
diags.diagnose(specifier.getLoc(),
214+
diag::lifetime_dependence_invalid_self);
215+
return llvm::None;
216+
}
217+
}
218+
auto ownership =
219+
paramIndex == 0
220+
? afd->getImplicitSelfDecl()->getValueOwnership()
221+
: afd->getParameters()->get(paramIndex - 1)->getValueOwnership();
184222
if (updateLifetimeDependenceInfo(
185-
specifier, /*paramIndexToSet*/ specifier.getIndex() + 1,
186-
afd->getParameters()->get(paramIndex)->getValueOwnership())) {
223+
specifier, /*paramIndexToSet*/ specifier.getIndex(), ownership)) {
187224
return llvm::None;
188225
}
189226
break;
@@ -205,9 +242,15 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd, Type resultType,
205242
}
206243

207244
return LifetimeDependenceInfo(
208-
IndexSubset::get(ctx, inheritLifetimeParamIndices),
209-
IndexSubset::get(ctx, borrowLifetimeParamIndices),
210-
IndexSubset::get(ctx, mutateLifetimeParamIndices));
245+
inheritLifetimeParamIndices.any()
246+
? IndexSubset::get(ctx, inheritLifetimeParamIndices)
247+
: nullptr,
248+
borrowLifetimeParamIndices.any()
249+
? IndexSubset::get(ctx, borrowLifetimeParamIndices)
250+
: nullptr,
251+
mutateLifetimeParamIndices.any()
252+
? IndexSubset::get(ctx, mutateLifetimeParamIndices)
253+
: nullptr);
211254
}
212255

213256
llvm::Optional<LifetimeDependenceInfo>

lib/Serialization/DeclTypeRecordNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ OTHER(ERROR_FLAG, 155)
212212
TRAILING_INFO(CONDITIONAL_SUBSTITUTION)
213213
TRAILING_INFO(CONDITIONAL_SUBSTITUTION_COND)
214214

215+
OTHER(LIFETIME_DEPENDENCE, 158)
216+
215217
#ifndef DECL_ATTR
216218
#define DECL_ATTR(NAME, CLASS, OPTIONS, CODE) RECORD_VAL(CLASS##_DECL_ATTR, 180+CODE)
217219
#endif

lib/Serialization/Deserialization.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4105,6 +4105,13 @@ class DeclDeserializer {
41054105

41064106
ParameterList *paramList = MF.readParameterList();
41074107
fn->setParameters(paramList);
4108+
SmallVector<LifetimeDependenceSpecifier> specifierList;
4109+
if (MF.maybeReadLifetimeDependence(specifierList, paramList->size())) {
4110+
auto typeRepr = new (ctx) FixedTypeRepr(resultType, SourceLoc());
4111+
auto lifetimeTypeRepr =
4112+
LifetimeDependentReturnTypeRepr::create(ctx, typeRepr, specifierList);
4113+
fn->setDeserializedResultTypeLoc(TypeLoc(lifetimeTypeRepr, resultType));
4114+
}
41084115

41094116
if (auto errorConvention = MF.maybeReadForeignErrorConvention())
41104117
fn->setForeignErrorConvention(*errorConvention);
@@ -8548,3 +8555,58 @@ ModuleFile::maybeReadForeignAsyncConvention() {
85488555
completionHandlerErrorFlagParamIndex,
85498556
errorFlagPolarity);
85508557
}
8558+
8559+
bool ModuleFile::maybeReadLifetimeDependence(
8560+
SmallVectorImpl<LifetimeDependenceSpecifier> &specifierList,
8561+
unsigned numParams) {
8562+
using namespace decls_block;
8563+
SmallVector<uint64_t, 8> scratch;
8564+
8565+
BCOffsetRAII restoreOffset(DeclTypeCursor);
8566+
8567+
llvm::BitstreamEntry next =
8568+
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
8569+
if (next.Kind != llvm::BitstreamEntry::Record)
8570+
return false;
8571+
8572+
unsigned recKind =
8573+
fatalIfUnexpected(DeclTypeCursor.readRecord(next.ID, scratch));
8574+
switch (recKind) {
8575+
case LIFETIME_DEPENDENCE:
8576+
restoreOffset.reset();
8577+
break;
8578+
8579+
default:
8580+
return false;
8581+
}
8582+
8583+
bool hasInheritLifetimeParamIndices, hasBorrowLifetimeParamIndices,
8584+
hasMutateLifetimeParamIndices;
8585+
ArrayRef<uint64_t> lifetimeDependenceData;
8586+
LifetimeDependenceLayout::readRecord(
8587+
scratch, hasInheritLifetimeParamIndices, hasBorrowLifetimeParamIndices,
8588+
hasMutateLifetimeParamIndices, lifetimeDependenceData);
8589+
8590+
unsigned startIndex = 0;
8591+
auto pushData = [&](LifetimeDependenceKind kind) {
8592+
for (unsigned i = 0; i < numParams + 1; i++) {
8593+
if (lifetimeDependenceData[startIndex + i]) {
8594+
specifierList.push_back(
8595+
LifetimeDependenceSpecifier::getOrderedLifetimeDependenceSpecifier(
8596+
SourceLoc(), kind, i));
8597+
}
8598+
}
8599+
startIndex += numParams + 1;
8600+
};
8601+
8602+
if (hasInheritLifetimeParamIndices) {
8603+
pushData(LifetimeDependenceKind::Consume);
8604+
}
8605+
if (hasBorrowLifetimeParamIndices) {
8606+
pushData(LifetimeDependenceKind::Borrow);
8607+
}
8608+
if (hasMutateLifetimeParamIndices) {
8609+
pushData(LifetimeDependenceKind::Mutate);
8610+
}
8611+
return true;
8612+
}

lib/Serialization/ModuleFile.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,10 @@ class ModuleFile
10601060
/// Reads a foreign async convention from \c DeclTypeCursor, if present.
10611061
llvm::Optional<ForeignAsyncConvention> maybeReadForeignAsyncConvention();
10621062

1063+
bool maybeReadLifetimeDependence(
1064+
SmallVectorImpl<LifetimeDependenceSpecifier> &specifierList,
1065+
unsigned numParams);
1066+
10631067
/// Reads inlinable body text from \c DeclTypeCursor, if present.
10641068
llvm::Optional<StringRef> maybeReadInlinableBodyText();
10651069

lib/Serialization/ModuleFormat.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 846; // always trigger mismatch for NoncopyableGenerics
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 847; // add LifetimeDependence
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -2174,6 +2174,14 @@ namespace decls_block {
21742174
BCFixed<1> // completion handler error flag polarity
21752175
>;
21762176

2177+
using LifetimeDependenceLayout =
2178+
BCRecordLayout<LIFETIME_DEPENDENCE,
2179+
BCFixed<1>, // hasInheritLifetimeParamIndices
2180+
BCFixed<1>, // hasBorrowLifetimeParamIndices
2181+
BCFixed<1>, // hasMutateLifetimeParamIndices
2182+
BCArray<BCFixed<1>> // concatenated param indices
2183+
>;
2184+
21772185
using AbstractClosureExprLayout = BCRecordLayout<
21782186
ABSTRACT_CLOSURE_EXPR_CONTEXT,
21792187
TypeIDField, // type

lib/Serialization/Serialization.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3509,6 +3509,20 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
35093509
fac.completionHandlerFlagIsErrorOnZero());
35103510
}
35113511

3512+
void
3513+
writeLifetimeDependenceInfo(LifetimeDependenceInfo lifetimeDependenceInfo) {
3514+
using namespace decls_block;
3515+
SmallVector<bool> paramIndices;
3516+
lifetimeDependenceInfo.getConcatenatedData(paramIndices);
3517+
3518+
auto abbrCode = S.DeclTypeAbbrCodes[LifetimeDependenceLayout::Code];
3519+
LifetimeDependenceLayout::emitRecord(
3520+
S.Out, S.ScratchRecord, abbrCode,
3521+
lifetimeDependenceInfo.hasInheritLifetimeParamIndices(),
3522+
lifetimeDependenceInfo.hasBorrowLifetimeParamIndices(),
3523+
lifetimeDependenceInfo.hasMutateLifetimeParamIndices(), paramIndices);
3524+
}
3525+
35123526
void writeGenericParams(const GenericParamList *genericParams) {
35133527
using namespace decls_block;
35143528

@@ -4482,6 +4496,12 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
44824496
// Write the body parameters.
44834497
writeParameterList(fn->getParameters());
44844498

4499+
auto fnType = ty->getAs<FunctionType>();
4500+
if (fnType && fnType->hasLifetimeDependenceInfo()) {
4501+
assert(!fnType->getLifetimeDependenceInfo().empty());
4502+
writeLifetimeDependenceInfo(fnType->getLifetimeDependenceInfo());
4503+
}
4504+
44854505
if (auto errorConvention = fn->getForeignErrorConvention())
44864506
writeForeignErrorConvention(*errorConvention);
44874507
if (auto asyncConvention = fn->getForeignAsyncConvention())
@@ -5949,6 +5969,7 @@ void Serializer::writeAllDeclsAndTypes() {
59495969

59505970
registerDeclTypeAbbr<ForeignErrorConventionLayout>();
59515971
registerDeclTypeAbbr<ForeignAsyncConventionLayout>();
5972+
registerDeclTypeAbbr<LifetimeDependenceLayout>();
59525973
registerDeclTypeAbbr<AbstractClosureExprLayout>();
59535974
registerDeclTypeAbbr<PatternBindingInitializerLayout>();
59545975
registerDeclTypeAbbr<DefaultArgumentInitializerLayout>();

test/Parse/explicit_lifetime_dependence_specifiers.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ func invalidSpecifier3(_ x: borrowing BufferView) -> _borrow(*) BufferView { //
9393
return BufferView(x.ptr)
9494
}
9595

96-
func invalidSpecifier4(_ x: borrowing BufferView) -> _borrow(0) BufferView {
96+
// TODO: Diagnose using param indices on func decls in sema
97+
func invalidSpecifier4(_ x: borrowing BufferView) -> _borrow(0) BufferView { // expected-error{{invalid lifetime dependence specifier, self is valid in non-static methods only}}
9798
return BufferView(x.ptr)
9899
}
99100

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
public struct BufferView : ~Escapable {
2+
let ptr: UnsafeRawBufferPointer
3+
@_unsafeNonescapableResult
4+
public init(_ ptr: UnsafeRawBufferPointer) {
5+
self.ptr = ptr
6+
}
7+
}
8+
9+
public struct MutableBufferView : ~Escapable, ~Copyable {
10+
let ptr: UnsafeMutableRawBufferPointer
11+
@_unsafeNonescapableResult
12+
public init(_ ptr: UnsafeMutableRawBufferPointer) {
13+
self.ptr = ptr
14+
}
15+
}
16+
17+
public func derive(_ x: borrowing BufferView) -> _borrow(x) BufferView {
18+
return BufferView(x.ptr)
19+
}
20+
21+
public func use(_ x: borrowing BufferView) {}
22+
23+
public func borrowAndCreate(_ view: borrowing BufferView) -> _borrow(view) BufferView {
24+
return BufferView(view.ptr)
25+
}
26+
27+
public func consumeAndCreate(_ view: consuming BufferView) -> _consume(view) BufferView {
28+
return BufferView(view.ptr)
29+
}
30+
31+
public func deriveThisOrThat(_ this: borrowing BufferView, _ that: borrowing BufferView) -> _borrow(this, that) BufferView {
32+
if (Int.random(in: 1..<100) == 0) {
33+
return BufferView(this.ptr)
34+
}
35+
return BufferView(that.ptr)
36+
}
37+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
public struct BufferView : ~Escapable {
2+
let ptr: UnsafeRawBufferPointer
3+
@_unsafeNonescapableResult
4+
public init(_ ptr: UnsafeRawBufferPointer) {
5+
self.ptr = ptr
6+
}
7+
}
8+
9+
public struct MutableBufferView : ~Escapable, ~Copyable {
10+
let ptr: UnsafeMutableRawBufferPointer
11+
@_unsafeNonescapableResult
12+
public init(_ ptr: UnsafeMutableRawBufferPointer) {
13+
self.ptr = ptr
14+
}
15+
}
16+
17+
public func derive(_ x: borrowing BufferView) -> BufferView {
18+
return BufferView(x.ptr)
19+
}
20+
21+
public func use(_ x: borrowing BufferView) {}
22+
23+
public func borrowAndCreate(_ view: borrowing BufferView) -> BufferView {
24+
return BufferView(view.ptr)
25+
}
26+
27+
public func consumeAndCreate(_ view: consuming BufferView) -> BufferView {
28+
return BufferView(view.ptr)
29+
}
30+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/def_explicit_lifetime_dependence.swift \
3+
// RUN: -enable-experimental-feature NonescapableTypes \
4+
// RUN: -disable-experimental-parser-round-trip \
5+
// RUN: -enable-experimental-feature NoncopyableGenerics
6+
7+
// RUN: llvm-bcanalyzer %t/def_explicit_lifetime_dependence.swiftmodule
8+
9+
// RUN: %target-swift-frontend -module-name lifetime-dependence -emit-silgen -I %t %s \
10+
// RUN: -enable-experimental-feature NonescapableTypes \
11+
// RUN: -disable-experimental-parser-round-trip \
12+
// RUN: -enable-experimental-feature NoncopyableGenerics | %FileCheck %s
13+
14+
// REQUIRES: noncopyable_generics
15+
16+
import def_explicit_lifetime_dependence
17+
18+
func testBasic() {
19+
let capacity = 4
20+
let a = Array(0..<capacity)
21+
a.withUnsafeBytes {
22+
let view = BufferView($0)
23+
let derivedView = derive(view)
24+
let consumedView = consumeAndCreate(derivedView)
25+
let borrowedView = borrowAndCreate(consumedView)
26+
let mysteryView = deriveThisOrThat(borrowedView, consumedView)
27+
use(mysteryView)
28+
}
29+
}
30+
31+
// CHECK: sil @$s32def_explicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _borrow(1) @owned BufferView
32+
// CHECK: sil @$s32def_explicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> _inherit(1) @owned BufferView
33+
// CHECK: sil @$s32def_explicit_lifetime_dependence15borrowAndCreateyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _borrow(1) @owned BufferView
34+
// CHECK: sil @$s32def_explicit_lifetime_dependence16deriveThisOrThatyAA10BufferViewVAD_ADtF : $@convention(thin) (@guaranteed BufferView, @guaranteed BufferView) -> _borrow(1, 2) @owned BufferView

0 commit comments

Comments
 (0)