[AST] Separate the DeclContexts for different pattern binding entries in a pattern binding decl.

This commit is contained in:
Doug Gregor
2016-09-01 15:27:52 -07:00
parent 4a24b069e0
commit 5e25d25c96
9 changed files with 83 additions and 42 deletions

View File

@@ -494,16 +494,19 @@ public:
/// deserialization.
class SerializedLocalDeclContext : public DeclContext {
private:
const LocalDeclContextKind LocalKind;
unsigned LocalKind : 3;
protected:
unsigned SpareBits : 29;
public:
SerializedLocalDeclContext(LocalDeclContextKind LocalKind,
DeclContext *Parent)
: DeclContext(DeclContextKind::SerializedLocal, Parent),
LocalKind(LocalKind) {}
LocalKind(static_cast<unsigned>(LocalKind)) {}
LocalDeclContextKind getLocalDeclContextKind() const {
return LocalKind;
return static_cast<LocalDeclContextKind>(LocalKind);
}
static bool classof(const DeclContext *DC) {

View File

@@ -80,16 +80,20 @@ public:
explicit PatternBindingInitializer(DeclContext *parent)
: Initializer(InitializerKind::PatternBinding, parent),
Binding(nullptr) {
SpareBits = 0;
}
void setBinding(PatternBindingDecl *binding) {
void setBinding(PatternBindingDecl *binding, unsigned bindingIndex) {
setParent(binding->getDeclContext());
Binding = binding;
SpareBits = bindingIndex;
}
PatternBindingDecl *getBinding() const { return Binding; }
unsigned getBindingIndex() const { return SpareBits; }
static bool classof(const DeclContext *DC) {
if (auto init = dyn_cast<Initializer>(DC))
return classof(init);
@@ -108,15 +112,21 @@ class SerializedPatternBindingInitializer : public SerializedLocalDeclContext {
PatternBindingDecl *Binding;
public:
SerializedPatternBindingInitializer(PatternBindingDecl *Binding)
SerializedPatternBindingInitializer(PatternBindingDecl *Binding,
unsigned bindingIndex)
: SerializedLocalDeclContext(LocalDeclContextKind::PatternBindingInitializer,
Binding->getDeclContext()),
Binding(Binding) {}
Binding(Binding) {
SpareBits = bindingIndex;
}
PatternBindingDecl *getBinding() const {
return Binding;
}
unsigned getBindingIndex() const { return SpareBits; }
static bool classof(const DeclContext *DC) {
if (auto LDC = dyn_cast<SerializedLocalDeclContext>(DC))
return LDC->getLocalDeclContextKind() ==

View File

@@ -53,7 +53,7 @@ const uint16_t VERSION_MAJOR = 0;
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
const uint16_t VERSION_MINOR = 264; // Last change: remove AllArchetypes
const uint16_t VERSION_MINOR = 265; // Last change: pattern binding initializer index
using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;
@@ -1306,7 +1306,8 @@ namespace decls_block {
using PatternBindingInitializerLayout = BCRecordLayout<
PATTERN_BINDING_INITIALIZER_CONTEXT,
DeclIDField // parent pattern binding decl
DeclIDField, // parent pattern binding decl
BCVBR<3> // binding index in the pattern binding decl
>;
using DefaultArgumentInitializerLayout = BCRecordLayout<

View File

@@ -722,7 +722,8 @@ unsigned DeclContext::printContext(raw_ostream &OS, unsigned indent) const {
switch (cast<Initializer>(this)->getInitializerKind()) {
case InitializerKind::PatternBinding: {
auto init = cast<PatternBindingInitializer>(this);
OS << " PatternBinding 0x" << (void*) init->getBinding();
OS << " PatternBinding 0x" << (void*) init->getBinding()
<< " #" << init->getBindingIndex();
break;
}
case InitializerKind::DefaultArgument: {
@@ -748,7 +749,8 @@ unsigned DeclContext::printContext(raw_ostream &OS, unsigned indent) const {
}
case LocalDeclContextKind::PatternBindingInitializer: {
auto init = cast<SerializedPatternBindingInitializer>(local);
OS << " PatternBinding 0x" << (void*) init->getBinding();
OS << " PatternBinding 0x" << (void*) init->getBinding()
<< " #" << init->getBindingIndex();
break;
}
case LocalDeclContextKind::TopLevelCodeDecl:

View File

@@ -3965,12 +3965,6 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
topLevelDecl = new (Context) TopLevelCodeDecl(CurDeclContext);
}
// If we're not in a local context, we'll need a context to parse initializers
// into (should we have one). This happens for properties and global
// variables in libraries.
PatternBindingInitializer *initContext = nullptr;
bool usedInitContext = false;
bool HasAccessors = false; // Syntactically has accessor {}'s.
ParserStatus Status;
@@ -3980,6 +3974,10 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
// so we can build our singular PatternBindingDecl at the end.
SmallVector<PatternBindingEntry, 4> PBDEntries;
// The pattern binding initializer contexts, which have to be set up at the
// end.
SmallVector<PatternBindingInitializer *, 4> PBDInitContexts;
// No matter what error path we take, make sure the
// PatternBindingDecl/TopLevel code block are added.
SWIFT_DEFER {
@@ -3993,12 +3991,17 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
auto PBD = PatternBindingDecl::create(Context, StaticLoc, StaticSpelling,
VarLoc, PBDEntries, CurDeclContext);
// Wire up any initializer contexts we needed.
assert(PBDInitContexts.size() == PBDEntries.size());
for (unsigned i : indices(PBDInitContexts)) {
auto initContext = PBDInitContexts[i];
if (initContext) initContext->setBinding(PBD, i);
}
// If we're setting up a TopLevelCodeDecl, configure it by setting up the
// body that holds PBD and we're done. The TopLevelCodeDecl is already set
// up in Decls to be returned to caller.
if (topLevelDecl) {
assert(!initContext &&
"Shouldn't need an initcontext: TopLevelCode is a local context!");
PBD->setDeclContext(topLevelDecl);
auto range = PBD->getSourceRange();
topLevelDecl->setBody(BraceStmt::create(Context, range.Start,
@@ -4007,17 +4010,6 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
return;
}
// If we set up an initialization context for a property or module-level
// global, check to see if we needed it and wind it down.
if (initContext) {
// If we didn't need the context, "destroy" it, which recycles it for
// the next user.
if (!usedInitContext)
Context.destroyPatternBindingContext(initContext);
else
initContext->setBinding(PBD);
}
// Otherwise return the PBD in "Decls" to the caller. We add it at a
// specific spot to get it in before any accessors, which SILGen seems to
// want.
@@ -4050,11 +4042,18 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
// Remember this pattern/init pair for our ultimate PatternBindingDecl. The
// Initializer will be added later when/if it is parsed.
PBDEntries.push_back({pattern, nullptr});
PBDInitContexts.push_back(nullptr);
Expr *PatternInit = nullptr;
// Parse an initializer if present.
if (Tok.is(tok::equal)) {
// If we're not in a local context, we'll need a context to parse initializers
// into (should we have one). This happens for properties and global
// variables in libraries.
PatternBindingInitializer *initContext = nullptr;
bool usedInitContext = false;
// Record the variables that we're trying to initialize. This allows us
// to cleanly reject "var x = x" when "x" isn't bound to an enclosing
// decl (even though names aren't injected into scope when the initializer
@@ -4115,6 +4114,17 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
if (initContext)
usedInitContext |= initParser->hasClosures();
// If we set up an initialization context for a property or module-level
// global, check to see if we needed it and wind it down.
if (initContext) {
// If we didn't need the context, "destroy" it, which recycles it for
// the next user.
if (!usedInitContext)
Context.destroyPatternBindingContext(initContext);
else
PBDInitContexts.back() = initContext;
}
// If we are doing second pass of code completion, we don't want to
// suddenly cut off parsing and throw away the declaration.
if (init.hasCodeCompletion() && isCodeCompletionFirstPass()) {
@@ -4144,6 +4154,12 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
// FIXME: Handle generalized parameters.
Expr *paramExpr = nullptr;
if (Tok.is(tok::l_brace)) {
// If we're not in a local context, we'll need a context to parse initializers
// into (should we have one). This happens for properties and global
// variables in libraries.
PatternBindingInitializer *initContext = nullptr;
bool usedInitContext = false;
// Record the variables that we're trying to set up. This allows us
// to cleanly reject "var x = x" when "x" isn't bound to an enclosing
// decl (even though names aren't injected into scope when the parameter
@@ -4172,7 +4188,11 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags,
initParser.emplace(*this, initContext);
auto closure = parseExprClosure();
if (initContext) {
usedInitContext = true;
PBDInitContexts.back() = initContext;
}
if (closure.isParseError())
return makeParserError();
if (closure.hasCodeCompletion())

View File

@@ -1930,7 +1930,7 @@ bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
// If we didn't find one, create it.
if (!initContext) {
initContext = Context.createPatternBindingContext(DC);
initContext->setBinding(PBD);
initContext->setBinding(PBD, patternNumber);
initContextIsNew = true;
}
DC = initContext;

View File

@@ -1507,13 +1507,15 @@ DeclContext *ModuleFile::getLocalDeclContext(DeclContextID DCID) {
case decls_block::PATTERN_BINDING_INITIALIZER_CONTEXT: {
DeclID bindingID;
uint32_t bindingIndex;
decls_block::PatternBindingInitializerLayout::readRecord(scratch,
bindingID);
bindingID,
bindingIndex);
auto decl = getDecl(bindingID);
PatternBindingDecl *binding = cast<PatternBindingDecl>(decl);
declContextOrOffset = new (ctx)
SerializedPatternBindingInitializer(binding);
SerializedPatternBindingInitializer(binding, bindingIndex);
break;
}

View File

@@ -1845,11 +1845,13 @@ void Serializer::writeDeclContext(const DeclContext *DC) {
declOrDeclContextID, isDecl);
}
void Serializer::writePatternBindingInitializer(PatternBindingDecl *binding) {
void Serializer::writePatternBindingInitializer(PatternBindingDecl *binding,
unsigned bindingIndex) {
using namespace decls_block;
auto abbrCode = DeclTypeAbbrCodes[PatternBindingInitializerLayout::Code];
PatternBindingInitializerLayout::emitRecord(Out, ScratchRecord,
abbrCode, addDeclRef(binding));
abbrCode, addDeclRef(binding),
bindingIndex);
}
void
@@ -1896,7 +1898,7 @@ void Serializer::writeLocalDeclContext(const DeclContext *DC) {
case DeclContextKind::Initializer: {
if (auto PBI = dyn_cast<PatternBindingInitializer>(DC)) {
writePatternBindingInitializer(PBI->getBinding());
writePatternBindingInitializer(PBI->getBinding(), PBI->getBindingIndex());
} else if (auto DAI = dyn_cast<DefaultArgumentInitializer>(DC)) {
writeDefaultArgumentInitializer(DAI->getParent(), DAI->getIndex());
}
@@ -1928,7 +1930,7 @@ void Serializer::writeLocalDeclContext(const DeclContext *DC) {
}
case LocalDeclContextKind::PatternBindingInitializer: {
auto PBI = cast<SerializedPatternBindingInitializer>(local);
writePatternBindingInitializer(PBI->getBinding());
writePatternBindingInitializer(PBI->getBinding(), PBI->getBindingIndex());
return;
}
case LocalDeclContextKind::TopLevelCodeDecl: {

View File

@@ -293,7 +293,8 @@ private:
void writeLocalDeclContext(const DeclContext *DC);
/// Write the components of a PatternBindingInitializer as a local context.
void writePatternBindingInitializer(PatternBindingDecl *binding);
void writePatternBindingInitializer(PatternBindingDecl *binding,
unsigned bindingIndex);
/// Write the components of a DefaultArgumentInitializer as a local context.
void writeDefaultArgumentInitializer(const DeclContext *parentContext, unsigned index);