Skip to content

Commit 92ba948

Browse files
authored
Merge pull request swiftlang#30166 from hamishknight/three-flags
Move parsing flags onto SourceFile
2 parents 8191aa4 + ea16419 commit 92ba948

File tree

19 files changed

+196
-114
lines changed

19 files changed

+196
-114
lines changed

include/swift/AST/SourceFile.h

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,36 @@ class SourceFile final : public FileUnit {
9090
}
9191
};
9292

93+
/// Flags that direct how the source file is parsed.
94+
enum class ParsingFlags : uint8_t {
95+
/// Whether to disable delayed parsing for nominal type, extension, and
96+
/// function bodies.
97+
///
98+
/// If set, type and function bodies will be parsed eagerly. Otherwise they
99+
/// will be lazily parsed when their contents is queried. This lets us avoid
100+
/// building AST nodes when they're not needed.
101+
///
102+
/// This is set for primary files, since we want to type check all
103+
/// declarations and function bodies anyway, so there's no benefit in lazy
104+
/// parsing.
105+
DisableDelayedBodies = 1 << 0,
106+
107+
/// Whether to disable evaluating the conditions of #if decls.
108+
///
109+
/// If set, #if decls are parsed as-is. Otherwise, the bodies of any active
110+
/// clauses are hoisted such that they become sibling nodes with the #if
111+
/// decl.
112+
///
113+
/// FIXME: When condition evaluation moves to a later phase, remove this
114+
/// and adjust the client call 'performParseOnly'.
115+
DisablePoundIfEvaluation = 1 << 1,
116+
117+
/// Whether to suppress warnings when parsing. This is set for secondary
118+
/// files, as they get parsed multiple times.
119+
SuppressWarnings = 1 << 2
120+
};
121+
using ParsingOptions = OptionSet<ParsingFlags>;
122+
93123
private:
94124
std::unique_ptr<SourceLookupCache> Cache;
95125
SourceLookupCache &getCache() const;
@@ -132,6 +162,9 @@ class SourceFile final : public FileUnit {
132162
/// If not, we can fast-path module checks.
133163
bool HasImplementationOnlyImports = false;
134164

165+
/// The parsing options for the file.
166+
ParsingOptions ParsingOpts;
167+
135168
/// The scope map that describes this source file.
136169
std::unique_ptr<ASTScope> Scope;
137170

@@ -196,6 +229,9 @@ class SourceFile final : public FileUnit {
196229
Decls.resize(count);
197230
}
198231

232+
/// Retrieve the parsing options for the file.
233+
ParsingOptions getParsingOptions() const { return ParsingOpts; }
234+
199235
/// A cache of syntax nodes that can be reused when creating the syntax tree
200236
/// for this file.
201237
swift::SyntaxParsingCache *SyntaxParsingCache = nullptr;
@@ -270,7 +306,7 @@ class SourceFile final : public FileUnit {
270306

271307
SourceFile(ModuleDecl &M, SourceFileKind K, Optional<unsigned> bufferID,
272308
ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens = false,
273-
bool KeepSyntaxTree = false);
309+
bool KeepSyntaxTree = false, ParsingOptions parsingOpts = {});
274310

275311
~SourceFile();
276312

@@ -533,6 +569,10 @@ class SourceFile final : public FileUnit {
533569

534570
bool isSuitableForASTScopes() const { return canBeParsedInFull(); }
535571

572+
/// Whether the bodies of types and functions within this file can be lazily
573+
/// parsed.
574+
bool hasDelayedBodyParsing() const;
575+
536576
syntax::SourceFileSyntax getSyntaxRoot() const;
537577
void setSyntaxRoot(syntax::SourceFileSyntax &&Root);
538578
bool hasSyntaxRoot() const;
@@ -556,6 +596,11 @@ class SourceFile final : public FileUnit {
556596
std::unique_ptr<SourceFileSyntaxInfo> SyntaxInfo;
557597
};
558598

599+
inline SourceFile::ParsingOptions operator|(SourceFile::ParsingFlags lhs,
600+
SourceFile::ParsingFlags rhs) {
601+
return SourceFile::ParsingOptions(lhs) | rhs;
602+
}
603+
559604
inline SourceFile &
560605
ModuleDecl::getMainSourceFile(SourceFileKind expectedKind) const {
561606
assert(!Files.empty() && "No files added yet");

include/swift/Frontend/Frontend.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,8 @@ class CompilerInstance {
632632
SourceFile *
633633
createSourceFileForMainModule(SourceFileKind FileKind,
634634
SourceFile::ImplicitModuleImportKind ImportKind,
635-
Optional<unsigned> BufferID);
635+
Optional<unsigned> BufferID,
636+
SourceFile::ParsingOptions options = {});
636637

637638
public:
638639
void freeASTContext();

include/swift/Parse/Parser.h

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,14 @@ class Parser {
173173

174174
LocalContext *CurLocalContext = nullptr;
175175

176-
bool isDelayedParsingEnabled() const {
177-
return DelayBodyParsing || isCodeCompletionFirstPass();
178-
}
176+
/// Whether we should delay parsing nominal type, extension, and function
177+
/// bodies.
178+
bool isDelayedParsingEnabled() const;
179+
180+
/// Whether to evaluate the conditions of #if decls, meaning that the bodies
181+
/// of any active clauses are hoisted such that they become sibling nodes with
182+
/// the #if decl.
183+
bool shouldEvaluatePoundIfDecls() const;
179184

180185
void setCodeCompletionCallbacks(CodeCompletionCallbacks *Callbacks) {
181186
CodeCompletion = Callbacks;
@@ -213,23 +218,6 @@ class Parser {
213218
/// Always empty if !SF.shouldBuildSyntaxTree().
214219
ParsedTrivia TrailingTrivia;
215220

216-
/// Whether we should delay parsing nominal type and extension bodies,
217-
/// and skip function bodies.
218-
///
219-
/// This is false in primary files, since we want to type check all
220-
/// declarations and function bodies.
221-
///
222-
/// This is true for non-primary files, where declarations only need to be
223-
/// lazily parsed and type checked.
224-
bool DelayBodyParsing;
225-
226-
/// Whether to evaluate the conditions of #if decls, meaning that the bodies
227-
/// of any active clauses are hoisted such that they become sibling nodes with
228-
/// the #if decl.
229-
// FIXME: When condition evaluation moves to a later phase, remove this bit
230-
// and adjust the client call 'performParseOnly'.
231-
bool EvaluateConditionals;
232-
233221
/// The receiver to collect all consumed tokens.
234222
ConsumeTokenReceiver *TokReceiver;
235223

@@ -407,17 +395,14 @@ class Parser {
407395
Parser(unsigned BufferID, SourceFile &SF, DiagnosticEngine* LexerDiags,
408396
SILParserTUStateBase *SIL,
409397
PersistentParserState *PersistentState,
410-
std::shared_ptr<SyntaxParseActions> SPActions = nullptr,
411-
bool DelayBodyParsing = true, bool EvaluateConditionals = true);
398+
std::shared_ptr<SyntaxParseActions> SPActions = nullptr);
412399
Parser(unsigned BufferID, SourceFile &SF, SILParserTUStateBase *SIL,
413400
PersistentParserState *PersistentState = nullptr,
414-
std::shared_ptr<SyntaxParseActions> SPActions = nullptr,
415-
bool DelayBodyParsing = true, bool EvaluateConditionals = true);
401+
std::shared_ptr<SyntaxParseActions> SPActions = nullptr);
416402
Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF,
417403
SILParserTUStateBase *SIL = nullptr,
418404
PersistentParserState *PersistentState = nullptr,
419-
std::shared_ptr<SyntaxParseActions> SPActions = nullptr,
420-
bool DelayBodyParsing = true, bool EvaluateConditionals = true);
405+
std::shared_ptr<SyntaxParseActions> SPActions = nullptr);
421406
~Parser();
422407

423408
/// Returns true if the buffer being parsed is allowed to contain SIL.

include/swift/Subsystems.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,7 @@ namespace swift {
108108
/// \param SF The file within the module being parsed.
109109
///
110110
/// \param BufferID The buffer to parse from.
111-
///
112-
/// \param DelayBodyParsing Whether parsing of type and function bodies can be
113-
/// delayed.
114-
void parseIntoSourceFile(SourceFile &SF, unsigned BufferID,
115-
bool DelayBodyParsing = true,
116-
bool EvaluateConditionals = true);
111+
void parseIntoSourceFile(SourceFile &SF, unsigned BufferID);
117112

118113
/// Parse a source file's SIL declarations into a given SIL module.
119114
void parseSourceFileSIL(SourceFile &SF, SILParserState *sil);

lib/AST/Module.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,10 +1896,11 @@ static void performAutoImport(
18961896
SourceFile::SourceFile(ModuleDecl &M, SourceFileKind K,
18971897
Optional<unsigned> bufferID,
18981898
ImplicitModuleImportKind ModImpKind,
1899-
bool KeepParsedTokens, bool BuildSyntaxTree)
1900-
: FileUnit(FileUnitKind::Source, M),
1901-
BufferID(bufferID ? *bufferID : -1),
1902-
Kind(K), SyntaxInfo(new SourceFileSyntaxInfo(BuildSyntaxTree)) {
1899+
bool KeepParsedTokens, bool BuildSyntaxTree,
1900+
ParsingOptions parsingOpts)
1901+
: FileUnit(FileUnitKind::Source, M), BufferID(bufferID ? *bufferID : -1),
1902+
ParsingOpts(parsingOpts), Kind(K),
1903+
SyntaxInfo(new SourceFileSyntaxInfo(BuildSyntaxTree)) {
19031904
M.getASTContext().addDestructorCleanup(*this);
19041905
performAutoImport(*this, ModImpKind);
19051906

@@ -1953,6 +1954,23 @@ bool SourceFile::canBeParsedInFull() const {
19531954
llvm_unreachable("unhandled kind");
19541955
}
19551956

1957+
bool SourceFile::hasDelayedBodyParsing() const {
1958+
if (ParsingOpts.contains(ParsingFlags::DisableDelayedBodies))
1959+
return false;
1960+
1961+
// Not supported right now.
1962+
if (Kind == SourceFileKind::REPL || Kind == SourceFileKind::SIL)
1963+
return false;
1964+
if (hasInterfaceHash())
1965+
return false;
1966+
if (shouldCollectToken())
1967+
return false;
1968+
if (shouldBuildSyntaxTree())
1969+
return false;
1970+
1971+
return true;
1972+
}
1973+
19561974
bool FileUnit::walk(ASTWalker &walker) {
19571975
SmallVector<Decl *, 64> Decls;
19581976
getTopLevelDecls(Decls);

lib/Frontend/Frontend.cpp

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -970,16 +970,7 @@ void CompilerInstance::parseLibraryFile(
970970
SourceFileKind::Library, implicitImports.kind, BufferID);
971971
addAdditionalInitialImportsTo(NextInput, implicitImports);
972972

973-
auto IsPrimary = isWholeModuleCompilation() || isPrimaryInput(BufferID);
974-
975-
auto &Diags = NextInput->getASTContext().Diags;
976-
auto DidSuppressWarnings = Diags.getSuppressWarnings();
977-
Diags.setSuppressWarnings(DidSuppressWarnings || !IsPrimary);
978-
979-
parseIntoSourceFile(*NextInput, BufferID, /*DelayedBodyParsing=*/!IsPrimary);
980-
981-
Diags.setSuppressWarnings(DidSuppressWarnings);
982-
973+
parseIntoSourceFile(*NextInput, BufferID);
983974
performNameBinding(*NextInput);
984975
}
985976

@@ -1023,8 +1014,7 @@ void CompilerInstance::parseAndTypeCheckMainFileUpTo(
10231014
Diags.setSuppressWarnings(DidSuppressWarnings || !mainIsPrimary);
10241015

10251016
// Parse the Swift decls into the source file.
1026-
parseIntoSourceFile(MainFile, MainBufferID,
1027-
/*delayBodyParsing*/ !mainIsPrimary);
1017+
parseIntoSourceFile(MainFile, MainBufferID);
10281018

10291019
// For a primary, also perform type checking if needed. Otherwise, just do
10301020
// name binding.
@@ -1081,17 +1071,27 @@ void CompilerInstance::finishTypeChecking() {
10811071

10821072
SourceFile *CompilerInstance::createSourceFileForMainModule(
10831073
SourceFileKind fileKind, SourceFile::ImplicitModuleImportKind importKind,
1084-
Optional<unsigned> bufferID) {
1074+
Optional<unsigned> bufferID, SourceFile::ParsingOptions opts) {
10851075
ModuleDecl *mainModule = getMainModule();
1076+
1077+
auto isPrimary = bufferID && isPrimaryInput(*bufferID);
1078+
if (isPrimary || isWholeModuleCompilation()) {
1079+
// Disable delayed body parsing for primaries.
1080+
opts |= SourceFile::ParsingFlags::DisableDelayedBodies;
1081+
} else {
1082+
// Suppress parse warnings for non-primaries, as they'll get parsed multiple
1083+
// times.
1084+
opts |= SourceFile::ParsingFlags::SuppressWarnings;
1085+
}
1086+
10861087
SourceFile *inputFile = new (*Context)
10871088
SourceFile(*mainModule, fileKind, bufferID, importKind,
10881089
Invocation.getLangOptions().CollectParsedToken,
1089-
Invocation.getLangOptions().BuildSyntaxTree);
1090+
Invocation.getLangOptions().BuildSyntaxTree, opts);
10901091
MainModule->addFile(*inputFile);
10911092

1092-
if (bufferID && isPrimaryInput(*bufferID)) {
1093+
if (isPrimary)
10931094
recordPrimarySourceFile(inputFile);
1094-
}
10951095

10961096
if (bufferID == SourceMgr.getCodeCompletionBufferID()) {
10971097
assert(!CodeCompletionFile && "Multiple code completion files?");
@@ -1113,35 +1113,32 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals,
11131113
"only supports parsing .swift files");
11141114
(void)Kind;
11151115

1116+
SourceFile::ParsingOptions parsingOpts;
1117+
if (!EvaluateConditionals)
1118+
parsingOpts |= SourceFile::ParsingFlags::DisablePoundIfEvaluation;
1119+
if (!CanDelayBodies)
1120+
parsingOpts |= SourceFile::ParsingFlags::DisableDelayedBodies;
1121+
11161122
// Make sure the main file is the first file in the module but parse it last,
11171123
// to match the parsing logic used when performing Sema.
11181124
if (MainBufferID != NO_SUCH_BUFFER) {
11191125
assert(Kind == InputFileKind::Swift ||
11201126
Kind == InputFileKind::SwiftModuleInterface);
11211127
createSourceFileForMainModule(Invocation.getSourceFileKind(),
11221128
SourceFile::ImplicitModuleImportKind::None,
1123-
MainBufferID);
1129+
MainBufferID, parsingOpts);
11241130
}
11251131

1126-
auto shouldDelayBodies = [&](unsigned bufferID) -> bool {
1127-
if (!CanDelayBodies)
1128-
return false;
1129-
1130-
// Don't delay bodies in whole module mode or for primary files.
1131-
return !(isWholeModuleCompilation() || isPrimaryInput(bufferID));
1132-
};
1133-
11341132
// Parse all the library files.
11351133
for (auto BufferID : InputSourceCodeBufferIDs) {
11361134
if (BufferID == MainBufferID)
11371135
continue;
11381136

11391137
SourceFile *NextInput = createSourceFileForMainModule(
11401138
SourceFileKind::Library, SourceFile::ImplicitModuleImportKind::None,
1141-
BufferID);
1139+
BufferID, parsingOpts);
11421140

1143-
parseIntoSourceFile(*NextInput, BufferID, shouldDelayBodies(BufferID),
1144-
EvaluateConditionals);
1141+
parseIntoSourceFile(*NextInput, BufferID);
11451142
}
11461143

11471144
// Now parse the main file.
@@ -1151,8 +1148,7 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals,
11511148
MainFile.SyntaxParsingCache = Invocation.getMainFileSyntaxParsingCache();
11521149
assert(MainBufferID == MainFile.getBufferID());
11531150

1154-
parseIntoSourceFile(MainFile, MainBufferID, shouldDelayBodies(MainBufferID),
1155-
EvaluateConditionals);
1151+
parseIntoSourceFile(MainFile, MainBufferID);
11561152
}
11571153

11581154
assert(Context->LoadedModules.size() == 1 &&

lib/Parse/ParseDecl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4569,7 +4569,7 @@ Parser::parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, Diag<> ErrorDiag,
45694569
bool Parser::canDelayMemberDeclParsing(bool &HasOperatorDeclarations,
45704570
bool &HasNestedClassDeclarations) {
45714571
// If explicitly disabled, respect the flag.
4572-
if (!DelayBodyParsing)
4572+
if (!isDelayedParsingEnabled())
45734573
return false;
45744574
// Recovering parser status later for #sourceLocation is not-trivial and
45754575
// it may not worth it.
@@ -6449,7 +6449,10 @@ void Parser::parseAbstractFunctionBody(AbstractFunctionDecl *AFD) {
64496449

64506450
llvm::SaveAndRestore<NullablePtr<llvm::MD5>> T(CurrentTokenHash, nullptr);
64516451

6452-
if (isDelayedParsingEnabled()) {
6452+
// If we can delay parsing this body, or this is the first pass of code
6453+
// completion, skip until the end. If we encounter a code completion token
6454+
// while skipping, we'll make a note of it.
6455+
if (isDelayedParsingEnabled() || isCodeCompletionFirstPass()) {
64536456
consumeAbstractFunctionBody(AFD, AFD->getAttrs());
64546457
return;
64556458
}

lib/Parse/ParseIfConfig.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ ParserResult<IfConfigDecl> Parser::parseIfConfig(
609609

610610
bool shouldEvaluate =
611611
// Don't evaluate if it's in '-parse' mode, etc.
612-
EvaluateConditionals &&
612+
shouldEvaluatePoundIfDecls() &&
613613
// If it's in inactive #if ... #endif block, there's no point to do it.
614614
!getScopeInfo().isInactiveConfigBlock();
615615

0 commit comments

Comments
 (0)