Skip to content

Commit 8aa0a3c

Browse files
authored
Merge pull request swiftlang#69841 from tshortli/silgen-lazy-typecheck-pattern-executable-init
AST/SILGen: Requestify var initializer expression typechecking
2 parents 8ca707b + 111eea7 commit 8aa0a3c

13 files changed

+189
-22
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2276,6 +2276,10 @@ class PatternBindingDecl final : public Decl,
22762276
getMutablePatternList()[i].setOriginalInit(E);
22772277
}
22782278

2279+
/// Returns a fully typechecked executable init expression for the pattern at
2280+
/// the given index.
2281+
Expr *getCheckedExecutableInit(unsigned i) const;
2282+
22792283
Pattern *getPattern(unsigned i) const {
22802284
return getPatternList()[i].getPattern();
22812285
}

include/swift/AST/Pattern.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,11 @@ class alignas(8) Pattern : public ASTAllocated<Pattern> {
6868
// clang-format off
6969
union { uint64_t OpaqueBits;
7070

71-
SWIFT_INLINE_BITFIELD_BASE(Pattern, bitmax(NumPatternKindBits,8)+1+1,
71+
SWIFT_INLINE_BITFIELD_BASE(Pattern, bitmax(NumPatternKindBits,8)+1+1+1,
7272
Kind : bitmax(NumPatternKindBits,8),
7373
isImplicit : 1,
74-
hasInterfaceType : 1
74+
hasInterfaceType : 1,
75+
executableInitChecked : 1
7576
);
7677

7778
SWIFT_INLINE_BITFIELD_FULL(TuplePattern, Pattern, 32,
@@ -104,6 +105,7 @@ class alignas(8) Pattern : public ASTAllocated<Pattern> {
104105
Bits.Pattern.Kind = unsigned(kind);
105106
Bits.Pattern.isImplicit = false;
106107
Bits.Pattern.hasInterfaceType = false;
108+
Bits.Pattern.executableInitChecked = false;
107109
}
108110

109111
private:
@@ -136,6 +138,11 @@ class alignas(8) Pattern : public ASTAllocated<Pattern> {
136138
bool isImplicit() const { return Bits.Pattern.isImplicit; }
137139
void setImplicit() { Bits.Pattern.isImplicit = true; }
138140

141+
bool executableInitChecked() const {
142+
return Bits.Pattern.executableInitChecked;
143+
}
144+
void setExecutableInitChecked() { Bits.Pattern.executableInitChecked = true; }
145+
139146
/// Find the smallest subpattern which obeys the property that matching it is
140147
/// equivalent to matching this pattern.
141148
///

include/swift/AST/TypeCheckRequests.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,6 +2347,27 @@ class PatternBindingEntryRequest
23472347
void cacheResult(const PatternBindingEntry *value) const;
23482348
};
23492349

2350+
class PatternBindingCheckedExecutableInitRequest
2351+
: public SimpleRequest<PatternBindingCheckedExecutableInitRequest,
2352+
Expr *(PatternBindingDecl *, unsigned),
2353+
RequestFlags::SeparatelyCached> {
2354+
public:
2355+
using SimpleRequest::SimpleRequest;
2356+
2357+
private:
2358+
friend SimpleRequest;
2359+
2360+
// Evaluation.
2361+
Expr *evaluate(Evaluator &evaluator, PatternBindingDecl *PBD,
2362+
unsigned i) const;
2363+
2364+
public:
2365+
// Separate caching.
2366+
bool isCached() const { return true; }
2367+
llvm::Optional<Expr *> getCachedResult() const;
2368+
void cacheResult(Expr *expr) const;
2369+
};
2370+
23502371
class NamingPatternRequest
23512372
: public SimpleRequest<NamingPatternRequest, NamedPattern *(VarDecl *),
23522373
RequestFlags::SeparatelyCached> {

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ SWIFT_REQUEST(TypeChecker, OverriddenDeclsRequest,
258258
SWIFT_REQUEST(TypeChecker, PatternBindingEntryRequest,
259259
const PatternBindingEntry *(PatternBindingDecl *, unsigned, bool),
260260
SeparatelyCached, NoLocationInfo)
261+
SWIFT_REQUEST(TypeChecker, PatternBindingCheckedExecutableInitRequest,
262+
Expr *(PatternBindingDecl *, unsigned),
263+
SeparatelyCached, NoLocationInfo)
261264
SWIFT_REQUEST(TypeChecker, PrimarySourceFilesRequest,
262265
ArrayRef<SourceFile *>(ModuleDecl *), Cached, NoLocationInfo)
263266
SWIFT_REQUEST(TypeChecker, PropertyWrapperAuxiliaryVariablesRequest,

lib/AST/Decl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,6 +2198,13 @@ PatternBindingDecl::getInitializerIsolation(unsigned i) const {
21982198
return var->getInitializerIsolation();
21992199
}
22002200

2201+
Expr *PatternBindingDecl::getCheckedExecutableInit(unsigned i) const {
2202+
return evaluateOrDefault(getASTContext().evaluator,
2203+
PatternBindingCheckedExecutableInitRequest{
2204+
const_cast<PatternBindingDecl *>(this), i},
2205+
nullptr);
2206+
}
2207+
22012208
bool PatternBindingDecl::hasStorage() const {
22022209
// Walk the pattern, to check to see if any of the VarDecls included in it
22032210
// have storage.

lib/AST/TypeCheckRequests.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,26 @@ void PatternBindingEntryRequest::cacheResult(
10221022
PBD->getMutablePatternList()[idx].setFullyValidated();
10231023
}
10241024

1025+
//----------------------------------------------------------------------------//
1026+
// PatternCheckedExecutableInitRequest computation.
1027+
//----------------------------------------------------------------------------//
1028+
1029+
llvm::Optional<Expr *>
1030+
PatternBindingCheckedExecutableInitRequest::getCachedResult() const {
1031+
auto *PBD = std::get<0>(getStorage());
1032+
auto idx = std::get<1>(getStorage());
1033+
if (!PBD->getPattern(idx)->executableInitChecked())
1034+
return llvm::None;
1035+
return PBD->getExecutableInit(idx);
1036+
}
1037+
1038+
void PatternBindingCheckedExecutableInitRequest::cacheResult(Expr *expr) const {
1039+
auto *PBD = std::get<0>(getStorage());
1040+
auto idx = std::get<1>(getStorage());
1041+
assert(expr == PBD->getExecutableInit(idx));
1042+
PBD->getPattern(idx)->setExecutableInitChecked();
1043+
}
1044+
10251045
//----------------------------------------------------------------------------//
10261046
// NamingPatternRequest computation.
10271047
//----------------------------------------------------------------------------//

lib/SILGen/SILGen.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,6 +1656,10 @@ emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) {
16561656
!pbd->getAnchoringVarDecl(i)->isInitExposedToClients())
16571657
return;
16581658

1659+
// Force the executable init to be type checked before emission.
1660+
if (!pbd->getCheckedExecutableInit(i))
1661+
return;
1662+
16591663
auto *var = pbd->getAnchoringVarDecl(i);
16601664
SILDeclRef constant(var, SILDeclRef::Kind::StoredPropertyInitializer);
16611665
emitOrDelayFunction(constant);
@@ -1666,6 +1670,9 @@ emitPropertyWrapperBackingInitializer(VarDecl *var) {
16661670
auto initInfo = var->getPropertyWrapperInitializerInfo();
16671671

16681672
if (initInfo.hasInitFromWrappedValue()) {
1673+
// FIXME: Fully typecheck the original property's init expression on-demand
1674+
// for lazy typechecking mode.
1675+
16691676
SILDeclRef constant(var, SILDeclRef::Kind::PropertyWrapperBackingInitializer);
16701677
emitOrDelayFunction(constant);
16711678
}

lib/SILGen/SILGenGlobalVariable.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd,
219219
->areAllParamsConcrete());
220220
}
221221

222+
// Force the executable init to be type checked before emission.
223+
if (!pd->getCheckedExecutableInit(pbdEntry))
224+
return;
225+
222226
Mangle::ASTMangler TokenMangler;
223227
std::string onceTokenBuffer = TokenMangler.mangleGlobalInit(pd, pbdEntry,
224228
false);

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2662,22 +2662,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
26622662
// as a replacement.
26632663
diagnoseWrittenPlaceholderTypes(Ctx, PBD->getPattern(i), init);
26642664

2665-
// If we entered an initializer context, contextualize any
2666-
// auto-closures we might have created.
2667-
// Note that we don't contextualize the initializer for a property
2668-
// with a wrapper, because the initializer will have been subsumed
2669-
// by the backing storage property.
2670-
if (!DC->isLocalContext() &&
2671-
!(PBD->getSingleVar() &&
2672-
PBD->getSingleVar()->hasAttachedPropertyWrapper())) {
2673-
auto *initContext = cast_or_null<PatternBindingInitializer>(
2674-
PBD->getInitContext(i));
2675-
if (initContext) {
2676-
TypeChecker::contextualizeInitializer(initContext, init);
2677-
(void)PBD->getInitializerIsolation(i);
2678-
TypeChecker::checkInitializerEffects(initContext, init);
2679-
}
2680-
}
2665+
// Trigger a request that will complete typechecking for the
2666+
// initializer.
2667+
(void)PBD->getCheckedExecutableInit(i);
26812668
}
26822669
}
26832670

@@ -2686,6 +2673,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
26862673
// If this is an init accessor property with a default initializer,
26872674
// make sure that it subsumes initializers of all of its "initializes"
26882675
// stored properties.
2676+
// FIXME: This should be requestified.
26892677
auto *initAccessor = var->getAccessor(AccessorKind::Init);
26902678
if (initAccessor && PBD->isInitialized(0)) {
26912679
for (auto *property : initAccessor->getInitializedProperties()) {

lib/Sema/TypeCheckStorage.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,43 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate(
585585
return &pbe;
586586
}
587587

588+
Expr *PatternBindingCheckedExecutableInitRequest::evaluate(
589+
Evaluator &eval, PatternBindingDecl *binding, unsigned i) const {
590+
// Force the entry to be checked.
591+
(void)binding->getCheckedPatternBindingEntry(i);
592+
if (binding->isInvalid())
593+
return nullptr;
594+
595+
if (!binding->isInitialized(i))
596+
return nullptr;
597+
598+
if (!binding->isInitializerChecked(i))
599+
TypeChecker::typeCheckPatternBinding(binding, i);
600+
601+
if (binding->isInvalid())
602+
return nullptr;
603+
604+
// If we entered an initializer context, contextualize any auto-closures we
605+
// might have created. Note that we don't contextualize the initializer for a
606+
// property with a wrapper, because the initializer will have been subsumed by
607+
// the backing storage property.
608+
auto *init = binding->getInit(i);
609+
610+
if (!binding->getDeclContext()->isLocalContext() &&
611+
!(binding->getSingleVar() &&
612+
binding->getSingleVar()->hasAttachedPropertyWrapper())) {
613+
auto *initContext =
614+
cast_or_null<PatternBindingInitializer>(binding->getInitContext(i));
615+
if (initContext) {
616+
TypeChecker::contextualizeInitializer(initContext, init);
617+
(void)binding->getInitializerIsolation(i);
618+
TypeChecker::checkInitializerEffects(initContext, init);
619+
}
620+
}
621+
622+
return binding->getExecutableInit(i);
623+
}
624+
588625
bool
589626
IsGetterMutatingRequest::evaluate(Evaluator &evaluator,
590627
AbstractStorageDecl *storage) const {

0 commit comments

Comments
 (0)