Skip to content

Refactor delayed member parsing and fix a bug #21879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions include/swift/Frontend/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -614,8 +614,7 @@ class CompilerInstance {

private:
void createREPLFile(const ImplicitImports &implicitImports);
std::unique_ptr<DelayedParsingCallbacks>
computeDelayedParsingCallback(bool isPrimary);
std::unique_ptr<DelayedParsingCallbacks> computeDelayedParsingCallback();

void addMainFileToModule(const ImplicitImports &implicitImports);

Expand All @@ -626,15 +625,13 @@ class CompilerInstance {
void parseLibraryFile(unsigned BufferID,
const ImplicitImports &implicitImports,
PersistentParserState &PersistentState,
DelayedParsingCallbacks *PrimaryDelayedCB,
DelayedParsingCallbacks *SecondaryDelayedCB);
DelayedParsingCallbacks *DelayedCB);

/// Return true if had load error
bool
parsePartialModulesAndLibraryFiles(const ImplicitImports &implicitImports,
PersistentParserState &PersistentState,
DelayedParsingCallbacks *PrimaryDelayedCB,
DelayedParsingCallbacks *SecondaryDelayedCB);
DelayedParsingCallbacks *DelayedCB);

OptionSet<TypeCheckingFlags> computeTypeCheckingOptions();

Expand Down
9 changes: 0 additions & 9 deletions include/swift/Parse/DelayedParsingCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,6 @@ class DelayedParsingCallbacks {
SourceRange BodyRange) = 0;
};

class AlwaysDelayedCallbacks : public DelayedParsingCallbacks {
bool shouldDelayFunctionBodyParsing(Parser &TheParser,
AbstractFunctionDecl *AFD,
const DeclAttributes &Attrs,
SourceRange BodyRange) override {
return true;
}
};

/// Implementation of callbacks that guide the parser in delayed
/// parsing for code completion.
class CodeCompleteDelayedCallbacks : public DelayedParsingCallbacks {
Expand Down
32 changes: 23 additions & 9 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,9 @@ class Parser {

DelayedParsingCallbacks *DelayedParseCB = nullptr;

bool isDelayedParsingEnabled() const { return DelayedParseCB != nullptr; }
bool isDelayedParsingEnabled() const {
return DelayBodyParsing || DelayedParseCB != nullptr;
}

void setDelayedParsingCallbacks(DelayedParsingCallbacks *DelayedParseCB) {
this->DelayedParseCB = DelayedParseCB;
Expand Down Expand Up @@ -207,8 +209,15 @@ class Parser {
/// Always empty if !SF.shouldBuildSyntaxTree().
ParsedTrivia TrailingTrivia;

/// Whether we should disable delayed parsing.
bool DisableDelayedParsing;
/// Whether we should delay parsing nominal type and extension bodies,
/// and skip function bodies.
///
/// This is false in primary files, since we want to type check all
/// declarations and function bodies.
///
/// This is true for non-primary files, where declarations only need to be
/// lazily parsed and type checked.
bool DelayBodyParsing;

/// The receiver to collect all consumed tokens.
ConsumeTokenReceiver *TokReceiver;
Expand Down Expand Up @@ -357,16 +366,16 @@ class Parser {
SILParserTUStateBase *SIL,
PersistentParserState *PersistentState,
std::shared_ptr<SyntaxParseActions> SPActions = nullptr,
bool DisableDelayedParsing = false);
bool DelayBodyParsing = true);
Parser(unsigned BufferID, SourceFile &SF, SILParserTUStateBase *SIL,
PersistentParserState *PersistentState = nullptr,
std::shared_ptr<SyntaxParseActions> SPActions = nullptr,
bool DisableDelayedParsing = false);
bool DelayBodyParsing = true);
Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF,
SILParserTUStateBase *SIL = nullptr,
PersistentParserState *PersistentState = nullptr,
std::shared_ptr<SyntaxParseActions> SPActions = nullptr,
bool DisableDelayedParsing = false);
bool DelayBodyParsing = true);
~Parser();

bool isInSILMode() const { return SIL != nullptr; }
Expand Down Expand Up @@ -798,6 +807,13 @@ class Parser {

void parseDeclListDelayed(IterableDeclContext *IDC);

bool canDelayMemberDeclParsing();

bool delayParsingDeclList(SourceLoc LBLoc, SourceLoc &RBLoc,
SourceLoc PosBeforeLB,
ParseDeclOptions Options,
IterableDeclContext *IDC);

ParserResult<TypeDecl> parseDeclTypeAlias(ParseDeclOptions Flags,
DeclAttributes &Attributes);

Expand Down Expand Up @@ -894,7 +910,7 @@ class Parser {
llvm::function_ref<void(Decl*)> handler);
bool parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc,
Diag<> ErrorDiag, ParseDeclOptions Options,
llvm::function_ref<void(Decl*)> handler);
IterableDeclContext *IDC);
ParserResult<ExtensionDecl> parseDeclExtension(ParseDeclOptions Flags,
DeclAttributes &Attributes);
ParserResult<EnumDecl> parseDeclEnum(ParseDeclOptions Flags,
Expand Down Expand Up @@ -1428,8 +1444,6 @@ class Parser {
parsePlatformVersionConstraintSpec();
ParserResult<PlatformAgnosticVersionConstraintAvailabilitySpec>
parsePlatformAgnosticVersionConstraintSpec();

bool canDelayMemberDeclParsing();
};

/// Describes a parsed declaration name.
Expand Down
4 changes: 2 additions & 2 deletions include/swift/Subsystems.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ namespace swift {
SILParserState *SIL = nullptr,
PersistentParserState *PersistentState = nullptr,
DelayedParsingCallbacks *DelayedParseCB = nullptr,
bool DisableDelayedParsing = false);
bool DelayBodyParsing = true);

/// Parse a single buffer into the given source file, until the full source
/// contents are parsed.
Expand All @@ -131,7 +131,7 @@ namespace swift {
bool parseIntoSourceFileFull(SourceFile &SF, unsigned BufferID,
PersistentParserState *PersistentState = nullptr,
DelayedParsingCallbacks *DelayedParseCB = nullptr,
bool DisableDelayedParsing = false);
bool DelayBodyParsing = true);

/// Finish the parsing by going over the nodes that were delayed
/// during the first parsing pass.
Expand Down
1 change: 0 additions & 1 deletion lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3547,7 +3547,6 @@ void ClassDecl::addImplicitDestructor() {
// Create an empty body for the destructor.
DD->setBody(BraceStmt::create(ctx, getLoc(), { }, getLoc(), true));
addMember(DD);
setHasDestructor();

// Propagate access control and versioned-ness.
DD->copyFormalAccessFrom(this, /*sourceIsParentContext*/true);
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,11 @@ void MemberLookupTable::updateLookupTable(NominalTypeDecl *nominal) {
}

void NominalTypeDecl::addedMember(Decl *member) {
// Remember if we added a destructor.
if (auto *CD = dyn_cast<ClassDecl>(this))
if (isa<DestructorDecl>(member))
CD->setHasDestructor();

// If we have a lookup table, add the new member to it.
if (LookupTable.getPointer()) {
LookupTable.getPointer()->addMember(member);
Expand Down
43 changes: 16 additions & 27 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,12 +735,10 @@ void CompilerInstance::createREPLFile(const ImplicitImports &implicitImports) {
}

std::unique_ptr<DelayedParsingCallbacks>
CompilerInstance::computeDelayedParsingCallback(bool isPrimary) {
CompilerInstance::computeDelayedParsingCallback() {
if (Invocation.isCodeCompletion())
return llvm::make_unique<CodeCompleteDelayedCallbacks>(
SourceMgr.getCodeCompletionLoc());
if (!isPrimary)
return llvm::make_unique<AlwaysDelayedCallbacks>();
return nullptr;
}

Expand All @@ -754,22 +752,13 @@ void CompilerInstance::addMainFileToModule(
void CompilerInstance::parseAndCheckTypesUpTo(
const ImplicitImports &implicitImports, SourceFile::ASTStage_t limitStage) {
FrontendStatsTracer tracer(Context->Stats, "parse-and-check-types");
// Delayed parsing callback for the primary file, or all files
// in non-WMO mode.
std::unique_ptr<DelayedParsingCallbacks> PrimaryDelayedCB{
computeDelayedParsingCallback(true)};

// Delayed parsing callback for non-primary files. Not used in
// WMO mode.
std::unique_ptr<DelayedParsingCallbacks> SecondaryDelayedCB{
computeDelayedParsingCallback(false)};
std::unique_ptr<DelayedParsingCallbacks> DelayedCB{
computeDelayedParsingCallback()};

PersistentParserState PersistentState(getASTContext());

bool hadLoadError = parsePartialModulesAndLibraryFiles(
implicitImports, PersistentState,
PrimaryDelayedCB.get(),
SecondaryDelayedCB.get());
implicitImports, PersistentState, DelayedCB.get());
if (Invocation.isCodeCompletion()) {
// When we are doing code completion, make sure to emit at least one
// diagnostic, so that ASTContext is marked as erroneous. In this case
Expand All @@ -788,7 +777,7 @@ void CompilerInstance::parseAndCheckTypesUpTo(
// interwined.
if (MainBufferID != NO_SUCH_BUFFER) {
parseAndTypeCheckMainFileUpTo(limitStage, PersistentState,
PrimaryDelayedCB.get(), TypeCheckOptions);
DelayedCB.get(), TypeCheckOptions);
}

assert(llvm::all_of(MainModule->getFiles(), [](const FileUnit *File) -> bool {
Expand Down Expand Up @@ -829,16 +818,14 @@ void CompilerInstance::parseAndCheckTypesUpTo(
void CompilerInstance::parseLibraryFile(
unsigned BufferID, const ImplicitImports &implicitImports,
PersistentParserState &PersistentState,
DelayedParsingCallbacks *PrimaryDelayedCB,
DelayedParsingCallbacks *SecondaryDelayedCB) {
DelayedParsingCallbacks *DelayedCB) {
FrontendStatsTracer tracer(Context->Stats, "parse-library-file");

auto *NextInput = createSourceFileForMainModule(
SourceFileKind::Library, implicitImports.kind, BufferID);
addAdditionalInitialImportsTo(NextInput, implicitImports);

auto IsPrimary = isWholeModuleCompilation() || isPrimaryInput(BufferID);
auto *DelayedCB = IsPrimary ? PrimaryDelayedCB : SecondaryDelayedCB;

auto &Diags = NextInput->getASTContext().Diags;
auto DidSuppressWarnings = Diags.getSuppressWarnings();
Expand All @@ -849,7 +836,7 @@ void CompilerInstance::parseLibraryFile(
// Parser may stop at some erroneous constructions like #else, #endif
// or '}' in some cases, continue parsing until we are done
parseIntoSourceFile(*NextInput, BufferID, &Done, nullptr, &PersistentState,
DelayedCB);
DelayedCB, /*DelayedBodyParsing=*/!IsPrimary);
} while (!Done);

Diags.setSuppressWarnings(DidSuppressWarnings);
Expand Down Expand Up @@ -878,8 +865,7 @@ OptionSet<TypeCheckingFlags> CompilerInstance::computeTypeCheckingOptions() {
bool CompilerInstance::parsePartialModulesAndLibraryFiles(
const ImplicitImports &implicitImports,
PersistentParserState &PersistentState,
DelayedParsingCallbacks *PrimaryDelayedCB,
DelayedParsingCallbacks *SecondaryDelayedCB) {
DelayedParsingCallbacks *DelayedCB) {
FrontendStatsTracer tracer(Context->Stats,
"parse-partial-modules-and-library-files");
bool hadLoadError = false;
Expand All @@ -894,8 +880,7 @@ bool CompilerInstance::parsePartialModulesAndLibraryFiles(
// Then parse all the library files.
for (auto BufferID : InputSourceCodeBufferIDs) {
if (BufferID != MainBufferID) {
parseLibraryFile(BufferID, implicitImports, PersistentState,
PrimaryDelayedCB, SecondaryDelayedCB);
parseLibraryFile(BufferID, implicitImports, PersistentState, DelayedCB);
}
}
return hadLoadError;
Expand Down Expand Up @@ -928,7 +913,7 @@ void CompilerInstance::parseAndTypeCheckMainFileUpTo(
// with 'sil' definitions.
parseIntoSourceFile(MainFile, MainFile.getBufferID().getValue(), &Done,
TheSILModule ? &SILContext : nullptr, &PersistentState,
DelayedParseCB);
DelayedParseCB, /*DelayedBodyParsing=*/false);

if (mainIsPrimary && (Done || CurTUElem < MainFile.Decls.size())) {
switch (LimitStage) {
Expand Down Expand Up @@ -1055,11 +1040,14 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals,
if (BufferID == MainBufferID)
continue;

auto IsPrimary = isWholeModuleCompilation() || isPrimaryInput(BufferID);

SourceFile *NextInput = createSourceFileForMainModule(
SourceFileKind::Library, SourceFile::ImplicitModuleImportKind::None,
BufferID);

parseIntoSourceFileFull(*NextInput, BufferID, &PersistentState);
parseIntoSourceFileFull(*NextInput, BufferID, &PersistentState,
nullptr, /*DelayBodyParsing=*/!IsPrimary);
}

// Now parse the main file.
Expand All @@ -1069,7 +1057,8 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals,
MainFile.SyntaxParsingCache = Invocation.getMainFileSyntaxParsingCache();

parseIntoSourceFileFull(MainFile, MainFile.getBufferID().getValue(),
&PersistentState);
&PersistentState, nullptr,
/*DelayBodyParsing=*/false);
}

assert(Context->LoadedModules.size() == 1 &&
Expand Down
Loading