Skip to content

Commit a037a19

Browse files
authored
Merge pull request #69918 from tshortli/refactor-pattern-binding-checked-init
AST: Refactor pattern binding initializer expression state representation
2 parents 3bd764d + 8d7cf97 commit a037a19

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)