Skip to content

Commit 1e2bda9

Browse files
committed
Extensions to SILBoxType to represent captures.
- Add a `[reflection]` bit to `alloc_box` instructions, to indicate that a box should be allocated with reflection metadata attached. - Add a `@captures_generics` attribute to SILLayouts, to indicate a type layout that captures the generic arguments it's substituted with, meaning it can recreate the generic environment without additional ABI-level arguments, like a generic partial application can.
1 parent f2e785e commit 1e2bda9

18 files changed

+96
-33
lines changed

include/swift/AST/Attr.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ TYPE_ATTR(pseudogeneric)
8484
TYPE_ATTR(yields)
8585
TYPE_ATTR(yield_once)
8686
TYPE_ATTR(yield_many)
87+
TYPE_ATTR(captures_generics)
8788

8889
// SIL metatype attributes.
8990
TYPE_ATTR(thin)

include/swift/AST/SILLayout.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,17 @@ class SILLayout final : public llvm::FoldingSetNode,
8989

9090
enum : unsigned {
9191
IsMutable = 0x1,
92+
CapturesGenericEnvironment = 0x2,
9293
};
9394

94-
static constexpr const unsigned NumFlags = 1;
95+
static constexpr const unsigned NumFlags = 2;
9596

96-
static unsigned getFlagsValue(bool Mutable) {
97+
static unsigned getFlagsValue(bool Mutable, bool CapturesGenerics) {
9798
unsigned flags = 0;
9899
if (Mutable)
99100
flags |= IsMutable;
101+
if (CapturesGenerics)
102+
flags |= CapturesGenericEnvironment;
100103

101104
assert(flags >> NumFlags == 0
102105
&& "more flags than flag bits?!");
@@ -109,15 +112,17 @@ class SILLayout final : public llvm::FoldingSetNode,
109112
unsigned NumFields;
110113

111114
SILLayout(CanGenericSignature Signature,
112-
ArrayRef<SILField> Fields);
115+
ArrayRef<SILField> Fields,
116+
bool CapturesGenericEnvironment);
113117

114118
SILLayout(const SILLayout &) = delete;
115119
SILLayout &operator=(const SILLayout &) = delete;
116120
public:
117121
/// Get or create a layout.
118122
static SILLayout *get(ASTContext &C,
119123
CanGenericSignature Generics,
120-
ArrayRef<SILField> Fields);
124+
ArrayRef<SILField> Fields,
125+
bool CapturesGenericEnvironment);
121126

122127
/// Get the generic signature in which this layout exists.
123128
CanGenericSignature getGenericSignature() const {
@@ -129,6 +134,12 @@ class SILLayout final : public llvm::FoldingSetNode,
129134
return GenericSigAndFlags.getInt() & IsMutable;
130135
}
131136

137+
/// True if the layout captures the generic arguments it is substituted with
138+
/// and can provide generic bindings when passed as a closure argument.
139+
bool capturesGenericEnvironment() const {
140+
return GenericSigAndFlags.getInt() & CapturesGenericEnvironment;
141+
}
142+
132143
/// Get the fields inside the layout.
133144
ArrayRef<SILField> getFields() const {
134145
return llvm::makeArrayRef(getTrailingObjects<SILField>(), NumFields);
@@ -137,11 +148,13 @@ class SILLayout final : public llvm::FoldingSetNode,
137148
/// Produce a profile of this layout, for use in a folding set.
138149
static void Profile(llvm::FoldingSetNodeID &id,
139150
CanGenericSignature Generics,
140-
ArrayRef<SILField> Fields);
151+
ArrayRef<SILField> Fields,
152+
bool CapturesGenericEnvironment);
141153

142154
/// Produce a profile of this locator, for use in a folding set.
143155
void Profile(llvm::FoldingSetNodeID &id) {
144-
Profile(id, getGenericSignature(), getFields());
156+
Profile(id, getGenericSignature(), getFields(),
157+
capturesGenericEnvironment());
145158
}
146159
};
147160

lib/AST/ASTContext.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5374,10 +5374,17 @@ std::string ASTContext::getEntryPointFunctionName() const {
53745374

53755375
SILLayout *SILLayout::get(ASTContext &C,
53765376
CanGenericSignature Generics,
5377-
ArrayRef<SILField> Fields) {
5377+
ArrayRef<SILField> Fields,
5378+
bool CapturesGenericEnvironment) {
5379+
// The "captures generic environment" flag is meaningless if there are
5380+
// no generic arguments to capture.
5381+
if (!Generics || Generics->areAllParamsConcrete()) {
5382+
CapturesGenericEnvironment = false;
5383+
}
5384+
53785385
// Profile the layout parameters.
53795386
llvm::FoldingSetNodeID id;
5380-
Profile(id, Generics, Fields);
5387+
Profile(id, Generics, Fields, CapturesGenericEnvironment);
53815388

53825389
// Return an existing layout if there is one.
53835390
void *insertPos;
@@ -5390,7 +5397,8 @@ SILLayout *SILLayout::get(ASTContext &C,
53905397
void *memory = C.Allocate(totalSizeToAlloc<SILField>(Fields.size()),
53915398
alignof(SILLayout));
53925399

5393-
auto newLayout = ::new (memory) SILLayout(Generics, Fields);
5400+
auto newLayout = ::new (memory) SILLayout(Generics, Fields,
5401+
CapturesGenericEnvironment);
53945402
Layouts.InsertNode(newLayout, insertPos);
53955403
return newLayout;
53965404
}
@@ -5423,7 +5431,8 @@ CanSILBoxType SILBoxType::get(CanType boxedType) {
54235431
auto genericParam = singleGenericParamSignature.getGenericParams()[0];
54245432
auto layout = SILLayout::get(ctx, singleGenericParamSignature,
54255433
SILField(CanType(genericParam),
5426-
/*mutable*/ true));
5434+
/*mutable*/ true),
5435+
/*captures generic env*/ false);
54275436

54285437
auto subMap =
54295438
SubstitutionMap::get(

lib/AST/ASTDemangler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,8 @@ Type ASTBuilder::createSILBoxTypeWithLayout(
706706
silFields.emplace_back(field.getPointer()->getCanonicalType(),
707707
field.getInt());
708708
SILLayout *layout =
709-
SILLayout::get(Ctx, signature.getCanonicalSignature(), silFields);
709+
SILLayout::get(Ctx, signature.getCanonicalSignature(), silFields,
710+
/*captures generics*/ false);
710711

711712
SubstitutionMap substs;
712713
if (signature)

lib/AST/ASTPrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6085,6 +6085,11 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
60856085
}
60866086

60876087
void visitSILBoxType(SILBoxType *T) {
6088+
// Print attributes.
6089+
if (T->getLayout()->capturesGenericEnvironment()) {
6090+
Printer << "@captures_generics ";
6091+
}
6092+
60886093
{
60896094
// A box layout has its own independent generic environment. Don't try
60906095
// to print it with the environment's generic params.

lib/AST/SILLayout.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,10 @@ static void verifyFields(CanGenericSignature Sig, ArrayRef<SILField> Fields) {
7272
#endif
7373

7474
SILLayout::SILLayout(CanGenericSignature Sig,
75-
ArrayRef<SILField> Fields)
76-
: GenericSigAndFlags(Sig, getFlagsValue(anyMutable(Fields))),
75+
ArrayRef<SILField> Fields,
76+
bool CapturesGenericEnvironment)
77+
: GenericSigAndFlags(Sig,
78+
getFlagsValue(anyMutable(Fields), CapturesGenericEnvironment)),
7779
NumFields(Fields.size())
7880
{
7981
#ifndef NDEBUG
@@ -87,8 +89,10 @@ SILLayout::SILLayout(CanGenericSignature Sig,
8789

8890
void SILLayout::Profile(llvm::FoldingSetNodeID &id,
8991
CanGenericSignature Generics,
90-
ArrayRef<SILField> Fields) {
92+
ArrayRef<SILField> Fields,
93+
bool CapturesGenericEnvironment) {
9194
id.AddPointer(Generics.getPointer());
95+
id.AddBoolean(CapturesGenericEnvironment);
9296
for (auto &field : Fields) {
9397
id.AddPointer(field.getLoweredType().getPointer());
9498
id.AddBoolean(field.isMutable());

lib/AST/Type.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5104,7 +5104,9 @@ case TypeKind::Id:
51045104
return *this;
51055105
boxTy = SILBoxType::get(Ptr->getASTContext(),
51065106
SILLayout::get(Ptr->getASTContext(),
5107-
l->getGenericSignature(), newFields),
5107+
l->getGenericSignature(),
5108+
newFields,
5109+
l->capturesGenericEnvironment()),
51085110
boxTy->getSubstitutions());
51095111
return boxTy;
51105112
}

lib/SIL/IR/SILPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,10 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
13551355
void visitAllocBoxInst(AllocBoxInst *ABI) {
13561356
if (ABI->hasDynamicLifetime())
13571357
*this << "[dynamic_lifetime] ";
1358+
1359+
if (ABI->emitReflectionMetadata()) {
1360+
*this << "[reflection] ";
1361+
}
13581362
*this << ABI->getType();
13591363
printDebugVar(ABI->getVarInfo(),
13601364
&ABI->getModule().getASTContext().SourceMgr);

lib/SIL/IR/TypeLowering.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3516,7 +3516,8 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
35163516
// We don't need to capture the generic environment.
35173517
if (!loweredInterfaceType->hasTypeParameter()) {
35183518
auto layout = SILLayout::get(C, nullptr,
3519-
SILField(loweredInterfaceType, isMutable));
3519+
SILField(loweredInterfaceType, isMutable),
3520+
/*captures generics*/ false);
35203521
return SILBoxType::get(C, layout, {});
35213522
}
35223523

@@ -3526,7 +3527,8 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured,
35263527
// only the parts used by the captured variable.
35273528

35283529
auto layout = SILLayout::get(C, signature,
3529-
SILField(loweredInterfaceType, isMutable));
3530+
SILField(loweredInterfaceType, isMutable),
3531+
/*captures generics*/ false);
35303532

35313533
// Instantiate the layout with identity substitutions.
35323534
auto subMap = SubstitutionMap::get(
@@ -3597,7 +3599,8 @@ CanSILBoxType TypeConverter::getBoxTypeForEnumElement(
35973599
if (boxSignature == CanGenericSignature()) {
35983600
auto eltIntfTy = elt->getArgumentInterfaceType();
35993601
auto boxVarTy = getLoweredRValueType(context, eltIntfTy);
3600-
auto layout = SILLayout::get(C, nullptr, SILField(boxVarTy, true));
3602+
auto layout = SILLayout::get(C, nullptr, SILField(boxVarTy, true),
3603+
/*captures generics*/ false);
36013604
return SILBoxType::get(C, layout, {});
36023605
}
36033606

@@ -3609,7 +3612,8 @@ CanSILBoxType TypeConverter::getBoxTypeForEnumElement(
36093612

36103613
auto boxVarTy = getLoweredRValueType(context,
36113614
getAbstractionPattern(elt), eltIntfTy);
3612-
auto layout = SILLayout::get(C, boxSignature, SILField(boxVarTy, true));
3615+
auto layout = SILLayout::get(C, boxSignature, SILField(boxVarTy, true),
3616+
/*captures generics*/ false);
36133617

36143618
// Instantiate the layout with enum's substitution list.
36153619
auto subMap = boundEnum->getContextSubstitutionMap(

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2772,8 +2772,11 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
27722772
switch (Opcode) {
27732773
case SILInstructionKind::AllocBoxInst: {
27742774
bool hasDynamicLifetime = false;
2775+
bool hasReflection = false;
27752776
if (parseSILOptional(hasDynamicLifetime, *this, "dynamic_lifetime"))
27762777
return true;
2778+
if (parseSILOptional(hasReflection, *this, "reflection"))
2779+
return true;
27772780

27782781
SILType Ty;
27792782
if (parseSILType(Ty))

0 commit comments

Comments
 (0)