Skip to content

Commit e920ddc

Browse files
authored
Merge pull request #3235 from slavapestov/fix-capturing-dynamic-self
Fix capturing dynamic Self
2 parents 8456dac + 2a59ad7 commit e920ddc

19 files changed

+985
-615
lines changed

include/swift/AST/CaptureInfo.h

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,20 @@ class CapturedValue {
5555

5656
CapturedValue(ValueDecl *D, unsigned Flags) : Value(D, Flags) {}
5757

58+
static CapturedValue getDynamicSelfMetadata() {
59+
return CapturedValue(nullptr, 0);
60+
}
61+
5862
bool isDirect() const { return Value.getInt() & IsDirect; }
5963
bool isNoEscape() const { return Value.getInt() & IsNoEscape; }
6064

61-
ValueDecl *getDecl() const { return Value.getPointer(); }
65+
bool isDynamicSelfMetadata() const { return !Value.getPointer(); }
66+
67+
ValueDecl *getDecl() const {
68+
assert(Value.getPointer() && "dynamic Self metadata capture does not "
69+
"have a value");
70+
return Value.getPointer();
71+
}
6272

6373
unsigned getFlags() const { return Value.getInt(); }
6474

@@ -106,19 +116,26 @@ template <> struct DenseMapInfo<swift::CapturedValue> {
106116

107117
namespace swift {
108118

119+
class DynamicSelfType;
120+
109121
/// \brief Stores information about captured variables.
110122
class CaptureInfo {
111123
const CapturedValue *Captures;
124+
DynamicSelfType *DynamicSelf;
112125
unsigned Count = 0;
113126
bool GenericParamCaptures : 1;
114127
bool Computed : 1;
115128

116129
public:
117130
CaptureInfo()
118-
: Captures(nullptr), Count(0), GenericParamCaptures(0), Computed(0) { }
131+
: Captures(nullptr), DynamicSelf(nullptr), Count(0),
132+
GenericParamCaptures(0), Computed(0) { }
119133

120134
bool hasBeenComputed() { return Computed; }
121-
bool empty() { return Count == 0; }
135+
136+
bool isTrivial() {
137+
return Count == 0 && !GenericParamCaptures && !DynamicSelf;
138+
}
122139

123140
ArrayRef<CapturedValue> getCaptures() const {
124141
return llvm::makeArrayRef(Captures, Count);
@@ -139,14 +156,28 @@ class CaptureInfo {
139156
bool hasLocalCaptures() const;
140157

141158
/// \returns true if the function captures any generic type parameters.
142-
bool hasGenericParamCaptures() {
159+
bool hasGenericParamCaptures() const {
143160
return GenericParamCaptures;
144161
}
145162

146163
void setGenericParamCaptures(bool genericParamCaptures) {
147164
GenericParamCaptures = genericParamCaptures;
148165
}
149166

167+
/// \returns true if the function captures the dynamic Self type.
168+
bool hasDynamicSelfCapture() const {
169+
return DynamicSelf != nullptr;
170+
}
171+
172+
/// \returns the captured dynamic Self type, if any.
173+
DynamicSelfType *getDynamicSelfType() const {
174+
return DynamicSelf;
175+
}
176+
177+
void setDynamicSelfType(DynamicSelfType *dynamicSelf) {
178+
DynamicSelf = dynamicSelf;
179+
}
180+
150181
void dump() const;
151182
void print(raw_ostream &OS) const;
152183
};

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,8 @@ ERROR(c_function_pointer_from_generic_function,none,
802802
ERROR(c_function_pointer_from_function_with_context,none,
803803
"a C function pointer cannot be formed from a "
804804
"%select{local function|closure}0 that captures "
805-
"%select{context|generic parameters}1", (bool, bool))
805+
"%select{context|generic parameters|dynamic Self type}1",
806+
(bool, unsigned))
806807
NOTE(c_function_pointer_captures_here,none,
807808
"%0 captured here", (Identifier))
808809

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ namespace {
737737

738738
void printCommonAFD(AbstractFunctionDecl *D, const char *Type) {
739739
printCommon(D, Type, FuncColor);
740-
if (!D->getCaptureInfo().empty()) {
740+
if (!D->getCaptureInfo().isTrivial()) {
741741
OS << " ";
742742
D->getCaptureInfo().print(OS);
743743
}
@@ -2014,7 +2014,7 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
20142014
llvm::raw_ostream &printClosure(AbstractClosureExpr *E, char const *name) {
20152015
printCommon(E, name);
20162016
OS << " discriminator=" << E->getDiscriminator();
2017-
if (!E->getCaptureInfo().empty()) {
2017+
if (!E->getCaptureInfo().isTrivial()) {
20182018
OS << " ";
20192019
E->getCaptureInfo().print(OS);
20202020
}

lib/AST/CaptureInfo.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ void CaptureInfo::dump() const {
4646

4747
void CaptureInfo::print(raw_ostream &OS) const {
4848
OS << "captures=(";
49+
50+
if (hasGenericParamCaptures())
51+
OS << "<generic> ";
52+
if (hasDynamicSelfCapture())
53+
OS << "<dynamic_self> ";
54+
4955
bool isFirst = true;
5056

5157
for (auto capture : getCaptures()) {

lib/SIL/SILArgument.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,6 @@ using namespace swift;
2626
SILArgument::SILArgument(SILBasicBlock *ParentBB, SILType Ty,
2727
const ValueDecl *D)
2828
: ValueBase(ValueKind::SILArgument, Ty), ParentBB(ParentBB), Decl(D) {
29-
// Function arguments need to have a decl.
30-
assert(
31-
!ParentBB->getParent()->isBare() &&
32-
ParentBB->getParent()->size() == 1
33-
? D != nullptr
34-
: true);
3529
ParentBB->insertArgument(ParentBB->bbarg_end(), this);
3630
}
3731

lib/SIL/SILFunctionType.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,18 @@ static CanSILFunctionType getSILFunctionType(SILModule &M,
735735
auto loweredCaptures = Types.getLoweredLocalCaptures(*function);
736736

737737
for (auto capture : loweredCaptures.getCaptures()) {
738+
if (capture.isDynamicSelfMetadata()) {
739+
ParameterConvention convention = ParameterConvention::Direct_Unowned;
740+
auto selfMetatype = MetatypeType::get(
741+
loweredCaptures.getDynamicSelfType()->getSelfType(),
742+
MetatypeRepresentation::Thick)
743+
->getCanonicalType();
744+
SILParameterInfo param(selfMetatype, convention);
745+
inputs.push_back(param);
746+
747+
continue;
748+
}
749+
738750
auto *VD = capture.getDecl();
739751
auto type = VD->getType()->getCanonicalType();
740752

lib/SIL/SILVerifier.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,23 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
13261326
if (auto dynamicSelf = dyn_cast<DynamicSelfType>(formalType))
13271327
formalType = CanType(dynamicSelf->getSelfType());
13281328

1329+
// Optional of dynamic self has the same lowering as its contained type.
1330+
OptionalTypeKind loweredOptionalKind;
1331+
OptionalTypeKind formalOptionalKind;
1332+
1333+
CanType loweredObjectType = loweredType.getSwiftRValueType()
1334+
.getAnyOptionalObjectType(loweredOptionalKind);
1335+
CanType formalObjectType = formalType
1336+
.getAnyOptionalObjectType(formalOptionalKind);
1337+
1338+
if (loweredOptionalKind != OTK_None) {
1339+
if (auto dynamicSelf = dyn_cast<DynamicSelfType>(formalObjectType)) {
1340+
formalObjectType = dynamicSelf->getSelfType()->getCanonicalType();
1341+
}
1342+
return ((loweredOptionalKind == formalOptionalKind) &&
1343+
loweredObjectType == formalObjectType);
1344+
}
1345+
13291346
// Metatypes preserve their instance type through lowering.
13301347
if (auto loweredMT = loweredType.getAs<MetatypeType>()) {
13311348
if (auto formalMT = dyn_cast<MetatypeType>(formalType)) {

lib/SIL/TypeLowering.cpp

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,13 +2074,14 @@ getAnyFunctionRefFromCapture(CapturedValue capture) {
20742074
CaptureInfo
20752075
TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
20762076
// First, bail out if there are no local captures at all.
2077-
if (!fn.getCaptureInfo().hasLocalCaptures()) {
2077+
if (!fn.getCaptureInfo().hasLocalCaptures() &&
2078+
!fn.getCaptureInfo().hasDynamicSelfCapture()) {
20782079
CaptureInfo info;
20792080
info.setGenericParamCaptures(
20802081
fn.getCaptureInfo().hasGenericParamCaptures());
20812082
return info;
20822083
};
2083-
2084+
20842085
// See if we've cached the lowered capture list for this function.
20852086
auto found = LoweredCaptures.find(fn);
20862087
if (found != LoweredCaptures.end())
@@ -2089,7 +2090,13 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
20892090
// Recursively collect transitive captures from captured local functions.
20902091
llvm::DenseSet<AnyFunctionRef> visitedFunctions;
20912092
llvm::SetVector<CapturedValue> captures;
2093+
2094+
// If there is a capture of 'self' with dynamic 'Self' type, it goes last so
2095+
// that IRGen can pass dynamic 'Self' metadata.
2096+
Optional<CapturedValue> selfCapture;
2097+
20922098
bool capturesGenericParams = false;
2099+
DynamicSelfType *capturesDynamicSelf = nullptr;
20932100

20942101
std::function<void (AnyFunctionRef)> collectFunctionCaptures
20952102
= [&](AnyFunctionRef curFn) {
@@ -2098,6 +2105,8 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
20982105

20992106
if (curFn.getCaptureInfo().hasGenericParamCaptures())
21002107
capturesGenericParams = true;
2108+
if (curFn.getCaptureInfo().hasDynamicSelfCapture())
2109+
capturesDynamicSelf = curFn.getCaptureInfo().getDynamicSelfType();
21012110

21022111
SmallVector<CapturedValue, 4> localCaptures;
21032112
curFn.getCaptureInfo().getLocalCaptures(localCaptures);
@@ -2108,7 +2117,7 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
21082117
collectFunctionCaptures(*capturedFn);
21092118
continue;
21102119
}
2111-
2120+
21122121
// If the capture is of a computed property, grab the transitive captures
21132122
// of its accessors.
21142123
if (auto capturedVar = dyn_cast<VarDecl>(capture.getDecl())) {
@@ -2127,21 +2136,38 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
21272136
// Directly capture storage if we're supposed to.
21282137
if (capture.isDirect())
21292138
goto capture_value;
2130-
2139+
21312140
// Otherwise, transitively capture the accessors.
21322141
SWIFT_FALLTHROUGH;
2133-
2142+
21342143
case VarDecl::Computed: {
21352144
collectFunctionCaptures(capturedVar->getGetter());
21362145
if (auto setter = capturedVar->getSetter())
21372146
collectFunctionCaptures(setter);
21382147
continue;
21392148
}
21402149

2141-
case VarDecl::Stored:
2150+
case VarDecl::Stored: {
21422151
// We can always capture the storage in these cases.
2152+
Type captureType;
2153+
if (auto *selfType = capturedVar->getType()->getAs<DynamicSelfType>()) {
2154+
captureType = selfType->getSelfType();
2155+
if (auto *metatypeType = captureType->getAs<MetatypeType>())
2156+
captureType = metatypeType->getInstanceType();
2157+
2158+
// We're capturing a 'self' value with dynamic 'Self' type;
2159+
// handle it specially.
2160+
if (!selfCapture &&
2161+
captureType->getClassOrBoundGenericClass()) {
2162+
selfCapture = capture;
2163+
continue;
2164+
}
2165+
}
2166+
2167+
// Otherwise just fall through.
21432168
goto capture_value;
21442169
}
2170+
}
21452171
}
21462172

21472173
capture_value:
@@ -2150,12 +2176,23 @@ TypeConverter::getLoweredLocalCaptures(AnyFunctionRef fn) {
21502176
}
21512177
};
21522178
collectFunctionCaptures(fn);
2153-
2179+
2180+
// If we captured the dynamic 'Self' type and we have a 'self' value also,
2181+
// add it as the final capture. Otherwise, add a fake hidden capture for
2182+
// the dynamic 'Self' metatype.
2183+
if (selfCapture.hasValue()) {
2184+
captures.insert(*selfCapture);
2185+
} else if (capturesDynamicSelf) {
2186+
selfCapture = CapturedValue::getDynamicSelfMetadata();
2187+
captures.insert(*selfCapture);
2188+
}
2189+
21542190
// Cache the uniqued set of transitive captures.
21552191
auto inserted = LoweredCaptures.insert({fn, CaptureInfo()});
21562192
assert(inserted.second && "already in map?!");
21572193
auto &cachedCaptures = inserted.first->second;
21582194
cachedCaptures.setGenericParamCaptures(capturesGenericParams);
2195+
cachedCaptures.setDynamicSelfType(capturesDynamicSelf);
21592196
cachedCaptures.setCaptures(Context.AllocateCopy(captures));
21602197

21612198
return cachedCaptures;

lib/SILGen/SILGenFunction.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,28 @@ void SILGenFunction::emitCaptures(SILLocation loc,
232232
canGuarantee = false;
233233

234234
for (auto capture : captureInfo.getCaptures()) {
235+
if (capture.isDynamicSelfMetadata()) {
236+
// The parameter type is the static Self type, but the value we
237+
// want to pass is the dynamic Self type, so upcast it.
238+
auto dynamicSelfMetatype = MetatypeType::get(
239+
captureInfo.getDynamicSelfType(),
240+
MetatypeRepresentation::Thick)
241+
->getCanonicalType();
242+
auto staticSelfMetatype = MetatypeType::get(
243+
captureInfo.getDynamicSelfType()->getSelfType(),
244+
MetatypeRepresentation::Thick)
245+
->getCanonicalType();
246+
SILType dynamicSILType = SILType::getPrimitiveObjectType(
247+
dynamicSelfMetatype);
248+
SILType staticSILType = SILType::getPrimitiveObjectType(
249+
staticSelfMetatype);
250+
251+
SILValue value = B.createMetatype(loc, dynamicSILType);
252+
value = B.createUpcast(loc, value, staticSILType);
253+
capturedArgs.push_back(ManagedValue::forUnmanaged(value));
254+
continue;
255+
}
256+
235257
auto *vd = capture.getDecl();
236258

237259
switch (SGM.Types.getDeclCaptureKind(capture)) {

lib/SILGen/SILGenProlog.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ void SILGenFunction::bindParametersForForwarding(const ParameterList *params,
357357

358358
static void emitCaptureArguments(SILGenFunction &gen, CapturedValue capture,
359359
unsigned ArgNo) {
360+
360361
auto *VD = capture.getDecl();
361362
auto type = VD->getType();
362363
SILLocation Loc(VD);
@@ -428,8 +429,21 @@ void SILGenFunction::emitProlog(AnyFunctionRef TheClosure,
428429
// Emit the capture argument variables. These are placed last because they
429430
// become the first curry level of the SIL function.
430431
auto captureInfo = SGM.Types.getLoweredLocalCaptures(TheClosure);
431-
for (auto capture : captureInfo.getCaptures())
432+
for (auto capture : captureInfo.getCaptures()) {
433+
if (capture.isDynamicSelfMetadata()) {
434+
auto selfMetatype = MetatypeType::get(
435+
captureInfo.getDynamicSelfType()->getSelfType(),
436+
MetatypeRepresentation::Thick)
437+
->getCanonicalType();
438+
SILType ty = SILType::getPrimitiveObjectType(selfMetatype);
439+
SILValue val = new (SGM.M) SILArgument(F.begin(), ty);
440+
(void) val;
441+
442+
return;
443+
}
444+
432445
emitCaptureArguments(*this, capture, ++ArgNo);
446+
}
433447
}
434448

435449
static void emitIndirectResultParameters(SILGenFunction &gen, Type resultType,

0 commit comments

Comments
 (0)