Skip to content

Commit fea97d2

Browse files
authored
Merge pull request #27789 from rintaro/syntaxparse-assertion-layout
[SyntaxParse] Assert that the children of syntax tree nodes have contiguous ranges
2 parents a52fac4 + 7c43083 commit fea97d2

14 files changed

+140
-70
lines changed

include/swift/Parse/ParsedRawSyntaxNode.h

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class ParsedRawSyntaxNode {
5252
};
5353
struct DeferredLayoutNode {
5454
MutableArrayRef<ParsedRawSyntaxNode> Children;
55+
CharSourceRange Range;
5556
};
5657
struct DeferredTokenNode {
5758
const ParsedTriviaPiece *TriviaPieces;
@@ -72,9 +73,9 @@ class ParsedRawSyntaxNode {
7273
/// Primary used for capturing a deferred missing token.
7374
bool IsMissing = false;
7475

75-
ParsedRawSyntaxNode(syntax::SyntaxKind k,
76+
ParsedRawSyntaxNode(syntax::SyntaxKind k, CharSourceRange r,
7677
MutableArrayRef<ParsedRawSyntaxNode> deferredNodes)
77-
: DeferredLayout({deferredNodes}),
78+
: DeferredLayout({deferredNodes, r}),
7879
SynKind(uint16_t(k)), TokKind(uint16_t(tok::unknown)),
7980
DK(DataKind::DeferredLayout) {
8081
assert(getKind() == k && "Syntax kind with too large value!");
@@ -109,10 +110,12 @@ class ParsedRawSyntaxNode {
109110
}
110111

111112
ParsedRawSyntaxNode(syntax::SyntaxKind k, tok tokKind,
112-
CharSourceRange r, OpaqueSyntaxNode n)
113+
CharSourceRange r, OpaqueSyntaxNode n,
114+
bool IsMissing = false)
113115
: RecordedData{n, r},
114116
SynKind(uint16_t(k)), TokKind(uint16_t(tokKind)),
115-
DK(DataKind::Recorded) {
117+
DK(DataKind::Recorded),
118+
IsMissing(IsMissing) {
116119
assert(getKind() == k && "Syntax kind with too large value!");
117120
assert(getTokenKind() == tokKind && "Token kind with too large value!");
118121
}
@@ -209,9 +212,20 @@ class ParsedRawSyntaxNode {
209212
return copy;
210213
}
211214

215+
CharSourceRange getDeferredRange() const {
216+
switch (DK) {
217+
case DataKind::DeferredLayout:
218+
return getDeferredLayoutRange();
219+
case DataKind::DeferredToken:
220+
return getDeferredTokenRangeWithTrivia();
221+
default:
222+
llvm_unreachable("node not deferred");
223+
}
224+
}
225+
212226
// Recorded Data ===========================================================//
213227

214-
CharSourceRange getRange() const {
228+
CharSourceRange getRecordedRange() const {
215229
assert(isRecorded());
216230
return RecordedData.Range;
217231
}
@@ -228,6 +242,10 @@ class ParsedRawSyntaxNode {
228242

229243
// Deferred Layout Data ====================================================//
230244

245+
CharSourceRange getDeferredLayoutRange() const {
246+
assert(DK == DataKind::DeferredLayout);
247+
return DeferredLayout.Range;
248+
}
231249
ArrayRef<ParsedRawSyntaxNode> getDeferredChildren() const {
232250
assert(DK == DataKind::DeferredLayout);
233251
return DeferredLayout.Children;
@@ -259,6 +277,19 @@ class ParsedRawSyntaxNode {
259277

260278
// Deferred Token Data =====================================================//
261279

280+
CharSourceRange getDeferredTokenRangeWithTrivia() const {
281+
assert(DK == DataKind::DeferredToken);
282+
auto leadTriviaPieces = getDeferredLeadingTriviaPieces();
283+
auto trailTriviaPieces = getDeferredTrailingTriviaPieces();
284+
285+
auto leadTriviaLen = ParsedTriviaPiece::getTotalLength(leadTriviaPieces);
286+
auto trailTriviaLen = ParsedTriviaPiece::getTotalLength(trailTriviaPieces);
287+
288+
SourceLoc begin = DeferredToken.TokLoc.getAdvancedLoc(-leadTriviaLen);
289+
unsigned len = leadTriviaLen + DeferredToken.TokLength + trailTriviaLen;
290+
291+
return CharSourceRange{begin, len};
292+
}
262293
CharSourceRange getDeferredTokenRange() const {
263294
assert(DK == DataKind::DeferredToken);
264295
return CharSourceRange{DeferredToken.TokLoc, DeferredToken.TokLength};

include/swift/Parse/ParsedRawSyntaxRecorder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ class ParsedRawSyntaxRecorder {
7373
/// Used for incremental re-parsing.
7474
ParsedRawSyntaxNode lookupNode(size_t lexerOffset, SourceLoc loc,
7575
syntax::SyntaxKind kind);
76+
77+
#ifndef NDEBUG
78+
static void verifyElementRanges(ArrayRef<ParsedRawSyntaxNode> elements);
79+
#endif
7680
};
7781

7882
} // end namespace swift

include/swift/Parse/ParsedSyntaxBuilders.h.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ public:
6262
% end
6363

6464
Parsed${node.name} build();
65-
Parsed${node.name} makeDeferred();
6665

6766
private:
67+
Parsed${node.name} makeDeferred();
6868
Parsed${node.name} record();
6969
void finishLayout(bool deferred);
7070
};

include/swift/Parse/ParsedSyntaxRecorder.h.gyb

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,22 @@ struct ParsedSyntaxRecorder {
4343
% end
4444
% child_params = ', '.join(child_params)
4545
private:
46-
static Parsed${node.name} record${node.syntax_kind}(${child_params},
46+
static Parsed${node.name} record${node.syntax_kind}(MutableArrayRef<ParsedRawSyntaxNode> layout,
4747
ParsedRawSyntaxRecorder &rec);
48-
public:
49-
static Parsed${node.name} defer${node.syntax_kind}(${child_params},
48+
static Parsed${node.name} defer${node.syntax_kind}(MutableArrayRef<ParsedRawSyntaxNode> layout,
5049
SyntaxParsingContext &SPCtx);
50+
public:
5151
static Parsed${node.name} make${node.syntax_kind}(${child_params},
5252
SyntaxParsingContext &SPCtx);
5353
% elif node.is_syntax_collection():
5454
private:
5555
static Parsed${node.name} record${node.syntax_kind}(
56-
MutableArrayRef<Parsed${node.collection_element_type}> elts,
56+
MutableArrayRef<ParsedRawSyntaxNode> layout,
5757
ParsedRawSyntaxRecorder &rec);
58-
59-
public:
6058
static Parsed${node.name} defer${node.syntax_kind}(
61-
MutableArrayRef<Parsed${node.collection_element_type}> elts,
59+
MutableArrayRef<ParsedRawSyntaxNode> layout,
6260
SyntaxParsingContext &SPCtx);
61+
public:
6362
static Parsed${node.name} make${node.syntax_kind}(
6463
MutableArrayRef<Parsed${node.collection_element_type}> elts,
6564
SyntaxParsingContext &SPCtx);

include/swift/Parse/Parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,10 @@ class Parser {
532532
return consumeToken();
533533
}
534534

535+
SourceLoc leadingTriviaLoc() {
536+
return Tok.getLoc().getAdvancedLoc(-LeadingTrivia.getLength());
537+
}
538+
535539
SourceLoc consumeIdentifier(Identifier *Result = nullptr,
536540
bool allowDollarIdentifier = false) {
537541
assert(Tok.isAny(tok::identifier, tok::kw_self, tok::kw_Self));

lib/Parse/ParseDecl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4615,9 +4615,9 @@ ParserStatus Parser::parseGetSet(ParseDeclOptions Flags,
46154615
accessors.LBLoc = consumeToken(tok::l_brace);
46164616
// Give syntax node an empty accessor list.
46174617
if (SyntaxContext->isEnabled()) {
4618-
SourceLoc listLoc = accessors.LBLoc.getAdvancedLoc(1);
4618+
SourceLoc listLoc = leadingTriviaLoc();
46194619
SyntaxContext->addSyntax(
4620-
ParsedSyntaxRecorder::makeBlankAccessorList(listLoc, *SyntaxContext));
4620+
ParsedSyntaxRecorder::makeBlankAccessorList(listLoc, *SyntaxContext));
46214621
}
46224622
accessors.RBLoc = consumeToken(tok::r_brace);
46234623

lib/Parse/ParseExpr.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,7 +1183,7 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
11831183
// Add dummy blank argument list to the call expression syntax.
11841184
SyntaxContext->addSyntax(
11851185
ParsedSyntaxRecorder::makeBlankTupleExprElementList(
1186-
Tok.getLoc(), *SyntaxContext));
1186+
leadingTriviaLoc(), *SyntaxContext));
11871187
}
11881188

11891189
ParserResult<Expr> closure =
@@ -1466,6 +1466,7 @@ ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
14661466
// name, not a binding, because it is the start of an enum pattern or
14671467
// call pattern.
14681468
peekToken().isNot(tok::period, tok::period_prefix, tok::l_paren)) {
1469+
DeferringContextRAII Deferring(*SyntaxContext);
14691470
Identifier name;
14701471
SourceLoc loc = consumeIdentifier(&name, /*allowDollarIdentifier=*/true);
14711472
auto introducer = (InVarOrLetPattern != IVOLP_InVar
@@ -1474,10 +1475,10 @@ ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
14741475
auto pattern = createBindingFromPattern(loc, name, introducer);
14751476
if (SyntaxContext->isEnabled()) {
14761477
ParsedPatternSyntax PatternNode =
1477-
ParsedSyntaxRecorder::deferIdentifierPattern(
1478+
ParsedSyntaxRecorder::makeIdentifierPattern(
14781479
SyntaxContext->popToken(), *SyntaxContext);
14791480
ParsedExprSyntax ExprNode =
1480-
ParsedSyntaxRecorder::deferUnresolvedPatternExpr(std::move(PatternNode),
1481+
ParsedSyntaxRecorder::makeUnresolvedPatternExpr(std::move(PatternNode),
14811482
*SyntaxContext);
14821483
SyntaxContext->addSyntax(std::move(ExprNode));
14831484
}
@@ -1587,7 +1588,7 @@ ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
15871588
// Add dummy blank argument list to the call expression syntax.
15881589
SyntaxContext->addSyntax(
15891590
ParsedSyntaxRecorder::makeBlankTupleExprElementList(
1590-
Tok.getLoc(), *SyntaxContext));
1591+
leadingTriviaLoc(), *SyntaxContext));
15911592
}
15921593

15931594
ParserResult<Expr> closure =
@@ -2101,7 +2102,7 @@ DeclName Parser::parseUnqualifiedDeclName(bool afterDot,
21012102
if (SyntaxContext->isEnabled())
21022103
SyntaxContext->addSyntax(
21032104
ParsedSyntaxRecorder::makeBlankDeclNameArgumentList(
2104-
Tok.getLoc(), *SyntaxContext));
2105+
leadingTriviaLoc(), *SyntaxContext));
21052106
consumeToken(tok::r_paren);
21062107
loc = DeclNameLoc(baseNameLoc);
21072108
SmallVector<Identifier, 2> argumentLabels;
@@ -3303,9 +3304,8 @@ ParserResult<Expr> Parser::parseExprCollection() {
33033304
// [] is always an array.
33043305
if (Tok.is(tok::r_square)) {
33053306
if (SyntaxContext->isEnabled())
3306-
SyntaxContext->addSyntax(
3307-
ParsedSyntaxRecorder::makeBlankArrayElementList(
3308-
Tok.getLoc(), *SyntaxContext));
3307+
SyntaxContext->addSyntax(ParsedSyntaxRecorder::makeBlankArrayElementList(
3308+
leadingTriviaLoc(), *SyntaxContext));
33093309
RSquareLoc = consumeToken(tok::r_square);
33103310
ArrayOrDictContext.setCreateSyntax(SyntaxKind::ArrayExpr);
33113311
return makeParserResult(

lib/Parse/ParsedRawSyntaxNode.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,34 @@ ParsedRawSyntaxNode
2121
ParsedRawSyntaxNode::makeDeferred(SyntaxKind k,
2222
MutableArrayRef<ParsedRawSyntaxNode> deferredNodes,
2323
SyntaxParsingContext &ctx) {
24+
CharSourceRange range;
2425
if (deferredNodes.empty()) {
25-
return ParsedRawSyntaxNode(k, {});
26+
return ParsedRawSyntaxNode(k, range, {});
2627
}
2728
ParsedRawSyntaxNode *newPtr =
2829
ctx.getScratchAlloc().Allocate<ParsedRawSyntaxNode>(deferredNodes.size());
2930

30-
// uninitialized move;
31+
#ifndef NDEBUG
32+
ParsedRawSyntaxRecorder::verifyElementRanges(deferredNodes);
33+
#endif
3134
auto ptr = newPtr;
32-
for (auto &node : deferredNodes)
33-
:: new (static_cast<void *>(ptr++)) ParsedRawSyntaxNode(std::move(node));
35+
for (auto &node : deferredNodes) {
36+
// Cached range.
37+
if (!node.isNull() && !node.isMissing()) {
38+
auto nodeRange = node.getDeferredRange();
39+
if (nodeRange.isValid()) {
40+
if (range.isInvalid())
41+
range = nodeRange;
42+
else
43+
range.widen(nodeRange);
44+
}
45+
}
3446

35-
return ParsedRawSyntaxNode(k, makeMutableArrayRef(newPtr, deferredNodes.size()));
47+
// uninitialized move;
48+
:: new (static_cast<void *>(ptr++)) ParsedRawSyntaxNode(std::move(node));
49+
}
50+
return ParsedRawSyntaxNode(k, range,
51+
makeMutableArrayRef(newPtr, deferredNodes.size()));
3652
}
3753

3854
ParsedRawSyntaxNode

lib/Parse/ParsedRawSyntaxRecorder.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ ParsedRawSyntaxNode
5353
ParsedRawSyntaxRecorder::recordMissingToken(tok tokenKind, SourceLoc loc) {
5454
CharSourceRange range{loc, 0};
5555
OpaqueSyntaxNode n = SPActions->recordMissingToken(tokenKind, loc);
56-
return ParsedRawSyntaxNode{SyntaxKind::Token, tokenKind, range, n};
56+
return ParsedRawSyntaxNode{SyntaxKind::Token, tokenKind, range, n,
57+
/*isMissing=*/true};
5758
}
5859

5960
static ParsedRawSyntaxNode
@@ -74,6 +75,9 @@ getRecordedNode(ParsedRawSyntaxNode node, ParsedRawSyntaxRecorder &rec) {
7475
ParsedRawSyntaxNode
7576
ParsedRawSyntaxRecorder::recordRawSyntax(SyntaxKind kind,
7677
MutableArrayRef<ParsedRawSyntaxNode> elements) {
78+
#ifndef NDEBUG
79+
ParsedRawSyntaxRecorder::verifyElementRanges(elements);
80+
#endif
7781
CharSourceRange range;
7882
SmallVector<OpaqueSyntaxNode, 16> subnodes;
7983
if (!elements.empty()) {
@@ -84,11 +88,11 @@ ParsedRawSyntaxRecorder::recordRawSyntax(SyntaxKind kind,
8488
if (subnode.isNull()) {
8589
subnodes.push_back(nullptr);
8690
} else if (subnode.isRecorded()) {
87-
localRange = subnode.getRange();
91+
localRange = subnode.getRecordedRange();
8892
subnodes.push_back(subnode.takeOpaqueNode());
8993
} else {
9094
auto recorded = getRecordedNode(subnode.copyDeferred(), *this);
91-
localRange = recorded.getRange();
95+
localRange = recorded.getRecordedRange();
9296
subnodes.push_back(recorded.takeOpaqueNode());
9397
}
9498

@@ -128,3 +132,21 @@ ParsedRawSyntaxRecorder::lookupNode(size_t lexerOffset, SourceLoc loc,
128132
CharSourceRange range{loc, unsigned(length)};
129133
return ParsedRawSyntaxNode{kind, tok::unknown, range, n};
130134
}
135+
136+
#ifndef NDEBUG
137+
void ParsedRawSyntaxRecorder::verifyElementRanges(ArrayRef<ParsedRawSyntaxNode> elements) {
138+
SourceLoc prevEndLoc;
139+
for (const auto &elem: elements) {
140+
if (elem.isMissing() || elem.isNull())
141+
continue;
142+
CharSourceRange range = elem.isRecorded()
143+
? elem.getRecordedRange()
144+
: elem.getDeferredRange();
145+
if (range.isValid()) {
146+
assert((prevEndLoc.isInvalid() || range.getStart() == prevEndLoc)
147+
&& "Non-contiguous child ranges?");
148+
prevEndLoc = range.getEnd();
149+
}
150+
}
151+
}
152+
#endif

lib/Parse/ParsedSyntaxBuilders.cpp.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Parsed${node.name}Builder::makeDeferred() {
7474

7575
Parsed${node.name}
7676
Parsed${node.name}Builder::build() {
77-
if (SPCtx.isBacktracking())
77+
if (SPCtx.shouldDefer())
7878
return makeDeferred();
7979
return record();
8080
}

0 commit comments

Comments
 (0)