Skip to content

Commit 8d7cf97

Browse files
committed
AST: Refactor pattern binding initializer expression state representation.
As a follow up to #69841, clarify the possible states that initializer expression of a pattern can be in. The possible states are not checked, checked, and "checked and contextualized" (which is the new state that was introduced and requestified in the previous PR). This refactoring encodes the states more explicitly and renames a few compiler APIs to better align with the new naming. NFC.
1 parent 7680332 commit 8d7cf97

File tree

10 files changed

+89
-51
lines changed

10 files changed

+89
-51
lines changed

include/swift/AST/Decl.h

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,7 +1918,7 @@ class ExtensionRange {
19181918
/// the initializer can be null if there is none.
19191919
class PatternBindingEntry {
19201920
enum class Flags {
1921-
Checked = 1 << 0,
1921+
// 1 << 0 is available
19221922
Removed = 1 << 1,
19231923
/// Whether the contents of this initializer were subsumed by
19241924
/// some other initialization, e.g., a lazy property's initializer
@@ -1927,6 +1927,15 @@ class PatternBindingEntry {
19271927
};
19281928
llvm::PointerIntPair<Pattern *, 3, OptionSet<Flags>> PatternAndFlags;
19291929

1930+
enum class InitializerStatus {
1931+
/// The init expression has not been typechecked.
1932+
NotChecked = 0,
1933+
/// The init expression has been typechecked but not contextualized.
1934+
Checked,
1935+
/// The init expression has been typechecked and contextualized.
1936+
CheckedAndContextualized,
1937+
};
1938+
19301939
struct InitializerAndEqualLoc {
19311940
// When the initializer is removed we don't actually clear the pointers
19321941
// because we might need to get initializer's source range. Since the
@@ -1936,7 +1945,7 @@ class PatternBindingEntry {
19361945
Expr *originalInit;
19371946
/// Might be transformed, e.g. for a property wrapper. In the absence of
19381947
/// transformation or synthesis, holds the expr as parsed.
1939-
Expr *initAfterSynthesis;
1948+
llvm::PointerIntPair<Expr *, 2, InitializerStatus> initAfterSynthesis;
19401949
/// The location of the equal '=' token.
19411950
SourceLoc EqualLoc;
19421951
};
@@ -1974,6 +1983,7 @@ class PatternBindingEntry {
19741983
// typeCheckPatternBinding are requestified, merge this bit with
19751984
// Flags::Checked.
19761985
friend class PatternBindingEntryRequest;
1986+
friend class PatternBindingCheckedAndContextualizedInitRequest;
19771987

19781988
bool isFullyValidated() const {
19791989
return InitContextAndFlags.getInt().contains(
@@ -1996,7 +2006,8 @@ class PatternBindingEntry {
19962006
/// \p E is the initializer as parsed.
19972007
PatternBindingEntry(Pattern *P, SourceLoc EqualLoc, Expr *E,
19982008
DeclContext *InitContext)
1999-
: PatternAndFlags(P, {}), InitExpr({E, E, EqualLoc}),
2009+
: PatternAndFlags(P, {}),
2010+
InitExpr({E, {E, InitializerStatus::NotChecked}, EqualLoc}),
20002011
InitContextAndFlags({InitContext, llvm::None}) {}
20012012

20022013
private:
@@ -2013,7 +2024,7 @@ class PatternBindingEntry {
20132024
if (PatternAndFlags.getInt().contains(Flags::Removed) ||
20142025
InitContextAndFlags.getInt().contains(PatternFlags::IsText))
20152026
return nullptr;
2016-
return InitExpr.initAfterSynthesis;
2027+
return InitExpr.initAfterSynthesis.getPointer();
20172028
}
20182029
/// Retrieve the initializer if it should be executed to initialize this
20192030
/// particular pattern binding.
@@ -2060,11 +2071,26 @@ class PatternBindingEntry {
20602071
/// Set the initializer after the = as it was written in the source.
20612072
void setOriginalInit(Expr *);
20622073

2074+
InitializerStatus initializerStatus() const {
2075+
if (InitContextAndFlags.getInt().contains(PatternFlags::IsText))
2076+
return InitializerStatus::NotChecked;
2077+
return InitExpr.initAfterSynthesis.getInt();
2078+
}
20632079
bool isInitializerChecked() const {
2064-
return PatternAndFlags.getInt().contains(Flags::Checked);
2080+
return initializerStatus() != InitializerStatus::NotChecked;
20652081
}
20662082
void setInitializerChecked() {
2067-
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Checked);
2083+
assert(!InitContextAndFlags.getInt().contains(PatternFlags::IsText));
2084+
InitExpr.initAfterSynthesis.setInt(InitializerStatus::Checked);
2085+
}
2086+
2087+
bool isInitializerCheckedAndContextualized() const {
2088+
return initializerStatus() == InitializerStatus::CheckedAndContextualized;
2089+
}
2090+
void setInitializerCheckedAndContextualized() {
2091+
assert(!InitContextAndFlags.getInt().contains(PatternFlags::IsText));
2092+
InitExpr.initAfterSynthesis.setInt(
2093+
InitializerStatus::CheckedAndContextualized);
20682094
}
20692095

20702096
bool isInitializerSubsumed() const {
@@ -2128,6 +2154,7 @@ class PatternBindingDecl final : public Decl,
21282154
friend TrailingObjects;
21292155
friend class Decl;
21302156
friend class PatternBindingEntryRequest;
2157+
friend class PatternBindingCheckedAndContextualizedInitRequest;
21312158

21322159
SourceLoc StaticLoc; ///< Location of the 'static/class' keyword, if present.
21332160
SourceLoc VarLoc; ///< Location of the 'var' keyword.
@@ -2276,9 +2303,13 @@ class PatternBindingDecl final : public Decl,
22762303
getMutablePatternList()[i].setOriginalInit(E);
22772304
}
22782305

2279-
/// Returns a fully typechecked executable init expression for the pattern at
2280-
/// the given index.
2281-
Expr *getCheckedExecutableInit(unsigned i) const;
2306+
/// Returns a fully typechecked init expression for the pattern at the given
2307+
/// index.
2308+
Expr *getCheckedAndContextualizedInit(unsigned i) const;
2309+
2310+
/// Returns the result of `getCheckedAndContextualizedInit()` if the init is
2311+
/// not subsumed. Otherwise, returns `nullptr`.
2312+
Expr *getCheckedAndContextualizedExecutableInit(unsigned i) const;
22822313

22832314
Pattern *getPattern(unsigned i) const {
22842315
return getPatternList()[i].getPattern();

include/swift/AST/Pattern.h

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,10 @@ 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+1,
71+
SWIFT_INLINE_BITFIELD_BASE(Pattern, bitmax(NumPatternKindBits,8)+1+1,
7272
Kind : bitmax(NumPatternKindBits,8),
7373
isImplicit : 1,
74-
hasInterfaceType : 1,
75-
executableInitChecked : 1
74+
hasInterfaceType : 1
7675
);
7776

7877
SWIFT_INLINE_BITFIELD_FULL(TuplePattern, Pattern, 32,
@@ -105,7 +104,6 @@ class alignas(8) Pattern : public ASTAllocated<Pattern> {
105104
Bits.Pattern.Kind = unsigned(kind);
106105
Bits.Pattern.isImplicit = false;
107106
Bits.Pattern.hasInterfaceType = false;
108-
Bits.Pattern.executableInitChecked = false;
109107
}
110108

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

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

include/swift/AST/TypeCheckRequests.h

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

2350-
class PatternBindingCheckedExecutableInitRequest
2351-
: public SimpleRequest<PatternBindingCheckedExecutableInitRequest,
2350+
class PatternBindingCheckedAndContextualizedInitRequest
2351+
: public SimpleRequest<PatternBindingCheckedAndContextualizedInitRequest,
23522352
Expr *(PatternBindingDecl *, unsigned),
23532353
RequestFlags::SeparatelyCached> {
23542354
public:

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ SWIFT_REQUEST(TypeChecker, OverriddenDeclsRequest,
258258
SWIFT_REQUEST(TypeChecker, PatternBindingEntryRequest,
259259
const PatternBindingEntry *(PatternBindingDecl *, unsigned, bool),
260260
SeparatelyCached, NoLocationInfo)
261-
SWIFT_REQUEST(TypeChecker, PatternBindingCheckedExecutableInitRequest,
261+
SWIFT_REQUEST(TypeChecker, PatternBindingCheckedAndContextualizedInitRequest,
262262
Expr *(PatternBindingDecl *, unsigned),
263263
SeparatelyCached, NoLocationInfo)
264264
SWIFT_REQUEST(TypeChecker, PrimarySourceFilesRequest,

lib/AST/Decl.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,7 +2072,7 @@ void PatternBindingEntry::setInit(Expr *E) {
20722072
} else {
20732073
PatternAndFlags.setInt(F | Flags::Removed);
20742074
}
2075-
InitExpr.initAfterSynthesis = E;
2075+
InitExpr.initAfterSynthesis.setPointer(E);
20762076
InitContextAndFlags.setInt(InitContextAndFlags.getInt() -
20772077
PatternFlags::IsText);
20782078
}
@@ -2198,13 +2198,19 @@ PatternBindingDecl::getInitializerIsolation(unsigned i) const {
21982198
return var->getInitializerIsolation();
21992199
}
22002200

2201-
Expr *PatternBindingDecl::getCheckedExecutableInit(unsigned i) const {
2201+
Expr *PatternBindingDecl::getCheckedAndContextualizedInit(unsigned i) const {
22022202
return evaluateOrDefault(getASTContext().evaluator,
2203-
PatternBindingCheckedExecutableInitRequest{
2203+
PatternBindingCheckedAndContextualizedInitRequest{
22042204
const_cast<PatternBindingDecl *>(this), i},
22052205
nullptr);
22062206
}
22072207

2208+
Expr *PatternBindingDecl::getCheckedAndContextualizedExecutableInit(
2209+
unsigned i) const {
2210+
(void)getCheckedAndContextualizedInit(i);
2211+
return getExecutableInit(i);
2212+
}
2213+
22082214
bool PatternBindingDecl::hasStorage() const {
22092215
// Walk the pattern, to check to see if any of the VarDecls included in it
22102216
// have storage.

lib/AST/TypeCheckRequests.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,23 +1023,24 @@ void PatternBindingEntryRequest::cacheResult(
10231023
}
10241024

10251025
//----------------------------------------------------------------------------//
1026-
// PatternCheckedExecutableInitRequest computation.
1026+
// PatternBindingCheckedAndContextualizedInitRequest computation.
10271027
//----------------------------------------------------------------------------//
10281028

10291029
llvm::Optional<Expr *>
1030-
PatternBindingCheckedExecutableInitRequest::getCachedResult() const {
1030+
PatternBindingCheckedAndContextualizedInitRequest::getCachedResult() const {
10311031
auto *PBD = std::get<0>(getStorage());
10321032
auto idx = std::get<1>(getStorage());
1033-
if (!PBD->getPattern(idx)->executableInitChecked())
1033+
if (!PBD->getPatternList()[idx].isInitializerCheckedAndContextualized())
10341034
return llvm::None;
1035-
return PBD->getExecutableInit(idx);
1035+
return PBD->getInit(idx);
10361036
}
10371037

1038-
void PatternBindingCheckedExecutableInitRequest::cacheResult(Expr *expr) const {
1038+
void PatternBindingCheckedAndContextualizedInitRequest::cacheResult(
1039+
Expr *expr) const {
10391040
auto *PBD = std::get<0>(getStorage());
10401041
auto idx = std::get<1>(getStorage());
1041-
assert(expr == PBD->getExecutableInit(idx));
1042-
PBD->getPattern(idx)->setExecutableInitChecked();
1042+
assert(expr == PBD->getInit(idx));
1043+
PBD->getMutablePatternList()[idx].setInitializerCheckedAndContextualized();
10431044
}
10441045

10451046
//----------------------------------------------------------------------------//

lib/SILGen/SILGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1657,7 +1657,7 @@ emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) {
16571657
return;
16581658

16591659
// Force the executable init to be type checked before emission.
1660-
if (!pbd->getCheckedExecutableInit(i))
1660+
if (!pbd->getCheckedAndContextualizedExecutableInit(i))
16611661
return;
16621662

16631663
auto *var = pbd->getAnchoringVarDecl(i);

lib/SILGen/SILGenGlobalVariable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ void SILGenModule::emitGlobalInitialization(PatternBindingDecl *pd,
220220
}
221221

222222
// Force the executable init to be type checked before emission.
223-
if (!pd->getCheckedExecutableInit(pbdEntry))
223+
if (!pd->getCheckedAndContextualizedExecutableInit(pbdEntry))
224224
return;
225225

226226
Mangle::ASTMangler TokenMangler;

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2664,7 +2664,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
26642664

26652665
// Trigger a request that will complete typechecking for the
26662666
// initializer.
2667-
(void)PBD->getCheckedExecutableInit(i);
2667+
(void)PBD->getCheckedAndContextualizedInit(i);
26682668
}
26692669
}
26702670

lib/Sema/TypeCheckStorage.cpp

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -585,41 +585,48 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate(
585585
return &pbe;
586586
}
587587

588-
Expr *PatternBindingCheckedExecutableInitRequest::evaluate(
589-
Evaluator &eval, PatternBindingDecl *binding, unsigned i) const {
588+
static void checkAndContextualizePatternBindingInit(PatternBindingDecl *binding,
589+
unsigned i) {
590590
// Force the entry to be checked.
591591
(void)binding->getCheckedPatternBindingEntry(i);
592592
if (binding->isInvalid())
593-
return nullptr;
593+
return;
594594

595595
if (!binding->isInitialized(i))
596-
return nullptr;
596+
return;
597597

598598
if (!binding->isInitializerChecked(i))
599599
TypeChecker::typeCheckPatternBinding(binding, i);
600600

601601
if (binding->isInvalid())
602-
return nullptr;
602+
return;
603603

604604
// If we entered an initializer context, contextualize any auto-closures we
605605
// might have created. Note that we don't contextualize the initializer for a
606606
// property with a wrapper, because the initializer will have been subsumed by
607607
// the backing storage property.
608-
auto *init = binding->getInit(i);
608+
if (binding->getDeclContext()->isLocalContext())
609+
return;
609610

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-
}
611+
if (auto *var = binding->getSingleVar()) {
612+
if (var->hasAttachedPropertyWrapper())
613+
return;
620614
}
621615

622-
return binding->getExecutableInit(i);
616+
auto *initContext =
617+
cast_or_null<PatternBindingInitializer>(binding->getInitContext(i));
618+
if (initContext) {
619+
auto *init = binding->getInit(i);
620+
TypeChecker::contextualizeInitializer(initContext, init);
621+
(void)binding->getInitializerIsolation(i);
622+
TypeChecker::checkInitializerEffects(initContext, init);
623+
}
624+
}
625+
626+
Expr *PatternBindingCheckedAndContextualizedInitRequest::evaluate(
627+
Evaluator &eval, PatternBindingDecl *binding, unsigned i) const {
628+
checkAndContextualizePatternBindingInit(binding, i);
629+
return binding->getInit(i);
623630
}
624631

625632
bool

0 commit comments

Comments
 (0)