Skip to content

Commit e342a38

Browse files
committed
Sema: Convert TypeChecker::computeCaptures() into two requests
We now compute captures of functions and default arguments lazily, instead of as a side effect of primary file checking. Captures of closures are computed as part of the enclosing context, not lazily, because the type checking of a single closure body is not lazy. This fixes a specific issue with the `-experimental-skip-*` flags, where functions declared after a top-level `guard` statement are considered to have local captures, but nothing was forcing these captures to be computed. Fixes rdar://problem/125981663.
1 parent 55ff73f commit e342a38

17 files changed

+229
-78
lines changed

include/swift/AST/Decl.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6814,9 +6814,14 @@ class ParamDecl : public VarDecl {
68146814

68156815
void setDefaultArgumentInitContext(Initializer *initContext);
68166816

6817-
CaptureInfo getDefaultArgumentCaptureInfo() const {
6817+
CaptureInfo getDefaultArgumentCaptureInfo() const;
6818+
6819+
std::optional<CaptureInfo> getCachedDefaultArgumentCaptureInfo() const {
68186820
assert(DefaultValueAndFlags.getPointer());
6819-
return DefaultValueAndFlags.getPointer()->Captures;
6821+
const auto &captures = DefaultValueAndFlags.getPointer()->Captures;
6822+
if (!captures.hasBeenComputed())
6823+
return std::nullopt;
6824+
return captures;
68206825
}
68216826

68226827
void setDefaultArgumentCaptureInfo(CaptureInfo captures);
@@ -7754,7 +7759,13 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
77547759
/// Retrieve the source range of the function declaration name + patterns.
77557760
SourceRange getSignatureSourceRange() const;
77567761

7757-
CaptureInfo getCaptureInfo() const { return Captures; }
7762+
CaptureInfo getCaptureInfo() const;
7763+
7764+
std::optional<CaptureInfo> getCachedCaptureInfo() const {
7765+
if (!Captures.hasBeenComputed())
7766+
return std::nullopt;
7767+
return Captures;
7768+
}
77587769

77597770
void setCaptureInfo(CaptureInfo captures) {
77607771
assert(captures.hasBeenComputed());

include/swift/AST/Expr.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3912,7 +3912,16 @@ class AbstractClosureExpr : public DeclContext, public Expr {
39123912
std::tuple<CapturedValue, unsigned, ApplyIsolationCrossing>>
39133913
&foundIsolationCrossings);
39143914

3915-
CaptureInfo getCaptureInfo() const { return Captures; }
3915+
CaptureInfo getCaptureInfo() const {
3916+
assert(Captures.hasBeenComputed());
3917+
return Captures;
3918+
}
3919+
3920+
std::optional<CaptureInfo> getCachedCaptureInfo() const {
3921+
if (!Captures.hasBeenComputed())
3922+
return std::nullopt;
3923+
return Captures;
3924+
}
39163925

39173926
void setCaptureInfo(CaptureInfo captures) {
39183927
assert(captures.hasBeenComputed());

include/swift/AST/TypeCheckRequests.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4949,6 +4949,47 @@ class LifetimeDependenceInfoRequest
49494949
public:
49504950
// Caching.
49514951
bool isCached() const { return true; }
4952+
4953+
};
4954+
4955+
class CaptureInfoRequest :
4956+
public SimpleRequest<CaptureInfoRequest,
4957+
CaptureInfo(AbstractFunctionDecl *),
4958+
RequestFlags::SeparatelyCached> {
4959+
public:
4960+
using SimpleRequest::SimpleRequest;
4961+
4962+
private:
4963+
friend SimpleRequest;
4964+
4965+
// Evaluation.
4966+
CaptureInfo evaluate(Evaluator &evaluator, AbstractFunctionDecl *func) const;
4967+
4968+
public:
4969+
// Separate caching.
4970+
bool isCached() const { return true; }
4971+
std::optional<CaptureInfo> getCachedResult() const;
4972+
void cacheResult(CaptureInfo value) const;
4973+
};
4974+
4975+
class ParamCaptureInfoRequest :
4976+
public SimpleRequest<ParamCaptureInfoRequest,
4977+
CaptureInfo(ParamDecl *),
4978+
RequestFlags::SeparatelyCached> {
4979+
public:
4980+
using SimpleRequest::SimpleRequest;
4981+
4982+
private:
4983+
friend SimpleRequest;
4984+
4985+
// Evaluation.
4986+
CaptureInfo evaluate(Evaluator &evaluator, ParamDecl *param) const;
4987+
4988+
public:
4989+
// Separate caching.
4990+
bool isCached() const { return true; }
4991+
std::optional<CaptureInfo> getCachedResult() const;
4992+
void cacheResult(CaptureInfo value) const;
49524993
};
49534994

49544995
class SuppressesConformanceRequest

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,3 +571,10 @@ SWIFT_REQUEST(TypeChecker, LifetimeDependenceInfoRequest,
571571
SWIFT_REQUEST(TypeChecker, SuppressesConformanceRequest,
572572
bool(NominalTypeDecl *decl, KnownProtocolKind kp),
573573
SeparatelyCached, NoLocationInfo)
574+
575+
SWIFT_REQUEST(TypeChecker, CaptureInfoRequest,
576+
CaptureInfo(AbstractFunctionDecl *),
577+
SeparatelyCached, NoLocationInfo)
578+
SWIFT_REQUEST(TypeChecker, ParamCaptureInfoRequest,
579+
CaptureInfo(ParamDecl *),
580+
SeparatelyCached, NoLocationInfo)

lib/AST/ASTDumper.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,10 +1402,10 @@ namespace {
14021402
printField(PD->getDefaultArgumentKind(), "default_arg");
14031403
}
14041404
if (PD->hasDefaultExpr() &&
1405-
PD->getDefaultArgumentCaptureInfo().hasBeenComputed() &&
1406-
!PD->getDefaultArgumentCaptureInfo().isTrivial()) {
1405+
PD->getCachedDefaultArgumentCaptureInfo() &&
1406+
!PD->getCachedDefaultArgumentCaptureInfo()->isTrivial()) {
14071407
printFieldRaw([&](raw_ostream &OS) {
1408-
PD->getDefaultArgumentCaptureInfo().print(OS);
1408+
PD->getCachedDefaultArgumentCaptureInfo()->print(OS);
14091409
}, "", CapturesColor);
14101410
}
14111411

@@ -1489,11 +1489,12 @@ namespace {
14891489

14901490
void printCommonAFD(AbstractFunctionDecl *D, const char *Type, StringRef Label) {
14911491
printCommon(D, Type, Label, FuncColor);
1492-
if (D->getCaptureInfo().hasBeenComputed() &&
1493-
!D->getCaptureInfo().isTrivial()) {
1494-
printFlagRaw([&](raw_ostream &OS) {
1495-
D->getCaptureInfo().print(OS);
1496-
});
1492+
if (auto captureInfo = D->getCachedCaptureInfo()) {
1493+
if (!captureInfo->isTrivial()) {
1494+
printFlagRaw([&](raw_ostream &OS) {
1495+
captureInfo->print(OS);
1496+
});
1497+
}
14971498
}
14981499

14991500
if (auto *attr = D->getAttrs().getAttribute<NonisolatedAttr>()) {
@@ -2828,11 +2829,12 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
28282829
break;
28292830
}
28302831

2831-
if (E->getCaptureInfo().hasBeenComputed() &&
2832-
!E->getCaptureInfo().isTrivial()) {
2833-
printFieldRaw([&](raw_ostream &OS) {
2834-
E->getCaptureInfo().print(OS);
2835-
}, "", CapturesColor);
2832+
if (auto captureInfo = E->getCachedCaptureInfo()) {
2833+
if (!captureInfo->isTrivial()) {
2834+
printFieldRaw([&](raw_ostream &OS) {
2835+
captureInfo->print(OS);
2836+
}, "", CapturesColor);
2837+
}
28362838
}
28372839
// Printing a function type doesn't indicate whether it's escaping because it doesn't
28382840
// matter in 99% of contexts. AbstractClosureExpr nodes are one of the only exceptions.

lib/AST/Decl.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8716,6 +8716,16 @@ void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) {
87168716
defaultInfo->InitContextAndIsTypeChecked.setPointer(initContext);
87178717
}
87188718

8719+
CaptureInfo ParamDecl::getDefaultArgumentCaptureInfo() const {
8720+
if (!DefaultValueAndFlags.getPointer())
8721+
return CaptureInfo::empty();
8722+
8723+
auto &ctx = getASTContext();
8724+
return evaluateOrDefault(ctx.evaluator,
8725+
ParamCaptureInfoRequest{const_cast<ParamDecl *>(this)},
8726+
CaptureInfo::empty());
8727+
}
8728+
87198729
void ParamDecl::setDefaultArgumentCaptureInfo(CaptureInfo captures) {
87208730
assert(DefaultValueAndFlags.getPointer());
87218731
assert(captures.hasBeenComputed());
@@ -9171,6 +9181,13 @@ const ParamDecl *swift::getParameterAt(const DeclContext *source,
91719181
return nullptr;
91729182
}
91739183

9184+
CaptureInfo AbstractFunctionDecl::getCaptureInfo() const {
9185+
auto &ctx = getASTContext();
9186+
return evaluateOrDefault(ctx.evaluator,
9187+
CaptureInfoRequest{const_cast<AbstractFunctionDecl *>(this)},
9188+
CaptureInfo::empty());
9189+
}
9190+
91749191
Type AbstractFunctionDecl::getMethodInterfaceType() const {
91759192
assert(getDeclContext()->isTypeContext());
91769193
auto Ty = getInterfaceType();

lib/AST/Module.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3468,6 +3468,7 @@ void SourceFile::typeCheckDelayedFunctions() {
34683468
auto *AFD = DelayedFunctions[i];
34693469
assert(!AFD->getDeclContext()->isLocalContext());
34703470
AFD->getTypecheckedBody();
3471+
(void) AFD->getCaptureInfo();
34713472
}
34723473

34733474
DelayedFunctions.clear();

lib/AST/TypeCheckRequests.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2258,3 +2258,25 @@ void ExpandBodyMacroRequest::noteCycleStep(DiagnosticEngine &diags) const {
22582258
"body",
22592259
decl->getName());
22602260
}
2261+
2262+
std::optional<CaptureInfo>
2263+
CaptureInfoRequest::getCachedResult() const {
2264+
auto *func = std::get<0>(getStorage());
2265+
return func->getCachedCaptureInfo();
2266+
}
2267+
2268+
void CaptureInfoRequest::cacheResult(CaptureInfo info) const {
2269+
auto *func = std::get<0>(getStorage());
2270+
return func->setCaptureInfo(info);
2271+
}
2272+
2273+
std::optional<CaptureInfo>
2274+
ParamCaptureInfoRequest::getCachedResult() const {
2275+
auto *param = std::get<0>(getStorage());
2276+
return param->getCachedDefaultArgumentCaptureInfo();
2277+
}
2278+
2279+
void ParamCaptureInfoRequest::cacheResult(CaptureInfo info) const {
2280+
auto *param = std::get<0>(getStorage());
2281+
param->setDefaultArgumentCaptureInfo(info);
2282+
}

lib/SIL/IR/TypeLowering.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4169,8 +4169,6 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
41694169
};
41704170

41714171
collectCaptures = [&](CaptureInfo captureInfo) {
4172-
assert(captureInfo.hasBeenComputed());
4173-
41744172
if (captureInfo.hasGenericParamCaptures())
41754173
capturesGenericParams = true;
41764174
if (captureInfo.hasDynamicSelfCapture())

lib/SILGen/SILGenProlog.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,9 +1235,6 @@ void SILGenFunction::emitProlog(
12351235
SourceLoc throwsLoc) {
12361236
// Emit the capture argument variables. These are placed last because they
12371237
// become the first curry level of the SIL function.
1238-
assert(captureInfo.hasBeenComputed() &&
1239-
"can't emit prolog of function with uncomputed captures");
1240-
12411238
bool hasErasedIsolation =
12421239
(TypeContext && TypeContext->ExpectedLoweredType->hasErasedIsolation());
12431240

0 commit comments

Comments
 (0)