Skip to content

Commit 325204b

Browse files
authored
Merge pull request #27406 from nathawes/add-syntax-range-assertions
[Parse] Assert that the children of syntax tree nodes have contiguous source ranges
2 parents 066bb61 + f1a2134 commit 325204b

9 files changed

+113
-84
lines changed

include/swift/Parse/ParsedRawSyntaxNode.h

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,12 @@ class ParsedRawSyntaxNode {
109109
}
110110

111111
ParsedRawSyntaxNode(syntax::SyntaxKind k, tok tokKind,
112-
CharSourceRange r, OpaqueSyntaxNode n)
112+
CharSourceRange r, OpaqueSyntaxNode n,
113+
bool IsMissing = false)
113114
: RecordedData{n, r},
114115
SynKind(uint16_t(k)), TokKind(uint16_t(tokKind)),
115-
DK(DataKind::Recorded) {
116+
DK(DataKind::Recorded),
117+
IsMissing(IsMissing) {
116118
assert(getKind() == k && "Syntax kind with too large value!");
117119
assert(getTokenKind() == tokKind && "Token kind with too large value!");
118120
}
@@ -197,12 +199,14 @@ class ParsedRawSyntaxNode {
197199
return copy;
198200
}
199201

200-
CharSourceRange getDeferredRange() const {
202+
CharSourceRange getDeferredRange(bool includeTrivia) const {
201203
switch (DK) {
202204
case DataKind::DeferredLayout:
203-
return getDeferredLayoutRange();
205+
return getDeferredLayoutRange(includeTrivia);
204206
case DataKind::DeferredToken:
205-
return getDeferredTokenRange();
207+
return includeTrivia
208+
? getDeferredTokenRangeWithTrivia()
209+
: getDeferredTokenRange();
206210
default:
207211
llvm_unreachable("node not deferred");
208212
}
@@ -227,18 +231,19 @@ class ParsedRawSyntaxNode {
227231

228232
// Deferred Layout Data ====================================================//
229233

230-
CharSourceRange getDeferredLayoutRange() const {
234+
CharSourceRange getDeferredLayoutRange(bool includeTrivia) const {
231235
assert(DK == DataKind::DeferredLayout);
232-
assert(!DeferredLayout.Children.empty());
233-
auto getLastNonNullChild = [this]() -> const ParsedRawSyntaxNode & {
234-
for (auto &Child : llvm::reverse(getDeferredChildren()))
235-
if (!Child.isNull())
236-
return Child;
237-
llvm_unreachable("layout node without non-null children");
236+
auto HasValidRange = [includeTrivia](const ParsedRawSyntaxNode &Child) {
237+
return !Child.isNull() && !Child.isMissing() &&
238+
Child.getDeferredRange(includeTrivia).isValid();
238239
};
239-
auto firstRange = DeferredLayout.Children.front().getDeferredRange();
240-
auto lastRange = getLastNonNullChild().getDeferredRange();
241-
firstRange.widen(lastRange);
240+
auto first = llvm::find_if(getDeferredChildren(), HasValidRange);
241+
if (first == getDeferredChildren().end())
242+
return CharSourceRange();
243+
auto last = llvm::find_if(llvm::reverse(getDeferredChildren()),
244+
HasValidRange);
245+
auto firstRange = first->getDeferredRange(includeTrivia);
246+
firstRange.widen(last->getDeferredRange(includeTrivia));
242247
return firstRange;
243248
}
244249
ArrayRef<ParsedRawSyntaxNode> getDeferredChildren() const {

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: 9 additions & 12 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);
@@ -69,14 +68,12 @@ public:
6968
% elif node.is_unknown():
7069
private:
7170
static Parsed${node.name} record${node.syntax_kind}(
72-
MutableArrayRef<ParsedSyntax> elts,
71+
MutableArrayRef<ParsedRawSyntaxNode> layout,
7372
ParsedRawSyntaxRecorder &rec);
74-
75-
public:
7673
static Parsed${node.name} defer${node.syntax_kind}(
77-
MutableArrayRef<ParsedSyntax> elts,
74+
MutableArrayRef<ParsedRawSyntaxNode> layout,
7875
SyntaxParsingContext &SPCtx);
79-
76+
public:
8077
static Parsed${node.name} make${node.syntax_kind}(
8178
MutableArrayRef<ParsedSyntax> elts,
8279
SyntaxParsingContext &SPCtx);

lib/Parse/ParseExpr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,8 +1498,8 @@ ParserResult<Expr> Parser::parseExprPrimary(Diag<> ID, bool isExprBasic) {
14981498
ParsedSyntaxRecorder::makeIdentifierPattern(
14991499
SyntaxContext->popToken(), *SyntaxContext);
15001500
ParsedExprSyntax ExprNode =
1501-
ParsedSyntaxRecorder::deferUnresolvedPatternExpr(std::move(PatternNode),
1502-
*SyntaxContext);
1501+
ParsedSyntaxRecorder::makeUnresolvedPatternExpr(std::move(PatternNode),
1502+
*SyntaxContext);
15031503
SyntaxContext->addSyntax(std::move(ExprNode));
15041504
return makeParserResult(new (Context) UnresolvedPatternExpr(pattern));
15051505
}

lib/Parse/ParseType.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ Parser::TypeASTResult Parser::parseType(Diag<> MessageID,
399399
diagnose(Tok.getLoc(), DiagID)
400400
.fixItInsert(ArrowLoc, "throws ")
401401
.fixItRemove(Tok.getLoc());
402-
Throws = consumeTokenSyntax();
402+
ignoreToken();
403403
}
404404
ParserResult<TypeRepr> SecondHalf =
405405
parseType(diag::expected_type_function_result);
@@ -944,7 +944,8 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() {
944944
replacement = "Any";
945945
} else {
946946
auto extractText = [&](ParsedTypeSyntax &Type) -> StringRef {
947-
auto SourceRange = Type.getRaw().getDeferredRange();
947+
auto SourceRange = Type.getRaw()
948+
.getDeferredRange(/*includeTrivia=*/false);
948949
return SourceMgr.extractText(SourceRange);
949950
};
950951
auto Begin = Protocols.begin();
@@ -1061,18 +1062,15 @@ Parser::TypeResult Parser::parseTypeTupleBody() {
10611062
// Consume a name.
10621063
NameLoc = Tok.getLoc();
10631064
Name = consumeArgumentLabelSyntax();
1064-
LocalJunk.push_back(Name->copyDeferred());
10651065

10661066
// If there is a second name, consume it as well.
10671067
if (Tok.canBeArgumentLabel()) {
10681068
SecondNameLoc = Tok.getLoc();
10691069
SecondName = consumeArgumentLabelSyntax();
1070-
LocalJunk.push_back(SecondName->copyDeferred());
10711070
}
10721071

10731072
// Consume the ':'.
10741073
if ((Colon = consumeTokenSyntaxIf(tok::colon))) {
1075-
LocalJunk.push_back(Colon->copyDeferred());
10761074
// If we succeed, then we successfully parsed a label.
10771075
if (Backtracking)
10781076
Backtracking->cancelBacktrack();
@@ -1089,6 +1087,18 @@ Parser::TypeResult Parser::parseTypeTupleBody() {
10891087
IsInOutObsoleted = false;
10901088
}
10911089

1090+
if (!Backtracking || !Backtracking->willBacktrack()) {
1091+
if (Name)
1092+
LocalJunk.push_back(Name->copyDeferred());
1093+
if (SecondName)
1094+
LocalJunk.push_back(SecondName->copyDeferred());
1095+
if (Colon)
1096+
LocalJunk.push_back(Colon->copyDeferred());
1097+
} else if (Backtracking && Backtracking->willBacktrack()) {
1098+
Name.reset();
1099+
SecondName.reset();
1100+
assert(!Colon.hasValue());
1101+
}
10921102
Backtracking.reset();
10931103

10941104
// Parse the type annotation.

lib/Parse/ParsedRawSyntaxRecorder.cpp

Lines changed: 20 additions & 1 deletion
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
@@ -128,3 +129,21 @@ ParsedRawSyntaxRecorder::lookupNode(size_t lexerOffset, SourceLoc loc,
128129
CharSourceRange range{loc, unsigned(length)};
129130
return ParsedRawSyntaxNode{kind, tok::unknown, range, n};
130131
}
132+
133+
#ifndef NDEBUG
134+
void ParsedRawSyntaxRecorder::verifyElementRanges(ArrayRef<ParsedRawSyntaxNode> elements) {
135+
SourceLoc prevEndLoc;
136+
for (const auto &elem: elements) {
137+
if (elem.isMissing() || elem.isNull())
138+
continue;
139+
CharSourceRange range = elem.isRecorded()
140+
? elem.getRecordedRange()
141+
: elem.getDeferredRange(/*includeTrivia=*/true);
142+
if (range.isValid()) {
143+
assert((prevEndLoc.isInvalid() || range.getStart() == prevEndLoc)
144+
&& "Non-contiguous child ranges?");
145+
prevEndLoc = range.getEnd();
146+
}
147+
}
148+
}
149+
#endif

lib/Parse/ParsedSyntaxBuilders.cpp.gyb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ void Parsed${node.name}Builder::finishLayout(bool deferred) {
120120
}
121121
% end
122122
% end
123+
124+
#ifndef NDEBUG
125+
ParsedRawSyntaxRecorder::verifyElementRanges(Layout);
126+
#endif
123127
% end
124128
}
125129

lib/Parse/ParsedSyntaxRecorder.cpp.gyb

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -90,23 +90,21 @@ bool ParsedSyntaxRecorder::formExactLayoutFor(syntax::SyntaxKind Kind,
9090
% child_params = ', '.join(child_params)
9191
% child_move_args = ', '.join(child_move_args)
9292
Parsed${node.name}
93-
ParsedSyntaxRecorder::record${node.syntax_kind}(${child_params},
93+
ParsedSyntaxRecorder::record${node.syntax_kind}(MutableArrayRef<ParsedRawSyntaxNode> layout,
9494
ParsedRawSyntaxRecorder &rec) {
95-
ParsedRawSyntaxNode layout[] = {
96-
% for child in node.children:
97-
% if child.is_optional:
98-
${child.name}.hasValue() ? ${child.name}->takeRaw() : ParsedRawSyntaxNode::null(),
99-
% else:
100-
${child.name}.takeRaw(),
101-
% end
102-
% end
103-
};
10495
auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout);
10596
return Parsed${node.name}(std::move(raw));
10697
}
10798

10899
Parsed${node.name}
109-
ParsedSyntaxRecorder::defer${node.syntax_kind}(${child_params}, SyntaxParsingContext &SPCtx) {
100+
ParsedSyntaxRecorder::defer${node.syntax_kind}(MutableArrayRef<ParsedRawSyntaxNode> layout, SyntaxParsingContext &SPCtx) {
101+
auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, layout, SPCtx);
102+
return Parsed${node.name}(std::move(raw));
103+
}
104+
105+
Parsed${node.name}
106+
ParsedSyntaxRecorder::make${node.syntax_kind}(${child_params},
107+
SyntaxParsingContext &SPCtx) {
110108
ParsedRawSyntaxNode layout[] = {
111109
% for child in node.children:
112110
% if child.is_optional:
@@ -116,41 +114,27 @@ ParsedSyntaxRecorder::defer${node.syntax_kind}(${child_params}, SyntaxParsingCon
116114
% end
117115
% end
118116
};
119-
auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, llvm::makeMutableArrayRef(layout, ${len(node.children)}), SPCtx);
120-
return Parsed${node.name}(std::move(raw));
121-
}
122-
123-
Parsed${node.name}
124-
ParsedSyntaxRecorder::make${node.syntax_kind}(${child_params},
125-
SyntaxParsingContext &SPCtx) {
117+
#ifndef NDEBUG
118+
ParsedRawSyntaxRecorder::verifyElementRanges(layout);
119+
#endif
126120
if (SPCtx.shouldDefer())
127-
return defer${node.syntax_kind}(${child_move_args}, SPCtx);
128-
return record${node.syntax_kind}(${child_move_args}, SPCtx.getRecorder());
121+
return defer${node.syntax_kind}(layout, SPCtx);
122+
return record${node.syntax_kind}(layout, SPCtx.getRecorder());
129123
}
130124

131125
% elif node.is_syntax_collection():
132126
Parsed${node.name}
133127
ParsedSyntaxRecorder::record${node.syntax_kind}(
134-
MutableArrayRef<Parsed${node.collection_element_type}> elements,
128+
MutableArrayRef<ParsedRawSyntaxNode> layout,
135129
ParsedRawSyntaxRecorder &rec) {
136-
SmallVector<ParsedRawSyntaxNode, 16> layout;
137-
layout.reserve(elements.size());
138-
for (auto &element : elements) {
139-
layout.push_back(element.takeRaw());
140-
}
141130
auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout);
142131
return Parsed${node.name}(std::move(raw));
143132
}
144133

145134
Parsed${node.name}
146135
ParsedSyntaxRecorder::defer${node.syntax_kind}(
147-
MutableArrayRef<Parsed${node.collection_element_type}> elements,
136+
MutableArrayRef<ParsedRawSyntaxNode> layout,
148137
SyntaxParsingContext &SPCtx) {
149-
SmallVector<ParsedRawSyntaxNode, 16> layout;
150-
layout.reserve(elements.size());
151-
for (auto &element : elements) {
152-
layout.push_back(element.takeRaw());
153-
}
154138
auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind},
155139
layout, SPCtx);
156140
return Parsed${node.name}(std::move(raw));
@@ -160,9 +144,17 @@ Parsed${node.name}
160144
ParsedSyntaxRecorder::make${node.syntax_kind}(
161145
MutableArrayRef<Parsed${node.collection_element_type}> elements,
162146
SyntaxParsingContext &SPCtx) {
147+
SmallVector<ParsedRawSyntaxNode, 16> layout;
148+
layout.reserve(elements.size());
149+
for (auto &element : elements) {
150+
layout.push_back(element.takeRaw());
151+
}
152+
#ifndef NDEBUG
153+
ParsedRawSyntaxRecorder::verifyElementRanges(layout);
154+
#endif
163155
if (SPCtx.shouldDefer())
164-
return defer${node.syntax_kind}(elements, SPCtx);
165-
return record${node.syntax_kind}(elements, SPCtx.getRecorder());
156+
return defer${node.syntax_kind}(layout, SPCtx);
157+
return record${node.syntax_kind}(layout, SPCtx.getRecorder());
166158
}
167159

168160
Parsed${node.name}
@@ -180,26 +172,16 @@ ParsedSyntaxRecorder::makeBlank${node.syntax_kind}(SourceLoc loc,
180172
% elif node.is_unknown():
181173
Parsed${node.name}
182174
ParsedSyntaxRecorder::record${node.syntax_kind}(
183-
MutableArrayRef<ParsedSyntax> elements,
175+
MutableArrayRef<ParsedRawSyntaxNode> layout,
184176
ParsedRawSyntaxRecorder &rec) {
185-
SmallVector<ParsedRawSyntaxNode, 16> layout;
186-
layout.reserve(elements.size());
187-
for (auto &element : elements) {
188-
layout.push_back(element.takeRaw());
189-
}
190177
auto raw = rec.recordRawSyntax(SyntaxKind::${node.syntax_kind}, layout);
191178
return Parsed${node.name}(std::move(raw));
192179
}
193180

194181
Parsed${node.name}
195182
ParsedSyntaxRecorder::defer${node.syntax_kind}(
196-
MutableArrayRef<ParsedSyntax> elements,
183+
MutableArrayRef<ParsedRawSyntaxNode> layout,
197184
SyntaxParsingContext &SPCtx) {
198-
SmallVector<ParsedRawSyntaxNode, 16> layout;
199-
layout.reserve(elements.size());
200-
for (auto &element : elements) {
201-
layout.push_back(element.takeRaw());
202-
}
203185
auto raw = ParsedRawSyntaxNode::makeDeferred(SyntaxKind::${node.syntax_kind}, layout, SPCtx);
204186
return Parsed${node.name}(std::move(raw));
205187
}
@@ -208,9 +190,17 @@ Parsed${node.name}
208190
ParsedSyntaxRecorder::make${node.syntax_kind}(
209191
MutableArrayRef<ParsedSyntax> elements,
210192
SyntaxParsingContext &SPCtx) {
193+
SmallVector<ParsedRawSyntaxNode, 16> layout;
194+
layout.reserve(elements.size());
195+
for (auto &element : elements) {
196+
layout.push_back(element.takeRaw());
197+
}
198+
#ifndef NDEBUG
199+
ParsedRawSyntaxRecorder::verifyElementRanges(layout);
200+
#endif
211201
if (SPCtx.shouldDefer())
212-
return defer${node.syntax_kind}(elements, SPCtx);
213-
return record${node.syntax_kind}(elements, SPCtx.getRecorder());
202+
return defer${node.syntax_kind}(layout, SPCtx);
203+
return record${node.syntax_kind}(layout, SPCtx.getRecorder());
214204
}
215205
% end
216206
% end

0 commit comments

Comments
 (0)