Skip to content

Commit c94bc1d

Browse files
authored
Merge pull request #19260 from nkcsgexi/parse-other-type
Parser: allow on-demand member decl parsing for other nominal types.
2 parents 64fe398 + a7a06d7 commit c94bc1d

File tree

15 files changed

+144
-25
lines changed

15 files changed

+144
-25
lines changed

include/swift/AST/ASTContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,10 @@ class ASTContext final {
791791
/// \param IDC The context whose member decls should be lazily parsed.
792792
void parseMembers(IterableDeclContext *IDC);
793793

794+
/// Use the lazy parsers associated with the context to check whether the decl
795+
/// context has been parsed.
796+
bool hasUnparsedMembers(const IterableDeclContext *IDC) const;
797+
794798
/// Get the lazy function data for the given generic context.
795799
///
796800
/// \param lazyLoader If non-null, the lazy loader to use when creating the

include/swift/AST/LazyResolver.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ class LazyMemberParser {
101101
///
102102
/// The implementation should add the members to IDC.
103103
virtual void parseMembers(IterableDeclContext *IDC) = 0;
104+
105+
/// Return whether the iterable decl context needs parsing.
106+
virtual bool hasUnparsedMembers(const IterableDeclContext *IDC) = 0;
107+
108+
/// Parse all delayed decl list members.
109+
virtual void parseAllDelayedDeclLists() = 0;
104110
};
105111

106112
/// Context data for generic contexts.

include/swift/Frontend/Frontend.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,8 @@ class CompilerInstance {
552552

553553
/// Parses the input file but does no type-checking or module imports.
554554
/// Note that this only supports parsing an invocation with a single file.
555-
void performParseOnly(bool EvaluateConditionals = false);
555+
void performParseOnly(bool EvaluateConditionals = false,
556+
bool ParseDelayedBodyOnEnd = false);
556557

557558
/// Parses and performs name binding on all input files.
558559
///

include/swift/Parse/Parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ class Parser {
346346
SyntaxParsingContext *SyntaxContext;
347347

348348
public:
349+
Parser(unsigned BufferID, SourceFile &SF, DiagnosticEngine* LexerDiags,
350+
SILParserTUStateBase *SIL,
351+
PersistentParserState *PersistentState);
349352
Parser(unsigned BufferID, SourceFile &SF, SILParserTUStateBase *SIL,
350353
PersistentParserState *PersistentState = nullptr);
351354
Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF,

include/swift/Parse/PersistentParserState.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,12 @@ class PersistentParserState: public LazyMemberParser {
174174
std::unique_ptr<DelayedDeclListState>
175175
takeDelayedDeclListState(IterableDeclContext *IDC);
176176

177-
bool hasDelayedDeclList(IterableDeclContext *IDC) {
177+
bool hasUnparsedMembers(const IterableDeclContext *IDC) override {
178178
return DelayedDeclListStates.find(IDC) != DelayedDeclListStates.end();
179179
}
180180

181+
void parseAllDelayedDeclLists() override;
182+
181183
TopLevelContext &getTopLevelContext() {
182184
return TopLevelCode;
183185
}

lib/AST/ASTContext.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,7 @@ void ASTContext::addLazyParser(LazyMemberParser *lazyParser) {
573573

574574
void ASTContext::removeLazyParser(LazyMemberParser *lazyParser) {
575575
auto removed = getImpl().lazyParsers.erase(lazyParser);
576+
(void)removed;
576577
assert(removed && "Removing an non-existing lazy parser.");
577578
}
578579

@@ -1902,9 +1903,16 @@ LazyContextData *ASTContext::getOrCreateLazyContextData(
19021903
return contextData;
19031904
}
19041905

1906+
bool ASTContext::hasUnparsedMembers(const IterableDeclContext *IDC) const {
1907+
auto parsers = getImpl().lazyParsers;
1908+
return std::any_of(parsers.begin(), parsers.end(),
1909+
[IDC](LazyMemberParser *p) { return p->hasUnparsedMembers(IDC); });
1910+
}
1911+
19051912
void ASTContext::parseMembers(IterableDeclContext *IDC) {
19061913
for (auto *p: getImpl().lazyParsers) {
1907-
p->parseMembers(IDC);
1914+
if (p->hasUnparsedMembers(IDC))
1915+
p->parseMembers(IDC);
19081916
}
19091917
}
19101918

lib/AST/ASTVerifier.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,8 @@ class Verifier : public ASTWalker {
709709
pushScope(fn); \
710710
if (fn->hasLazyMembers()) \
711711
return false; \
712+
if (fn->getASTContext().hasUnparsedMembers(fn)) \
713+
return false; \
712714
return shouldVerify(cast<ASTNodeBase<NODE*>::BaseTy>(fn));\
713715
} \
714716
void cleanup(NODE *fn) { \

lib/Frontend/Frontend.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,8 @@ SourceFile *CompilerInstance::createSourceFileForMainModule(
925925
return inputFile;
926926
}
927927

928-
void CompilerInstance::performParseOnly(bool EvaluateConditionals) {
928+
void CompilerInstance::performParseOnly(bool EvaluateConditionals,
929+
bool ParseDelayedBodyOnEnd) {
929930
const InputFileKind Kind = Invocation.getInputKind();
930931
ModuleDecl *const MainModule = getMainModule();
931932
Context->LoadedModules[MainModule->getName()] = MainModule;
@@ -947,6 +948,10 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals) {
947948
}
948949

949950
PersistentParserState PersistentState(getASTContext());
951+
SWIFT_DEFER {
952+
if (ParseDelayedBodyOnEnd)
953+
PersistentState.parseAllDelayedDeclLists();
954+
};
950955
PersistentState.PerformConditionEvaluation = EvaluateConditionals;
951956
// Parse all the library files.
952957
for (auto BufferID : InputSourceCodeBufferIDs) {

lib/FrontendTool/FrontendTool.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,8 +902,12 @@ static bool performCompile(CompilerInstance &Instance,
902902
return compileLLVMIR(Invocation, Instance, Stats);
903903

904904
if (FrontendOptions::shouldActionOnlyParse(Action)) {
905+
bool ParseDelayedDeclListsOnEnd =
906+
Action == FrontendOptions::ActionType::DumpParse ||
907+
Invocation.getDiagnosticOptions().VerifyMode != DiagnosticOptions::NoVerify;
905908
Instance.performParseOnly(/*EvaluateConditionals*/
906-
Action == FrontendOptions::ActionType::EmitImportedModules);
909+
Action == FrontendOptions::ActionType::EmitImportedModules,
910+
ParseDelayedDeclListsOnEnd);
907911
} else if (Action == FrontendOptions::ActionType::ResolveImports) {
908912
Instance.performParseAndResolveImportsOnly();
909913
} else {

lib/Parse/ParseDecl.cpp

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -181,18 +181,21 @@ namespace {
181181
} // end anonymous namespace
182182

183183
void PersistentParserState::parseMembers(IterableDeclContext *IDC) {
184-
if (!hasDelayedDeclList(IDC))
185-
return;
186184
SourceFile &SF = *IDC->getDecl()->getDeclContext()->getParentSourceFile();
187185
assert(!SF.hasInterfaceHash() &&
188186
"Cannot delay parsing if we care about the interface hash.");
187+
assert(SF.Kind != SourceFileKind::SIL && "cannot delay parsing SIL");
189188
unsigned BufferID = *SF.getBufferID();
189+
190190
// MarkedPos is not useful for delayed parsing because we know where we should
191191
// jump the parser to. However, we should recover the MarkedPos here in case
192192
// the PersistentParserState will be used to continuously parse the rest of
193193
// the file linearly.
194194
llvm::SaveAndRestore<ParserPosition> Pos(MarkedPos, ParserPosition());
195-
Parser TheParser(BufferID, SF, nullptr, this);
195+
196+
// Lexer diaganostics have been emitted during skipping, so we disable lexer's
197+
// diagnostic engine here.
198+
Parser TheParser(BufferID, SF, /*No Lexer Diags*/nullptr, nullptr, this);
196199
// Disable libSyntax creation in the delayed parsing.
197200
TheParser.SyntaxContext->disable();
198201
TheParser.parseDeclListDelayed(IDC);
@@ -2292,7 +2295,8 @@ static unsigned skipUntilMatchingRBrace(Parser &P, bool &HasPoundDirective,
22922295
SyntaxParsingContext BodyContext(SyntaxContext, SyntaxKind::TokenList);
22932296
unsigned OpenBraces = 1;
22942297
while (OpenBraces != 0 && P.Tok.isNot(tok::eof)) {
2295-
HasPoundDirective |= P.Tok.isAny(tok::pound_sourceLocation, tok::pound_line);
2298+
HasPoundDirective |= P.Tok.isAny(tok::pound_sourceLocation, tok::pound_line,
2299+
tok::pound_if, tok::pound_else, tok::pound_endif, tok::pound_elseif);
22962300
if (P.consumeIf(tok::l_brace)) {
22972301
OpenBraces++;
22982302
continue;
@@ -2902,6 +2906,15 @@ void Parser::parseDeclListDelayed(IterableDeclContext *IDC) {
29022906
ParseDeclOptions(DelayedState->Flags),
29032907
[&] (Decl *D) { ext->addMember(D); });
29042908
ext->setBraces({LBLoc, RBLoc});
2909+
} else if (auto *cd = dyn_cast<ClassDecl>(D)) {
2910+
auto handler = [&] (Decl *D) {
2911+
cd->addMember(D);
2912+
if (isa<DestructorDecl>(D))
2913+
cd->setHasDestructor();
2914+
};
2915+
parseDeclList(cd->getBraces().Start, RBLoc, Id,
2916+
ParseDeclOptions(DelayedState->Flags), handler);
2917+
cd->setBraces({LBLoc, RBLoc});
29052918
} else {
29062919
auto *ntd = cast<NominalTypeDecl>(D);
29072920
parseDeclList(ntd->getBraces().Start, RBLoc, Id,
@@ -3349,6 +3362,10 @@ bool Parser::parseDeclList(SourceLoc LBLoc, SourceLoc &RBLoc,
33493362
}
33503363

33513364
bool Parser::canDelayMemberDeclParsing() {
3365+
// There's no fundamental reasons that SIL cannnot be lasily parsed. We need
3366+
// to keep SILParserTUStateBase persistent to make it happen.
3367+
if (isInSILMode())
3368+
return false;
33523369
// Calculating interface hash requires tokens consumed in the original order.
33533370
if (SF.hasInterfaceHash())
33543371
return false;
@@ -5831,6 +5848,7 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
58315848
// Make the entities of the struct as a code block.
58325849
SyntaxParsingContext BlockContext(SyntaxContext, SyntaxKind::MemberDeclBlock);
58335850
SourceLoc LBLoc, RBLoc;
5851+
SourceLoc PosBeforeLB = Tok.getLoc();
58345852
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_struct)) {
58355853
LBLoc = PreviousLoc;
58365854
RBLoc = LBLoc;
@@ -5839,9 +5857,20 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
58395857
// Parse the body.
58405858
Scope S(this, ScopeKind::StructBody);
58415859
ParseDeclOptions Options(PD_HasContainerType | PD_InStruct);
5842-
if (parseDeclList(LBLoc, RBLoc, diag::expected_rbrace_struct,
5843-
Options, [&](Decl *D) {SD->addMember(D);}))
5844-
Status.setIsParseError();
5860+
if (canDelayMemberDeclParsing()) {
5861+
if (Tok.is(tok::r_brace)) {
5862+
RBLoc = consumeToken();
5863+
} else {
5864+
RBLoc = Tok.getLoc();
5865+
Status.setIsParseError();
5866+
}
5867+
State->delayDeclList(SD, Options.toRaw(), CurDeclContext, { LBLoc, RBLoc },
5868+
PosBeforeLB);
5869+
} else {
5870+
if (parseDeclList(LBLoc, RBLoc, diag::expected_rbrace_struct,
5871+
Options, [&](Decl *D) {SD->addMember(D);}))
5872+
Status.setIsParseError();
5873+
}
58455874
}
58465875

58475876
SD->setBraces({LBLoc, RBLoc});
@@ -5942,6 +5971,7 @@ ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
59425971

59435972
SyntaxParsingContext BlockContext(SyntaxContext, SyntaxKind::MemberDeclBlock);
59445973
SourceLoc LBLoc, RBLoc;
5974+
auto PosBeforeLB = Tok.getLoc();
59455975
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_class)) {
59465976
LBLoc = PreviousLoc;
59475977
RBLoc = LBLoc;
@@ -5951,14 +5981,25 @@ ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
59515981
Scope S(this, ScopeKind::ClassBody);
59525982
ParseDeclOptions Options(PD_HasContainerType | PD_AllowDestructor |
59535983
PD_InClass);
5954-
auto Handler = [&] (Decl *D) {
5955-
CD->addMember(D);
5956-
if (isa<DestructorDecl>(D))
5957-
CD->setHasDestructor();
5958-
};
5959-
if (parseDeclList(LBLoc, RBLoc, diag::expected_rbrace_class,
5960-
Options, Handler))
5961-
Status.setIsParseError();
5984+
if (canDelayMemberDeclParsing()) {
5985+
if (Tok.is(tok::r_brace)) {
5986+
RBLoc = consumeToken();
5987+
} else {
5988+
RBLoc = Tok.getLoc();
5989+
Status.setIsParseError();
5990+
}
5991+
State->delayDeclList(CD, Options.toRaw(), CurDeclContext, { LBLoc, RBLoc },
5992+
PosBeforeLB);
5993+
} else {
5994+
auto Handler = [&] (Decl *D) {
5995+
CD->addMember(D);
5996+
if (isa<DestructorDecl>(D))
5997+
CD->setHasDestructor();
5998+
};
5999+
if (parseDeclList(LBLoc, RBLoc, diag::expected_rbrace_class,
6000+
Options, Handler))
6001+
Status.setIsParseError();
6002+
}
59626003
}
59636004

59646005
CD->setBraces({LBLoc, RBLoc});
@@ -6040,6 +6081,7 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
60406081
SyntaxParsingContext BlockContext(SyntaxContext, SyntaxKind::MemberDeclBlock);
60416082
SourceLoc LBraceLoc;
60426083
SourceLoc RBraceLoc;
6084+
SourceLoc PosBeforeLB = Tok.getLoc();
60436085
if (parseToken(tok::l_brace, LBraceLoc, diag::expected_lbrace_protocol)) {
60446086
LBraceLoc = PreviousLoc;
60456087
RBraceLoc = LBraceLoc;
@@ -6049,9 +6091,21 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
60496091
ParseDeclOptions Options(PD_HasContainerType |
60506092
PD_DisallowInit |
60516093
PD_InProtocol);
6052-
if (parseDeclList(LBraceLoc, RBraceLoc, diag::expected_rbrace_protocol,
6053-
Options, [&](Decl *D) {Proto->addMember(D);}))
6054-
Status.setIsParseError();
6094+
if (canDelayMemberDeclParsing()) {
6095+
if (Tok.is(tok::r_brace)) {
6096+
RBraceLoc = consumeToken();
6097+
} else {
6098+
RBraceLoc = Tok.getLoc();
6099+
Status.setIsParseError();
6100+
}
6101+
State->delayDeclList(Proto, Options.toRaw(), CurDeclContext,
6102+
{ LBraceLoc, RBraceLoc },
6103+
PosBeforeLB);
6104+
} else {
6105+
if (parseDeclList(LBraceLoc, RBraceLoc, diag::expected_rbrace_protocol,
6106+
Options, [&](Decl *D) {Proto->addMember(D);}))
6107+
Status.setIsParseError();
6108+
}
60556109
}
60566110

60576111
// Install the protocol elements.

lib/Parse/Parser.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,12 +331,18 @@ swift::tokenizeWithTrivia(const LangOptions &LangOpts, const SourceManager &SM,
331331
// Setup and Helper Methods
332332
//===----------------------------------------------------------------------===//
333333

334+
334335
Parser::Parser(unsigned BufferID, SourceFile &SF, SILParserTUStateBase *SIL,
335336
PersistentParserState *PersistentState)
337+
: Parser(BufferID, SF, &SF.getASTContext().Diags, SIL, PersistentState) {}
338+
339+
Parser::Parser(unsigned BufferID, SourceFile &SF, DiagnosticEngine* LexerDiags,
340+
SILParserTUStateBase *SIL,
341+
PersistentParserState *PersistentState)
336342
: Parser(
337343
std::unique_ptr<Lexer>(new Lexer(
338344
SF.getASTContext().LangOpts, SF.getASTContext().SourceMgr,
339-
BufferID, &SF.getASTContext().Diags,
345+
BufferID, LexerDiags,
340346
/*InSILMode=*/SIL != nullptr,
341347
SF.Kind == SourceFileKind::Main
342348
? HashbangMode::Allowed

lib/Parse/PersistentParserState.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ void PersistentParserState::delayDeclList(IterableDeclContext* D,
8181
ParentContext, BodyRange, PreviousLoc, ScopeInfo.saveCurrentScope());
8282
}
8383

84+
void PersistentParserState::parseAllDelayedDeclLists() {
85+
std::vector<IterableDeclContext*> AllDelayed;
86+
for (auto &P: DelayedDeclListStates) {
87+
AllDelayed.push_back(P.first);
88+
}
89+
for (auto *D: AllDelayed) {
90+
parseMembers(D);
91+
}
92+
}
93+
8494
void PersistentParserState::delayTopLevel(TopLevelCodeDecl *TLCD,
8595
SourceRange BodyRange,
8696
SourceLoc PreviousLoc) {

tools/swift-ide-test/swift-ide-test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1476,7 +1476,7 @@ static int doInputCompletenessTest(StringRef SourceFilename) {
14761476
llvm::raw_ostream &OS = llvm::outs();
14771477
OS << SourceFilename << ": ";
14781478
if (isSourceInputComplete(std::move(FileBufOrErr.get()),
1479-
SourceFileKind::Main).IsComplete) {
1479+
SourceFileKind::REPL).IsComplete) {
14801480
OS << "IS_COMPLETE\n";
14811481
} else {
14821482
OS << "IS_INCOMPLETE\n";

utils/scale-test

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ def run_once_with_primary(args, ast, rng, primary_idx):
109109
mode = "-c"
110110
if args.typecheck:
111111
mode = "-typecheck"
112+
if args.parse:
113+
mode = "-parse"
112114

113115
focus = ["-primary-file", primary]
114116
if args.whole_module_optimization:
@@ -716,6 +718,9 @@ def main():
716718
'--exponential-threshold', type=float,
717719
default=1.2,
718720
help='minimum base for exponential fit to consider "bad scaling"')
721+
parser.add_argument(
722+
'-parse', '--parse', action='store_true',
723+
default=False, help='only run compiler with -parse')
719724
parser.add_argument(
720725
'-typecheck', '--typecheck', action='store_true',
721726
default=False, help='only run compiler with -typecheck')
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %scale-test --sum-multi --parse --begin 5 --end 16 --step 5 --select NumIterableDeclContextParsed %s
2+
// REQUIRES: OS=macosx
3+
// REQUIRES: asserts
4+
5+
struct S${N} {}
6+
class C${N} {}
7+
enum E${N} {}
8+
extension C${N} {}
9+
protocol P${N} {}

0 commit comments

Comments
 (0)