Skip to content

Commit 83f2b4f

Browse files
committed
Requestify ExportedSourceFile parsing
Avoid parsing the syntax tree up-front, and instead only parse it when required, which happens when either: 1. ASTGen parsing is enabled (currently disabled by default) 2. Round trip checking is enabled for a primary file (enabled by default in a debug build, except when dep scanning or doing an IDE operation) 3. We need to evaluate a macro in that file This change therefore means that we now no longer need to parse the syntax tree for secondary files by default unless we specifically need to evaluate a macro in them (e.g if we need to lookup a member on a decl with an attached macro). And the same for primaries in release builds. rdar://109283847
1 parent 7163d0c commit 83f2b4f

File tree

11 files changed

+285
-107
lines changed

11 files changed

+285
-107
lines changed

include/swift/AST/ParseRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,26 @@ class ParseSourceFileRequest
116116
readDependencySource(const evaluator::DependencyRecorder &) const;
117117
};
118118

119+
/// Parse the ExportedSourceFile for a given SourceFile.
120+
class ExportedSourceFileRequest
121+
: public SimpleRequest<ExportedSourceFileRequest,
122+
void *(const SourceFile *),
123+
RequestFlags::SeparatelyCached> {
124+
public:
125+
using SimpleRequest::SimpleRequest;
126+
127+
private:
128+
friend SimpleRequest;
129+
130+
void *evaluate(Evaluator &evaluator, const SourceFile *SF) const;
131+
132+
public:
133+
// Separate caching.
134+
bool isCached() const { return true; }
135+
Optional<void *> getCachedResult() const;
136+
void cacheResult(void *exportedSF) const;
137+
};
138+
119139
/// Parse the top-level items of a SourceFile.
120140
class ParseTopLevelDeclsRequest
121141
: public SimpleRequest<

include/swift/AST/ParseTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,6 @@ SWIFT_REQUEST(Parse, ParseSourceFileRequest,
2828
SWIFT_REQUEST(Parse, ParseTopLevelDeclsRequest,
2929
ArrayRef<Decl *>(SourceFile *), Cached,
3030
NoLocationInfo)
31+
SWIFT_REQUEST(Parse, ExportedSourceFileRequest,
32+
void *(const SourceFile *), SeparatelyCached,
33+
NoLocationInfo)

include/swift/AST/SourceFile.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class SourceFile final : public FileUnit {
5858

5959
public:
6060
/// Flags that direct how the source file is parsed.
61-
enum class ParsingFlags : uint8_t {
61+
enum class ParsingFlags : uint16_t {
6262
/// Whether to disable delayed parsing for nominal type, extension, and
6363
/// function bodies.
6464
///
@@ -91,9 +91,17 @@ class SourceFile final : public FileUnit {
9191
/// files, as they get parsed multiple times.
9292
SuppressWarnings = 1 << 4,
9393

94-
/// Whether to disable the Swift Parser ASTGen
95-
/// e.g. in dependency scanning, where an AST is not needed.
96-
DisableSwiftParserASTGen = 1 << 5,
94+
/// Ensure that the SwiftSyntax tree round trips correctly.
95+
RoundTrip = 1 << 5,
96+
97+
/// Validate the new SwiftSyntax parser diagnostics.
98+
ValidateNewParserDiagnostics = 1 << 6,
99+
100+
/// Enable ASTGen for producing the AST nodes.
101+
EnableASTGen = 1 << 7,
102+
103+
/// Enable ASTGen for producing parser diagnostics.
104+
EnableASTGenDiagnostics = 1 << 8,
97105
};
98106
using ParsingOptions = OptionSet<ParsingFlags>;
99107

@@ -209,7 +217,13 @@ class SourceFile final : public FileUnit {
209217
/// Storage for \c HasImportsMatchingFlagRequest.
210218
ImportOptions cachedImportOptions;
211219

220+
/// The \c ExportedSourceFile instance produced by ASTGen, which includes
221+
/// the SourceFileSyntax node corresponding to this source file. This is
222+
/// \c None if it has not yet been computed.
223+
mutable Optional<void *> CachedExportedSourceFile;
224+
212225
friend ASTContext;
226+
friend class ExportedSourceFileRequest;
213227

214228
public:
215229
/// Appends the given declaration to the end of the top-level decls list. Do
@@ -262,6 +276,10 @@ class SourceFile final : public FileUnit {
262276
/// code for it. Note this method returns \c false in WMO.
263277
bool isPrimary() const { return IsPrimary; }
264278

279+
/// Retrieve the \c ExportedSourceFile instance produced by ASTGen, which
280+
/// includes the SourceFileSyntax node corresponding to this source file.
281+
void *getExportedSourceFile() const;
282+
265283
/// The list of local type declarations in the source file.
266284
llvm::SetVector<TypeDecl *> LocalTypeDecls;
267285

@@ -334,10 +352,6 @@ class SourceFile final : public FileUnit {
334352
/// this source file.
335353
llvm::SmallVector<Located<StringRef>, 0> VirtualFilePaths;
336354

337-
/// The \c ExportedSourceFile instance produced by ASTGen, which includes
338-
/// the SourceFileSyntax node corresponding to this source file.
339-
void *exportedSourceFile = nullptr;
340-
341355
/// Returns information about the file paths used for diagnostics and magic
342356
/// identifiers in this source file, including virtual filenames introduced by
343357
/// \c #sourceLocation(file:) declarations.

lib/AST/Module.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3687,6 +3687,14 @@ SourceFile::getDefaultParsingOptions(const LangOptions &langOpts) {
36873687
opts |= ParsingFlags::DisablePoundIfEvaluation;
36883688
if (langOpts.CollectParsedToken)
36893689
opts |= ParsingFlags::CollectParsedTokens;
3690+
if (langOpts.hasFeature(Feature::ParserRoundTrip))
3691+
opts |= ParsingFlags::RoundTrip;
3692+
if (langOpts.hasFeature(Feature::ParserValidation))
3693+
opts |= ParsingFlags::ValidateNewParserDiagnostics;
3694+
if (langOpts.hasFeature(Feature::ParserASTGen))
3695+
opts |= ParsingFlags::EnableASTGen;
3696+
if (langOpts.hasFeature(Feature::ParserDiagnostics))
3697+
opts |= ParsingFlags::EnableASTGenDiagnostics;
36903698
return opts;
36913699
}
36923700

@@ -3762,6 +3770,11 @@ ArrayRef<Decl *> SourceFile::getHoistedDecls() const {
37623770
return Hoisted;
37633771
}
37643772

3773+
void *SourceFile::getExportedSourceFile() const {
3774+
auto &eval = getASTContext().evaluator;
3775+
return evaluateOrDefault(eval, ExportedSourceFileRequest{this}, nullptr);
3776+
}
3777+
37653778
void SourceFile::addDeclWithRuntimeDiscoverableAttrs(ValueDecl *decl) {
37663779
assert(!decl->getRuntimeDiscoverableAttrs().empty());
37673780
DeclsWithRuntimeDiscoverableAttrs.insert(decl);

lib/Frontend/Frontend.cpp

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,6 +1513,9 @@ void CompilerInstance::finishTypeChecking() {
15131513

15141514
SourceFile::ParsingOptions
15151515
CompilerInstance::getSourceFileParsingOptions(bool forPrimary) const {
1516+
using ActionType = FrontendOptions::ActionType;
1517+
using ParsingFlags = SourceFile::ParsingFlags;
1518+
15161519
const auto &frontendOpts = Invocation.getFrontendOptions();
15171520
const auto action = frontendOpts.RequestedAction;
15181521

@@ -1521,42 +1524,45 @@ CompilerInstance::getSourceFileParsingOptions(bool forPrimary) const {
15211524
// Generally in a parse-only invocation, we want to disable #if evaluation.
15221525
// However, there are a couple of modes where we need to know which clauses
15231526
// are active.
1524-
if (action != FrontendOptions::ActionType::EmitImportedModules &&
1525-
action != FrontendOptions::ActionType::ScanDependencies) {
1526-
opts |= SourceFile::ParsingFlags::DisablePoundIfEvaluation;
1527+
if (action != ActionType::EmitImportedModules &&
1528+
action != ActionType::ScanDependencies) {
1529+
opts |= ParsingFlags::DisablePoundIfEvaluation;
15271530
}
15281531

15291532
// If we need to dump the parse tree, disable delayed bodies as we want to
15301533
// show everything.
1531-
if (action == FrontendOptions::ActionType::DumpParse)
1532-
opts |= SourceFile::ParsingFlags::DisableDelayedBodies;
1534+
if (action == ActionType::DumpParse)
1535+
opts |= ParsingFlags::DisableDelayedBodies;
15331536
}
15341537

1535-
auto typeOpts = getASTContext().TypeCheckerOpts;
1536-
if (forPrimary || isWholeModuleCompilation()) {
1538+
const auto &typeOpts = getASTContext().TypeCheckerOpts;
1539+
const auto isEffectivelyPrimary = forPrimary || isWholeModuleCompilation();
1540+
if (isEffectivelyPrimary) {
15371541
// Disable delayed body parsing for primaries and in WMO, unless
15381542
// forcefully skipping function bodies
15391543
if (typeOpts.SkipFunctionBodies == FunctionBodySkipping::None)
1540-
opts |= SourceFile::ParsingFlags::DisableDelayedBodies;
1544+
opts |= ParsingFlags::DisableDelayedBodies;
15411545
} else {
15421546
// Suppress parse warnings for non-primaries, as they'll get parsed multiple
15431547
// times.
1544-
opts |= SourceFile::ParsingFlags::SuppressWarnings;
1548+
opts |= ParsingFlags::SuppressWarnings;
15451549
}
15461550

1547-
// Dependency scanning does not require an AST, so disable Swift Parser
1548-
// ASTGen parsing completely.
1549-
if (frontendOpts.RequestedAction ==
1550-
FrontendOptions::ActionType::ScanDependencies)
1551-
opts |= SourceFile::ParsingFlags::DisableSwiftParserASTGen;
1551+
// Turn off round-trip checking for secondary files, and for dependency
1552+
// scanning and IDE inspection.
1553+
if (!isEffectivelyPrimary || SourceMgr.hasIDEInspectionTargetBuffer() ||
1554+
frontendOpts.RequestedAction == ActionType::ScanDependencies) {
1555+
opts -= ParsingFlags::RoundTrip;
1556+
opts -= ParsingFlags::ValidateNewParserDiagnostics;
1557+
}
15521558

15531559
// Enable interface hash computation for primaries or emit-module-separately,
15541560
// but not in WMO, as it's only currently needed for incremental mode.
15551561
if (forPrimary ||
15561562
typeOpts.SkipFunctionBodies ==
15571563
FunctionBodySkipping::NonInlinableWithoutTypes ||
15581564
frontendOpts.ReuseFrontendForMultipleCompilations) {
1559-
opts |= SourceFile::ParsingFlags::EnableInterfaceHash;
1565+
opts |= ParsingFlags::EnableInterfaceHash;
15601566
}
15611567
return opts;
15621568
}

0 commit comments

Comments
 (0)