Skip to content

Commit 4eac3ea

Browse files
committed
Always create initializer contexts for pattern binding entries in non-local scopes.
We were optimizing away unused pattern binding initializer contexts in both the parser and in semantic analysis, which led to a somewhat-unpredictable set of DeclContexts in the AST. Normalize everything by always creating these contexts.
1 parent 5e25d25 commit 4eac3ea

File tree

11 files changed

+126
-114
lines changed

11 files changed

+126
-114
lines changed

include/swift/AST/ASTContext.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -549,13 +549,6 @@ class ASTContext {
549549
addCleanup([&object]{ object.~T(); });
550550
}
551551

552-
/// Create a context for the initializer of a non-local variable,
553-
/// like a global or a field. To reduce memory usage, if the
554-
/// context goes unused, it should be returned to the ASTContext
555-
/// with destroyPatternBindingContext.
556-
PatternBindingInitializer *createPatternBindingContext(DeclContext *parent);
557-
void destroyPatternBindingContext(PatternBindingInitializer *DC);
558-
559552
/// Create a context for the initializer of the nth default argument
560553
/// of the given function. To reduce memory usage, if the context
561554
/// goes unused, it should be returned to the ASTContext with

include/swift/AST/Decl.h

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,11 @@ class alignas(1 << DeclAlignInBits) Decl {
246246

247247
/// \brief Whether 'static' or 'class' was used.
248248
unsigned StaticSpelling : 2;
249+
250+
/// \brief The number of pattern binding declarations.
251+
unsigned NumPatternEntries : 16;
249252
};
250-
enum { NumPatternBindingDeclBits = NumDeclBits + 3 };
253+
enum { NumPatternBindingDeclBits = NumDeclBits + 19 };
251254
static_assert(NumPatternBindingDeclBits <= 32, "fits in an unsigned");
252255

253256
class ValueDeclBitfields {
@@ -1668,9 +1671,14 @@ class PatternBindingEntry {
16681671
// initializer is ASTContext-allocated it is safe.
16691672
llvm::PointerIntPair<Expr *, 2, OptionSet<Flags>> InitCheckedAndRemoved;
16701673

1674+
/// The initializer context used for this pattern binding entry.
1675+
DeclContext *InitContext = nullptr;
1676+
1677+
friend class PatternBindingInitializer;
1678+
16711679
public:
1672-
PatternBindingEntry(Pattern *P, Expr *E)
1673-
: ThePattern(P), InitCheckedAndRemoved(E, {}) {}
1680+
PatternBindingEntry(Pattern *P, Expr *E, DeclContext *InitContext)
1681+
: ThePattern(P), InitCheckedAndRemoved(E, {}), InitContext(InitContext) {}
16741682

16751683
Pattern *getPattern() const { return ThePattern; }
16761684
void setPattern(Pattern *P) { ThePattern = P; }
@@ -1690,6 +1698,12 @@ class PatternBindingEntry {
16901698

16911699
// Return the first variable initialized by this pattern.
16921700
VarDecl *getAnchoringVarDecl() const;
1701+
1702+
// Retrieve the declaration context for the intializer.
1703+
DeclContext *getInitContext() const { return InitContext; }
1704+
1705+
/// Override the initializer context.
1706+
void setInitContext(DeclContext *dc) { InitContext = dc; }
16931707
};
16941708

16951709
/// \brief This decl contains a pattern and optional initializer for a set
@@ -1711,8 +1725,6 @@ class PatternBindingDecl final : public Decl,
17111725
SourceLoc StaticLoc; ///< Location of the 'static/class' keyword, if present.
17121726
SourceLoc VarLoc; ///< Location of the 'var' keyword.
17131727

1714-
unsigned numPatternEntries;
1715-
17161728
friend class Decl;
17171729

17181730
PatternBindingDecl(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
@@ -1732,13 +1744,22 @@ class PatternBindingDecl final : public Decl,
17321744
Pattern *Pat, Expr *E,
17331745
DeclContext *Parent);
17341746

1747+
static PatternBindingDecl *createDeserialized(
1748+
ASTContext &Ctx, SourceLoc StaticLoc,
1749+
StaticSpellingKind StaticSpelling,
1750+
SourceLoc VarLoc,
1751+
unsigned NumPatternEntries,
1752+
DeclContext *Parent);
1753+
17351754
SourceLoc getStartLoc() const {
17361755
return StaticLoc.isValid() ? StaticLoc : VarLoc;
17371756
}
17381757
SourceLoc getLoc() const { return VarLoc; }
17391758
SourceRange getSourceRange() const;
17401759

1741-
unsigned getNumPatternEntries() const { return numPatternEntries; }
1760+
unsigned getNumPatternEntries() const {
1761+
return PatternBindingDeclBits.NumPatternEntries;
1762+
}
17421763

17431764
ArrayRef<PatternBindingEntry> getPatternList() const {
17441765
return const_cast<PatternBindingDecl*>(this)->getMutablePatternList();
@@ -1760,7 +1781,7 @@ class PatternBindingDecl final : public Decl,
17601781
return getPatternList()[i].getPattern();
17611782
}
17621783

1763-
void setPattern(unsigned i, Pattern *Pat);
1784+
void setPattern(unsigned i, Pattern *Pat, DeclContext *InitContext);
17641785

17651786
/// Given that this PBD is the parent pattern for the specified VarDecl,
17661787
/// return the entry of the VarDecl in our PatternList. For example, in:
@@ -1810,7 +1831,7 @@ class PatternBindingDecl final : public Decl,
18101831
private:
18111832
MutableArrayRef<PatternBindingEntry> getMutablePatternList() {
18121833
// Pattern entries are tail allocated.
1813-
return {getTrailingObjects<PatternBindingEntry>(), numPatternEntries};
1834+
return {getTrailingObjects<PatternBindingEntry>(), getNumPatternEntries()};
18141835
}
18151836
};
18161837

include/swift/Serialization/ModuleFormat.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const uint16_t VERSION_MAJOR = 0;
5353
/// in source control, you should also update the comment to briefly
5454
/// describe what change you made. The content of this comment isn't important;
5555
/// it just ensures a conflict if two people change the module format.
56-
const uint16_t VERSION_MINOR = 265; // Last change: pattern binding initializer index
56+
const uint16_t VERSION_MINOR = 266; // Last change: pattern binding init contexts
5757

5858
using DeclID = PointerEmbeddedInt<unsigned, 31>;
5959
using DeclIDField = BCFixed<31>;
@@ -927,9 +927,9 @@ namespace decls_block {
927927
BCFixed<1>, // implicit flag
928928
BCFixed<1>, // static?
929929
StaticSpellingKindField, // spelling of 'static' or 'class'
930-
BCVBR<3> // numpatterns
931-
932-
// The pattern trails the record.
930+
BCVBR<3>, // numpatterns
931+
BCArray<DeclContextIDField> // init contexts
932+
// The patterns and decl-contexts trail the record.
933933
>;
934934

935935
template <unsigned Code>

lib/AST/ASTContext.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,6 @@ struct ASTContext::Implementation {
259259
llvm::DenseMap<Decl *, std::pair<LazyMemberLoader *, uint64_t>>
260260
ConformanceLoaders;
261261

262-
/// \brief A cached unused pattern-binding initializer context.
263-
PatternBindingInitializer *UnusedPatternBindingContext = nullptr;
264-
265262
/// \brief A cached unused default-argument initializer context.
266263
DefaultArgumentInitializer *UnusedDefaultArgumentContext = nullptr;
267264

@@ -1563,22 +1560,6 @@ void ValueDecl::setLocalDiscriminator(unsigned index) {
15631560
getASTContext().Impl.LocalDiscriminators.insert({this, index});
15641561
}
15651562

1566-
PatternBindingInitializer *
1567-
ASTContext::createPatternBindingContext(DeclContext *parent) {
1568-
// Check for an existing context we can re-use.
1569-
if (auto existing = Impl.UnusedPatternBindingContext) {
1570-
Impl.UnusedPatternBindingContext = nullptr;
1571-
existing->reset(parent);
1572-
return existing;
1573-
}
1574-
1575-
return new (*this) PatternBindingInitializer(parent);
1576-
}
1577-
void ASTContext::destroyPatternBindingContext(PatternBindingInitializer *DC) {
1578-
// There isn't much value in caching more than one of these.
1579-
Impl.UnusedPatternBindingContext = DC;
1580-
}
1581-
15821563
DefaultArgumentInitializer *
15831564
ASTContext::createDefaultArgumentContext(DeclContext *fn, unsigned index) {
15841565
// Check for an existing context we can re-use.

lib/AST/ASTWalker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
150150
for (auto entry : PBD->getPatternList()) {
151151
++idx;
152152
if (Pattern *Pat = doIt(entry.getPattern()))
153-
PBD->setPattern(idx, Pat);
153+
PBD->setPattern(idx, Pat, entry.getInitContext());
154154
else
155155
return true;
156156
if (entry.getInit()) {

lib/AST/Decl.cpp

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -792,11 +792,11 @@ PatternBindingDecl::PatternBindingDecl(SourceLoc StaticLoc,
792792
unsigned NumPatternEntries,
793793
DeclContext *Parent)
794794
: Decl(DeclKind::PatternBinding, Parent),
795-
StaticLoc(StaticLoc), VarLoc(VarLoc),
796-
numPatternEntries(NumPatternEntries) {
795+
StaticLoc(StaticLoc), VarLoc(VarLoc) {
797796
PatternBindingDeclBits.IsStatic = StaticLoc.isValid();
798797
PatternBindingDeclBits.StaticSpelling =
799798
static_cast<unsigned>(StaticSpelling);
799+
PatternBindingDeclBits.NumPatternEntries = NumPatternEntries;
800800
}
801801

802802
PatternBindingDecl *
@@ -805,9 +805,18 @@ PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc,
805805
SourceLoc VarLoc,
806806
Pattern *Pat, Expr *E,
807807
DeclContext *Parent) {
808-
return create(Ctx, StaticLoc, StaticSpelling, VarLoc,
809-
PatternBindingEntry(Pat, E),
810-
Parent);
808+
DeclContext *BindingInitContext = nullptr;
809+
if (!Parent->isLocalContext())
810+
BindingInitContext = new (Ctx) PatternBindingInitializer(Parent);
811+
812+
auto Result = create(Ctx, StaticLoc, StaticSpelling, VarLoc,
813+
PatternBindingEntry(Pat, E, BindingInitContext),
814+
Parent);
815+
816+
if (BindingInitContext)
817+
cast<PatternBindingInitializer>(BindingInitContext)->setBinding(Result, 0);
818+
819+
return Result;
811820
}
812821

813822
PatternBindingDecl *
@@ -829,7 +838,31 @@ PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc,
829838
++elt;
830839
auto &newEntry = entries[elt];
831840
newEntry = pe; // This should take care of initializer with flags
832-
PBD->setPattern(elt, pe.getPattern());
841+
DeclContext *initContext = pe.getInitContext();
842+
if (!initContext && !Parent->isLocalContext()) {
843+
auto pbi = new (Ctx) PatternBindingInitializer(Parent);
844+
pbi->setBinding(PBD, elt);
845+
initContext = pbi;
846+
}
847+
848+
PBD->setPattern(elt, pe.getPattern(), initContext);
849+
}
850+
return PBD;
851+
}
852+
853+
PatternBindingDecl *PatternBindingDecl::createDeserialized(
854+
ASTContext &Ctx, SourceLoc StaticLoc,
855+
StaticSpellingKind StaticSpelling,
856+
SourceLoc VarLoc,
857+
unsigned NumPatternEntries,
858+
DeclContext *Parent) {
859+
size_t Size = totalSizeToAlloc<PatternBindingEntry>(NumPatternEntries);
860+
void *D = allocateMemoryForDecl<PatternBindingDecl>(Ctx, Size,
861+
/*ClangNode*/false);
862+
auto PBD = ::new (D) PatternBindingDecl(StaticLoc, StaticSpelling, VarLoc,
863+
NumPatternEntries, Parent);
864+
for (auto &entry : PBD->getMutablePatternList()) {
865+
entry = PatternBindingEntry(nullptr, nullptr, nullptr);
833866
}
834867
return PBD;
835868
}
@@ -924,9 +957,11 @@ bool PatternBindingDecl::hasStorage() const {
924957
return false;
925958
}
926959

927-
void PatternBindingDecl::setPattern(unsigned i, Pattern *P) {
960+
void PatternBindingDecl::setPattern(unsigned i, Pattern *P,
961+
DeclContext *InitContext) {
928962
auto PatternList = getMutablePatternList();
929963
PatternList[i].setPattern(P);
964+
PatternList[i].setInitContext(InitContext);
930965

931966
// Make sure that any VarDecl's contained within the pattern know about this
932967
// PatternBindingDecl as their parent.

lib/Parse/ParseDecl.cpp

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3974,10 +3974,6 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
39743974
// so we can build our singular PatternBindingDecl at the end.
39753975
SmallVector<PatternBindingEntry, 4> PBDEntries;
39763976

3977-
// The pattern binding initializer contexts, which have to be set up at the
3978-
// end.
3979-
SmallVector<PatternBindingInitializer *, 4> PBDInitContexts;
3980-
39813977
// No matter what error path we take, make sure the
39823978
// PatternBindingDecl/TopLevel code block are added.
39833979
SWIFT_DEFER {
@@ -3992,10 +3988,9 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
39923988
VarLoc, PBDEntries, CurDeclContext);
39933989

39943990
// Wire up any initializer contexts we needed.
3995-
assert(PBDInitContexts.size() == PBDEntries.size());
3996-
for (unsigned i : indices(PBDInitContexts)) {
3997-
auto initContext = PBDInitContexts[i];
3998-
if (initContext) initContext->setBinding(PBD, i);
3991+
for (unsigned i : indices(PBDEntries)) {
3992+
if (auto initContext = PBDEntries[i].getInitContext())
3993+
cast<PatternBindingInitializer>(initContext)->setBinding(PBD, i);
39993994
}
40003995

40013996
// If we're setting up a TopLevelCodeDecl, configure it by setting up the
@@ -4041,8 +4036,7 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
40414036

40424037
// Remember this pattern/init pair for our ultimate PatternBindingDecl. The
40434038
// Initializer will be added later when/if it is parsed.
4044-
PBDEntries.push_back({pattern, nullptr});
4045-
PBDInitContexts.push_back(nullptr);
4039+
PBDEntries.push_back({pattern, nullptr, nullptr});
40464040

40474041
Expr *PatternInit = nullptr;
40484042

@@ -4052,7 +4046,6 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
40524046
// into (should we have one). This happens for properties and global
40534047
// variables in libraries.
40544048
PatternBindingInitializer *initContext = nullptr;
4055-
bool usedInitContext = false;
40564049

40574050
// Record the variables that we're trying to initialize. This allows us
40584051
// to cleanly reject "var x = x" when "x" isn't bound to an enclosing
@@ -4072,7 +4065,7 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
40724065
// for the PBD we'll eventually create. This allows us to have reasonable
40734066
// DeclContexts for any closures that may live inside of initializers.
40744067
if (!CurDeclContext->isLocalContext() && !topLevelDecl && !initContext)
4075-
initContext = Context.createPatternBindingContext(CurDeclContext);
4068+
initContext = new (Context) PatternBindingInitializer(CurDeclContext);
40764069

40774070
// If we're using a local context (either a TopLevelCodeDecl or a
40784071
// PatternBindingContext) install it now so that CurDeclContext is set
@@ -4109,21 +4102,9 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
41094102
PatternInit = init.getPtrOrNull();
41104103
PBDEntries.back().setInit(PatternInit);
41114104

4112-
// If we allocated an initContext and the expression had a closure in it,
4113-
// we'll need to keep the initContext around.
4114-
if (initContext)
4115-
usedInitContext |= initParser->hasClosures();
4116-
41174105
// If we set up an initialization context for a property or module-level
4118-
// global, check to see if we needed it and wind it down.
4119-
if (initContext) {
4120-
// If we didn't need the context, "destroy" it, which recycles it for
4121-
// the next user.
4122-
if (!usedInitContext)
4123-
Context.destroyPatternBindingContext(initContext);
4124-
else
4125-
PBDInitContexts.back() = initContext;
4126-
}
4106+
// global, record it.
4107+
PBDEntries.back().setInitContext(initContext);
41274108

41284109
// If we are doing second pass of code completion, we don't want to
41294110
// suddenly cut off parsing and throw away the declaration.
@@ -4158,7 +4139,6 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
41584139
// into (should we have one). This happens for properties and global
41594140
// variables in libraries.
41604141
PatternBindingInitializer *initContext = nullptr;
4161-
bool usedInitContext = false;
41624142

41634143
// Record the variables that we're trying to set up. This allows us
41644144
// to cleanly reject "var x = x" when "x" isn't bound to an enclosing
@@ -4178,7 +4158,7 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
41784158
// This will be recontextualized to a method we synthesize during
41794159
// type checking.
41804160
if (!CurDeclContext->isLocalContext() && !topLevelDecl && !initContext)
4181-
initContext = Context.createPatternBindingContext(CurDeclContext);
4161+
initContext = new (Context) PatternBindingInitializer(CurDeclContext);
41824162
Optional<ParseFunctionBody> initParser;
41834163
Optional<ContextChange> topLevelParser;
41844164
if (topLevelDecl)
@@ -4188,10 +4168,7 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
41884168
initParser.emplace(*this, initContext);
41894169

41904170
auto closure = parseExprClosure();
4191-
if (initContext) {
4192-
usedInitContext = true;
4193-
PBDInitContexts.back() = initContext;
4194-
}
4171+
PBDEntries.back().setInitContext(initContext);
41954172

41964173
if (closure.isParseError())
41974174
return makeParserError();

0 commit comments

Comments
 (0)