Skip to content

Commit e8c85fa

Browse files
authored
Merge pull request #80599 from hamishknight/cap-req-6.2
[6.2] [Sema] Requestify PatternBindingDecl capture computation
2 parents ca76d7e + 6d287be commit e8c85fa

11 files changed

+123
-57
lines changed

include/swift/AST/Decl.h

+19-9
Original file line numberDiff line numberDiff line change
@@ -2287,6 +2287,7 @@ class PatternBindingEntry {
22872287
// Flags::Checked.
22882288
friend class PatternBindingEntryRequest;
22892289
friend class PatternBindingCheckedAndContextualizedInitRequest;
2290+
friend class PatternBindingCaptureInfoRequest;
22902291

22912292
bool isFullyValidated() const {
22922293
return InitContextAndFlags.getInt().contains(
@@ -2435,8 +2436,20 @@ class PatternBindingEntry {
24352436
/// from the source range.
24362437
SourceRange getSourceRange(bool omitAccessors = false) const;
24372438

2438-
CaptureInfo getCaptureInfo() const { return Captures; }
2439-
void setCaptureInfo(CaptureInfo captures) { Captures = captures; }
2439+
/// Retrieve the computed capture info, or \c nullopt if it hasn't been
2440+
/// computed yet.
2441+
std::optional<CaptureInfo> getCachedCaptureInfo() const {
2442+
if (!Captures.hasBeenComputed())
2443+
return std::nullopt;
2444+
2445+
return Captures;
2446+
}
2447+
2448+
void setCaptureInfo(CaptureInfo captures) {
2449+
ASSERT(!Captures.hasBeenComputed());
2450+
ASSERT(captures.hasBeenComputed());
2451+
Captures = captures;
2452+
}
24402453

24412454
private:
24422455
SourceLoc getLastAccessorEndLoc() const;
@@ -2460,6 +2473,7 @@ class PatternBindingDecl final : public Decl,
24602473
friend class Decl;
24612474
friend class PatternBindingEntryRequest;
24622475
friend class PatternBindingCheckedAndContextualizedInitRequest;
2476+
friend class PatternBindingCaptureInfoRequest;
24632477

24642478
SourceLoc StaticLoc; ///< Location of the 'static/class' keyword, if present.
24652479
SourceLoc VarLoc; ///< Location of the 'var' keyword.
@@ -2639,13 +2653,9 @@ class PatternBindingDecl final : public Decl,
26392653
getMutablePatternList()[i].setInitContext(init);
26402654
}
26412655

2642-
CaptureInfo getCaptureInfo(unsigned i) const {
2643-
return getPatternList()[i].getCaptureInfo();
2644-
}
2645-
2646-
void setCaptureInfo(unsigned i, CaptureInfo captures) {
2647-
getMutablePatternList()[i].setCaptureInfo(captures);
2648-
}
2656+
/// Retrieve the capture info for the initializer at the given index,
2657+
/// computing if needed.
2658+
CaptureInfo getCaptureInfo(unsigned i) const;
26492659

26502660
/// Given that this PBD is the parent pattern for the specified VarDecl,
26512661
/// return the entry of the VarDecl in our PatternList. For example, in:

include/swift/AST/TypeCheckRequests.h

+20
Original file line numberDiff line numberDiff line change
@@ -5134,6 +5134,26 @@ class ParamCaptureInfoRequest :
51345134
void cacheResult(CaptureInfo value) const;
51355135
};
51365136

5137+
class PatternBindingCaptureInfoRequest
5138+
: public SimpleRequest<PatternBindingCaptureInfoRequest,
5139+
CaptureInfo(PatternBindingDecl *, unsigned),
5140+
RequestFlags::SeparatelyCached> {
5141+
public:
5142+
using SimpleRequest::SimpleRequest;
5143+
5144+
private:
5145+
friend SimpleRequest;
5146+
5147+
CaptureInfo evaluate(Evaluator &evaluator, PatternBindingDecl *PBD,
5148+
unsigned idx) const;
5149+
5150+
public:
5151+
// Separate caching.
5152+
bool isCached() const { return true; }
5153+
std::optional<CaptureInfo> getCachedResult() const;
5154+
void cacheResult(CaptureInfo info) const;
5155+
};
5156+
51375157
class SuppressesConformanceRequest
51385158
: public SimpleRequest<SuppressesConformanceRequest,
51395159
bool(NominalTypeDecl *decl, KnownProtocolKind kp),

include/swift/AST/TypeCheckerTypeIDZone.def

+3
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,9 @@ SWIFT_REQUEST(TypeChecker, CaptureInfoRequest,
608608
SWIFT_REQUEST(TypeChecker, ParamCaptureInfoRequest,
609609
CaptureInfo(ParamDecl *),
610610
SeparatelyCached, NoLocationInfo)
611+
SWIFT_REQUEST(TypeChecker, PatternBindingCaptureInfoRequest,
612+
CaptureInfo(PatternBindingDecl *, unsigned),
613+
SeparatelyCached, NoLocationInfo)
611614
SWIFT_REQUEST(TypeChecker, CustomDerivativesRequest,
612615
CustomDerivativesResult(SourceFile *),
613616
Cached, NoLocationInfo)

lib/AST/Decl.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -2287,6 +2287,13 @@ PatternBindingDecl *PatternBindingDecl::createDeserialized(
22872287
return PBD;
22882288
}
22892289

2290+
CaptureInfo PatternBindingDecl::getCaptureInfo(unsigned i) const {
2291+
auto *mutableThis = const_cast<PatternBindingDecl *>(this);
2292+
PatternBindingCaptureInfoRequest req(mutableThis, i);
2293+
return evaluateOrDefault(getASTContext().evaluator, req,
2294+
CaptureInfo::empty());
2295+
}
2296+
22902297
PatternBindingInitializer *
22912298
PatternBindingInitializer::createDeserialized(PatternBindingDecl *PBD,
22922299
unsigned index) {

lib/AST/TypeCheckRequests.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -2751,6 +2751,23 @@ void ParamCaptureInfoRequest::cacheResult(CaptureInfo info) const {
27512751
param->setDefaultArgumentCaptureInfo(info);
27522752
}
27532753

2754+
//----------------------------------------------------------------------------//
2755+
// PatternBindingCaptureInfoRequest caching.
2756+
//----------------------------------------------------------------------------//
2757+
2758+
std::optional<CaptureInfo>
2759+
PatternBindingCaptureInfoRequest::getCachedResult() const {
2760+
auto *PBD = std::get<0>(getStorage());
2761+
auto idx = std::get<1>(getStorage());
2762+
return PBD->getPatternList()[idx].getCachedCaptureInfo();
2763+
}
2764+
2765+
void PatternBindingCaptureInfoRequest::cacheResult(CaptureInfo info) const {
2766+
auto *PBD = std::get<0>(getStorage());
2767+
auto idx = std::get<1>(getStorage());
2768+
PBD->getMutablePatternList()[idx].setCaptureInfo(info);
2769+
}
2770+
27542771
//----------------------------------------------------------------------------//
27552772
// SemanticAvailableAttrRequest computation.
27562773
//----------------------------------------------------------------------------//

lib/Sema/TypeCheckCaptures.cpp

+22-35
Original file line numberDiff line numberDiff line change
@@ -857,43 +857,30 @@ CaptureInfo ParamCaptureInfoRequest::evaluate(Evaluator &evaluator,
857857
return finder.getCaptureInfo();
858858
}
859859

860-
static bool isLazy(PatternBindingDecl *PBD) {
861-
if (auto var = PBD->getSingleVar())
862-
return var->getAttrs().hasAttribute<LazyAttr>();
863-
return false;
864-
}
865-
866-
void TypeChecker::checkPatternBindingCaptures(IterableDeclContext *DC) {
867-
for (auto member : DC->getMembers()) {
868-
// Ignore everything other than PBDs.
869-
auto *PBD = dyn_cast<PatternBindingDecl>(member);
870-
if (!PBD) continue;
871-
// Walk the initializers for all properties declared in the type with
872-
// an initializer.
873-
for (unsigned i : range(PBD->getNumPatternEntries())) {
874-
if (PBD->isInitializerSubsumed(i))
875-
continue;
860+
CaptureInfo PatternBindingCaptureInfoRequest::evaluate(Evaluator &evaluator,
861+
PatternBindingDecl *PBD,
862+
unsigned int idx) const {
863+
auto *init = PBD->getExecutableInit(idx);
864+
if (!init)
865+
return CaptureInfo::empty();
876866

877-
auto *init = PBD->getInit(i);
878-
if (init == nullptr)
879-
continue;
867+
// Only have captures when we have a PatternBindingInitializer context, i.e
868+
// local variables don't have captures.
869+
auto *DC = PBD->getInitContext(idx);
870+
if (!DC)
871+
return CaptureInfo::empty();
880872

881-
auto *DC = PBD->getInitContext(i);
882-
FindCapturedVars finder(init->getLoc(),
883-
DC,
884-
/*NoEscape=*/false,
885-
/*ObjC=*/false,
886-
/*IsGenericFunction*/false);
887-
init->walk(finder);
888-
889-
auto &ctx = DC->getASTContext();
890-
if (finder.getDynamicSelfCaptureLoc().isValid() && !isLazy(PBD)) {
891-
ctx.Diags.diagnose(finder.getDynamicSelfCaptureLoc(),
892-
diag::dynamic_self_stored_property_init);
893-
}
873+
FindCapturedVars finder(init->getLoc(), DC,
874+
/*NoEscape=*/false,
875+
/*ObjC=*/false,
876+
/*IsGenericFunction*/ false);
877+
init->walk(finder);
894878

895-
auto captures = finder.getCaptureInfo();
896-
PBD->setCaptureInfo(i, captures);
897-
}
879+
auto &ctx = DC->getASTContext();
880+
if (finder.getDynamicSelfCaptureLoc().isValid()) {
881+
ctx.Diags.diagnose(finder.getDynamicSelfCaptureLoc(),
882+
diag::dynamic_self_stored_property_init);
898883
}
884+
885+
return finder.getCaptureInfo();
899886
}

lib/Sema/TypeCheckDeclPrimary.cpp

-8
Original file line numberDiff line numberDiff line change
@@ -3236,8 +3236,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
32363236
diagnoseMissingExplicitSendable(ED);
32373237
checkAccessControl(ED);
32383238

3239-
TypeChecker::checkPatternBindingCaptures(ED);
3240-
32413239
auto &DE = Ctx.Diags;
32423240
if (auto rawTy = ED->getRawType()) {
32433241
// The raw type must be one of the blessed literal convertible types.
@@ -3307,8 +3305,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
33073305
visit(Member);
33083306
}
33093307

3310-
TypeChecker::checkPatternBindingCaptures(SD);
3311-
33123308
checkInheritanceClause(SD);
33133309
diagnoseMissingExplicitSendable(SD);
33143310

@@ -3490,8 +3486,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
34903486
for (Decl *Member : CD->getABIMembers())
34913487
visit(Member);
34923488

3493-
TypeChecker::checkPatternBindingCaptures(CD);
3494-
34953489
// If this class requires all of its stored properties to have
34963490
// in-class initializers, diagnose this now.
34973491
if (CD->requiresStoredPropertyInits())
@@ -4074,8 +4068,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
40744068
for (Decl *Member : ED->getMembers())
40754069
visit(Member);
40764070

4077-
TypeChecker::checkPatternBindingCaptures(ED);
4078-
40794071
TypeChecker::checkConformancesInContext(ED);
40804072

40814073
checkAccessControl(ED);

lib/Sema/TypeCheckStorage.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,9 @@ static void checkAndContextualizePatternBindingInit(PatternBindingDecl *binding,
619619
auto *init = binding->getInit(i);
620620
TypeChecker::contextualizeExpr(init, initContext);
621621
}
622+
623+
// Compute captures in case diagnostics are emitted.
624+
(void)binding->getCaptureInfo(i);
622625
}
623626

624627
Expr *PatternBindingCheckedAndContextualizedInitRequest::evaluate(

lib/Sema/TypeChecker.h

-3
Original file line numberDiff line numberDiff line change
@@ -798,9 +798,6 @@ bool typeCheckForEachPreamble(DeclContext *dc, ForEachStmt *stmt);
798798
/// Compute the set of captures for the given closure.
799799
void computeCaptures(AbstractClosureExpr *ACE);
800800

801-
/// Check for invalid captures from stored property initializers.
802-
void checkPatternBindingCaptures(IterableDeclContext *DC);
803-
804801
/// Update the DeclContexts for AST nodes in a given DeclContext. This is
805802
/// necessary after type-checking since autoclosures may have been introduced.
806803
void contextualizeExpr(Expr *E, DeclContext *DC);

test/Macros/Inputs/syntax_macro_definitions.swift

+14
Original file line numberDiff line numberDiff line change
@@ -2134,6 +2134,20 @@ public struct VarValueMacro: DeclarationMacro, PeerMacro {
21342134
}
21352135
}
21362136

2137+
struct StoredPropertyMacro: DeclarationMacro {
2138+
public static func expansion(
2139+
of node: some FreestandingMacroExpansionSyntax,
2140+
in context: some MacroExpansionContext
2141+
) throws -> [DeclSyntax] {
2142+
guard let argument = node.arguments.first?.expression else {
2143+
fatalError("boom")
2144+
}
2145+
return [
2146+
"var storedProperty = \(argument)"
2147+
]
2148+
}
2149+
}
2150+
21372151
public struct GenericToVoidMacro: ExpressionMacro {
21382152
public static func expansion(
21392153
of node: some FreestandingMacroExpansionSyntax,

test/Macros/macro_expand.swift

+18-2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ macro freestandingWithClosure<T>(_ value: T, body: (T) -> T) = #externalMacro(mo
6363

6464
#endif
6565

66+
@freestanding(declaration, names: named(storedProperty))
67+
public macro AddStoredProperty<T>(_ x: T) = #externalMacro(module: "MacroDefinition", type: "StoredPropertyMacro")
68+
6669
#if TEST_DIAGNOSTICS
6770
@freestanding(declaration)
6871
macro NotCovered() = #externalMacro(module: "MacroDefinition", type: "InvalidMacro")
@@ -72,7 +75,7 @@ struct MemberNotCovered {
7275
// expected-note@-1 {{in expansion of macro 'NotCovered' here}}
7376

7477
// CHECK-DIAGS: error: declaration name 'value' is not covered by macro 'NotCovered'
75-
// CHECK-DIAGS: CONTENTS OF FILE @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX70_2_33_4361AD9339943F52AE6186DD51E04E91Ll10NotCoveredfMf_.swift
78+
// CHECK-DIAGS: CONTENTS OF FILE @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-5]]_2_33_4361AD9339943F52AE6186DD51E04E91Ll10NotCoveredfMf_.swift
7679
// CHECK-DIAGS: var value: Int
7780
// CHECK-DIAGS: END CONTENTS OF FILE
7881
}
@@ -126,6 +129,11 @@ struct Bad {}
126129
// CHECK-DIAGS: typealias _ImageLiteralType = Void
127130
// CHECK-DIAGS: typealias _FileReferenceLiteralType = Void
128131
// CHECK-DIAGS: END CONTENTS OF FILE
132+
133+
class HasStoredPropertyClassInvalid {
134+
#AddStoredProperty((Self.self, 0).1) // expected-note {{in expansion of macro 'AddStoredProperty' here}}
135+
// CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-2]]_2_33_{{.*}}AddStoredPropertyfMf_.swift:1:22: error: covariant 'Self' type cannot be referenced from a stored property initializer
136+
}
129137
#endif
130138

131139
@freestanding(declaration)
@@ -138,7 +146,7 @@ macro AccidentalCodeItem() = #externalMacro(module: "MacroDefinition", type: "Fa
138146
func invalidDeclarationMacro() {
139147
#accidentalCodeItem
140148
// expected-note@-1 {{in expansion of macro 'accidentalCodeItem' here}}
141-
// CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX138_2_18accidentalCodeItemfMf_.swift:1:1: error: expected macro expansion to produce a declaration
149+
// CHECK-DIAGS: @__swiftmacro_9MacroUser0023macro_expandswift_elFCffMX[[@LINE-3]]_2_18accidentalCodeItemfMf_.swift:1:1: error: expected macro expansion to produce a declaration
142150

143151
@AccidentalCodeItem struct S {}
144152
// expected-note@-1 {{in expansion of macro 'AccidentalCodeItem' on struct 'S' here}}
@@ -681,3 +689,11 @@ func invalidDeclarationMacro2() {
681689
}
682690
}
683691
#endif
692+
693+
// Make sure we compute captures for the introduced stored property here.
694+
struct HasStoredProperty {
695+
#AddStoredProperty(0)
696+
}
697+
class HasStoredPropertyClass {
698+
#AddStoredProperty(0)
699+
}

0 commit comments

Comments
 (0)