Skip to content

Commit 97d9521

Browse files
committed
AST: Record captured generic environments in CaptureInfo
1 parent a61f76f commit 97d9521

File tree

4 files changed

+129
-25
lines changed

4 files changed

+129
-25
lines changed

include/swift/AST/CaptureInfo.h

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class ValueDecl;
4343
class FuncDecl;
4444
class OpaqueValueExpr;
4545
class VarDecl;
46+
class GenericEnvironment;
4647

4748
/// CapturedValue includes both the declaration being captured, along with flags
4849
/// that indicate how it is captured.
@@ -140,19 +141,27 @@ class DynamicSelfType;
140141
/// Stores information about captured variables.
141142
class CaptureInfo {
142143
class CaptureInfoStorage final
143-
: public llvm::TrailingObjects<CaptureInfoStorage, CapturedValue> {
144+
: public llvm::TrailingObjects<CaptureInfoStorage,
145+
CapturedValue,
146+
GenericEnvironment *> {
144147

145148
DynamicSelfType *DynamicSelf;
146149
OpaqueValueExpr *OpaqueValue;
147-
unsigned Count;
150+
unsigned NumCapturedValues;
151+
unsigned NumGenericEnvironments;
152+
148153
public:
149-
explicit CaptureInfoStorage(unsigned count, DynamicSelfType *dynamicSelf,
150-
OpaqueValueExpr *opaqueValue)
151-
: DynamicSelf(dynamicSelf), OpaqueValue(opaqueValue), Count(count) { }
154+
explicit CaptureInfoStorage(DynamicSelfType *dynamicSelf,
155+
OpaqueValueExpr *opaqueValue,
156+
unsigned numCapturedValues,
157+
unsigned numGenericEnvironments)
158+
: DynamicSelf(dynamicSelf), OpaqueValue(opaqueValue),
159+
NumCapturedValues(numCapturedValues),
160+
NumGenericEnvironments(numGenericEnvironments) { }
152161

153-
ArrayRef<CapturedValue> getCaptures() const {
154-
return llvm::ArrayRef(this->getTrailingObjects<CapturedValue>(), Count);
155-
}
162+
ArrayRef<CapturedValue> getCaptures() const;
163+
164+
ArrayRef<GenericEnvironment *> getGenericEnvironments() const;
156165

157166
DynamicSelfType *getDynamicSelfType() const {
158167
return DynamicSelf;
@@ -161,6 +170,10 @@ class CaptureInfo {
161170
OpaqueValueExpr *getOpaqueValue() const {
162171
return OpaqueValue;
163172
}
173+
174+
unsigned numTrailingObjects(OverloadToken<CapturedValue>) const {
175+
return NumCapturedValues;
176+
}
164177
};
165178

166179
enum class Flags : unsigned {
@@ -173,9 +186,11 @@ class CaptureInfo {
173186
public:
174187
/// The default-constructed CaptureInfo is "not yet computed".
175188
CaptureInfo() = default;
176-
CaptureInfo(ASTContext &ctx, ArrayRef<CapturedValue> captures,
189+
CaptureInfo(ASTContext &ctx,
190+
ArrayRef<CapturedValue> captures,
177191
DynamicSelfType *dynamicSelf, OpaqueValueExpr *opaqueValue,
178-
bool genericParamCaptures);
192+
bool genericParamCaptures,
193+
ArrayRef<GenericEnvironment *> genericEnv=ArrayRef<GenericEnvironment*>());
179194

180195
/// A CaptureInfo representing no captures at all.
181196
static CaptureInfo empty();
@@ -190,12 +205,20 @@ class CaptureInfo {
190205
!hasDynamicSelfCapture() && !hasOpaqueValueCapture();
191206
}
192207

208+
/// Returns all captured values and opaque expressions.
193209
ArrayRef<CapturedValue> getCaptures() const {
194210
assert(hasBeenComputed());
195211
return StorageAndFlags.getPointer()->getCaptures();
196212
}
197213

198-
/// \returns true if the function captures any generic type parameters.
214+
/// Returns all captured pack element environments.
215+
ArrayRef<GenericEnvironment *> getGenericEnvironments() const {
216+
assert(hasBeenComputed());
217+
return StorageAndFlags.getPointer()->getGenericEnvironments();
218+
}
219+
220+
/// \returns true if the function captures the primary generic environment
221+
/// from its innermost declaration context.
199222
bool hasGenericParamCaptures() const {
200223
assert(hasBeenComputed());
201224
return StorageAndFlags.getInt().contains(Flags::HasGenericParamCaptures);

lib/AST/CaptureInfo.cpp

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,47 +13,72 @@
1313
#include "swift/AST/CaptureInfo.h"
1414
#include "swift/AST/ASTContext.h"
1515
#include "swift/AST/Decl.h"
16+
#include "swift/AST/GenericEnvironment.h"
1617
#include "llvm/Support/raw_ostream.h"
1718

1819
using namespace swift;
1920

21+
ArrayRef<CapturedValue>
22+
CaptureInfo::CaptureInfoStorage::getCaptures() const {
23+
return llvm::ArrayRef(this->getTrailingObjects<CapturedValue>(), NumCapturedValues);
24+
}
25+
26+
ArrayRef<GenericEnvironment *>
27+
CaptureInfo::CaptureInfoStorage::getGenericEnvironments() const {
28+
return llvm::ArrayRef(this->getTrailingObjects<GenericEnvironment *>(), NumGenericEnvironments);
29+
}
30+
2031
//===----------------------------------------------------------------------===//
2132
// MARK: CaptureInfo
2233
//===----------------------------------------------------------------------===//
2334

2435
CaptureInfo::CaptureInfo(ASTContext &ctx, ArrayRef<CapturedValue> captures,
2536
DynamicSelfType *dynamicSelf,
2637
OpaqueValueExpr *opaqueValue,
27-
bool genericParamCaptures) {
38+
bool genericParamCaptures,
39+
ArrayRef<GenericEnvironment *> genericEnv) {
2840
static_assert(IsTriviallyDestructible<CapturedValue>::value,
2941
"Capture info is alloc'd on the ASTContext and not destroyed");
3042
static_assert(IsTriviallyDestructible<CaptureInfo::CaptureInfoStorage>::value,
3143
"Capture info is alloc'd on the ASTContext and not destroyed");
3244

45+
// This is the only kind of local generic environment we can capture right now.
46+
#ifndef NDEBUG
47+
for (auto *env : genericEnv) {
48+
assert(env->getKind() == GenericEnvironment::Kind::OpenedElement);
49+
}
50+
#endif
51+
3352
OptionSet<Flags> flags;
3453
if (genericParamCaptures)
3554
flags |= Flags::HasGenericParamCaptures;
3655

37-
if (captures.empty() && !dynamicSelf && !opaqueValue) {
56+
if (captures.empty() && genericEnv.empty() && !dynamicSelf && !opaqueValue) {
3857
*this = CaptureInfo::empty();
3958
StorageAndFlags.setInt(flags);
4059
return;
4160
}
4261

4362
size_t storageToAlloc =
44-
CaptureInfoStorage::totalSizeToAlloc<CapturedValue>(captures.size());
63+
CaptureInfoStorage::totalSizeToAlloc<CapturedValue,
64+
GenericEnvironment *>(captures.size(),
65+
genericEnv.size());
4566
void *storageBuf = ctx.Allocate(storageToAlloc, alignof(CaptureInfoStorage));
46-
auto *storage = new (storageBuf) CaptureInfoStorage(captures.size(),
47-
dynamicSelf,
48-
opaqueValue);
67+
auto *storage = new (storageBuf) CaptureInfoStorage(dynamicSelf,
68+
opaqueValue,
69+
captures.size(),
70+
genericEnv.size());
4971
StorageAndFlags.setPointerAndInt(storage, flags);
5072
std::uninitialized_copy(captures.begin(), captures.end(),
5173
storage->getTrailingObjects<CapturedValue>());
74+
std::uninitialized_copy(genericEnv.begin(), genericEnv.end(),
75+
storage->getTrailingObjects<GenericEnvironment *>());
5276
}
5377

5478
CaptureInfo CaptureInfo::empty() {
55-
static const CaptureInfoStorage empty{0, /*dynamicSelf*/nullptr,
56-
/*opaqueValue*/nullptr};
79+
static const CaptureInfoStorage empty{/*dynamicSelf*/nullptr,
80+
/*opaqueValue*/nullptr,
81+
0, 0};
5782
CaptureInfo result;
5883
result.StorageAndFlags.setPointer(&empty);
5984
return result;
@@ -109,6 +134,13 @@ void CaptureInfo::print(raw_ostream &OS) const {
109134
OS << "<noescape>";
110135
},
111136
[&] { OS << ", "; });
137+
138+
interleave(getGenericEnvironments(),
139+
[&](GenericEnvironment *genericEnv) {
140+
OS << " shape_class=";
141+
OS << genericEnv->getOpenedElementShapeClass();
142+
},
143+
[&] { OS << ","; });
112144
OS << ')';
113145
}
114146

lib/SIL/IR/TypeLowering.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4150,6 +4150,9 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
41504150
// that IRGen can pass dynamic 'Self' metadata.
41514151
std::optional<CapturedValue> selfCapture;
41524152

4153+
// Captured pack element environments.
4154+
llvm::SetVector<GenericEnvironment *> genericEnv;
4155+
41534156
bool capturesGenericParams = false;
41544157
DynamicSelfType *capturesDynamicSelf = nullptr;
41554158
OpaqueValueExpr *capturesOpaqueValue = nullptr;
@@ -4176,6 +4179,13 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
41764179
if (captureInfo.hasOpaqueValueCapture())
41774180
capturesOpaqueValue = captureInfo.getOpaqueValue();
41784181

4182+
// Any set of mutually-recursive local functions will capture the same
4183+
// element environments, because we can't "cross" a pack expansion
4184+
// expression.
4185+
for (auto *env : captureInfo.getGenericEnvironments()) {
4186+
genericEnv.insert(env);
4187+
}
4188+
41794189
for (auto capture : captureInfo.getCaptures()) {
41804190
if (!capture.isLocalCapture())
41814191
continue;
@@ -4399,8 +4409,9 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
43994409
}
44004410

44014411
// Cache the uniqued set of transitive captures.
4402-
CaptureInfo info{Context, resultingCaptures, capturesDynamicSelf,
4403-
capturesOpaqueValue, capturesGenericParams};
4412+
CaptureInfo info(Context, resultingCaptures,
4413+
capturesDynamicSelf, capturesOpaqueValue,
4414+
capturesGenericParams, genericEnv.getArrayRef());
44044415
auto inserted = LoweredCaptures.insert({fn, info});
44054416
assert(inserted.second && "already in map?!");
44064417
(void)inserted;

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ class FindCapturedVars : public ASTWalker {
3838
ASTContext &Context;
3939
SmallVector<CapturedValue, 4> Captures;
4040
llvm::SmallDenseMap<ValueDecl*, unsigned, 4> captureEntryNumber;
41+
42+
/// A stack of pack element environments we're currently walking into.
43+
/// A reference to an element archetype defined by one of these is not
44+
/// a capture.
45+
llvm::SetVector<GenericEnvironment *> VisitingEnvironments;
46+
47+
/// A set of pack element environments we've encountered that were not
48+
/// in the above stack; those are the captures.
49+
llvm::SetVector<GenericEnvironment *> CapturedEnvironments;
50+
4151
SourceLoc GenericParamCaptureLoc;
4252
SourceLoc DynamicSelfCaptureLoc;
4353
DynamicSelfType *DynamicSelf = nullptr;
@@ -65,8 +75,9 @@ class FindCapturedVars : public ASTWalker {
6575
dynamicSelfToRecord = DynamicSelf;
6676
}
6777

68-
return CaptureInfo(Context, Captures, dynamicSelfToRecord, OpaqueValue,
69-
HasGenericParamCaptures);
78+
return CaptureInfo(Context, Captures, dynamicSelfToRecord,
79+
OpaqueValue, HasGenericParamCaptures,
80+
CapturedEnvironments.getArrayRef());
7081
}
7182

7283
bool hasGenericParamCaptures() const {
@@ -148,9 +159,17 @@ class FindCapturedVars : public ASTWalker {
148159
// perform it accurately.
149160
if (type->hasArchetype() || type->hasTypeParameter()) {
150161
type.walk(TypeCaptureWalker(ObjC, [&](Type t) {
151-
if ((t->is<ArchetypeType>() ||
162+
// Record references to element archetypes that were bound
163+
// outside the body of the current closure.
164+
if (auto *element = t->getAs<ElementArchetypeType>()) {
165+
auto *env = element->getGenericEnvironment();
166+
if (VisitingEnvironments.count(env) == 0)
167+
CapturedEnvironments.insert(env);
168+
}
169+
170+
if ((t->is<PrimaryArchetypeType>() ||
171+
t->is<PackArchetypeType>() ||
152172
t->is<GenericTypeParamType>()) &&
153-
!t->isOpenedExistential() &&
154173
!HasGenericParamCaptures) {
155174
GenericParamCaptureLoc = loc;
156175
HasGenericParamCaptures = true;
@@ -619,6 +638,25 @@ class FindCapturedVars : public ASTWalker {
619638
}
620639
}
621640

641+
if (auto expansion = dyn_cast<PackExpansionExpr>(E)) {
642+
if (auto *env = expansion->getGenericEnvironment()) {
643+
assert(VisitingEnvironments.count(env) == 0);
644+
VisitingEnvironments.insert(env);
645+
}
646+
}
647+
648+
return Action::Continue(E);
649+
}
650+
651+
PostWalkResult<Expr *> walkToExprPost(Expr *E) override {
652+
if (auto expansion = dyn_cast<PackExpansionExpr>(E)) {
653+
if (auto *env = expansion->getGenericEnvironment()) {
654+
assert(env == VisitingEnvironments.back());
655+
VisitingEnvironments.pop_back();
656+
(void) env;
657+
}
658+
}
659+
622660
return Action::Continue(E);
623661
}
624662
};

0 commit comments

Comments
 (0)