Skip to content

Commit fced748

Browse files
authored
[Syntax] Represent missing optioanl nodes as nullptr (#14300)
Allocating RawSyntax/SyntaxData for missing optional node is a waste of resource.
1 parent 7905d30 commit fced748

26 files changed

+174
-260
lines changed

Diff for: include/swift/Syntax/RawSyntax.h

+25-20
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ using llvm::StringRef;
4747

4848
#ifndef NDEBUG
4949
#define syntax_assert_child_kind(Raw, Cursor, ExpectedKind) \
50-
(assert(Raw->getChild(Cursor)->Kind == ExpectedKind));
50+
({ \
51+
if (auto &__Child = Raw->getChild(Cursor::CursorName)) \
52+
assert(__Child->getKind() == ExpectedKind); \
53+
})
5154
#else
5255
#define syntax_assert_child_kind(Raw, Cursor, ExpectedKind) ({});
5356
#endif
@@ -56,17 +59,18 @@ using llvm::StringRef;
5659
#define syntax_assert_child_token(Raw, CursorName, ...) \
5760
({ \
5861
bool __Found = false; \
59-
auto __Token = Raw->getChild(Cursor::CursorName); \
60-
assert(__Token->isToken()); \
61-
if (__Token->isPresent()) { \
62-
for (auto Token : {__VA_ARGS__}) { \
63-
if (__Token->getTokenKind() == Token) { \
64-
__Found = true; \
65-
break; \
62+
if (auto &__Token = Raw->getChild(Cursor::CursorName)) { \
63+
assert(__Token->isToken()); \
64+
if (__Token->isPresent()) { \
65+
for (auto Token : {__VA_ARGS__}) { \
66+
if (__Token->getTokenKind() == Token) { \
67+
__Found = true; \
68+
break; \
69+
} \
6670
} \
71+
assert(__Found && "invalid token supplied for " #CursorName \
72+
", expected one of {" #__VA_ARGS__ "}"); \
6773
} \
68-
assert(__Found && "invalid token supplied for " #CursorName \
69-
", expected one of {" #__VA_ARGS__ "}"); \
7074
} \
7175
})
7276
#else
@@ -77,18 +81,19 @@ using llvm::StringRef;
7781
#define syntax_assert_child_token_text(Raw, CursorName, TokenKind, ...) \
7882
({ \
7983
bool __Found = false; \
80-
auto __Child = Raw->getChild(Cursor::CursorName); \
81-
assert(__Child->isToken()); \
82-
if (__Child->isPresent()) { \
83-
assert(__Child->getTokenKind() == TokenKind); \
84-
for (auto __Text : {__VA_ARGS__}) { \
85-
if (__Child->getTokenText() == __Text) { \
86-
__Found = true; \
87-
break; \
84+
if (auto &__Child = Raw->getChild(Cursor::CursorName)) { \
85+
assert(__Child->isToken()); \
86+
if (__Child->isPresent()) { \
87+
assert(__Child->getTokenKind() == TokenKind); \
88+
for (auto __Text : {__VA_ARGS__}) { \
89+
if (__Child->getTokenText() == __Text) { \
90+
__Found = true; \
91+
break; \
92+
} \
8893
} \
94+
assert(__Found && "invalid text supplied for " #CursorName \
95+
", expected one of {" #__VA_ARGS__ "}"); \
8996
} \
90-
assert(__Found && "invalid text supplied for " #CursorName \
91-
", expected one of {" #__VA_ARGS__ "}"); \
9297
} \
9398
})
9499
#else

Diff for: include/swift/Syntax/Serialization/SyntaxSerialization.h

+21-10
Original file line numberDiff line numberDiff line change
@@ -194,30 +194,41 @@ struct ObjectTraits<TokenDescription> {
194194
/// }
195195
/// ```
196196
template<>
197-
struct ObjectTraits<RC<syntax::RawSyntax>> {
198-
static void mapping(Output &out, RC<syntax::RawSyntax> &value) {
199-
if (value->isToken()) {
200-
auto tokenKind = value->getTokenKind();
201-
auto text = value->getTokenText();
197+
struct ObjectTraits<syntax::RawSyntax> {
198+
static void mapping(Output &out, syntax::RawSyntax &value) {
199+
if (value.isToken()) {
200+
auto tokenKind = value.getTokenKind();
201+
auto text = value.getTokenText();
202202
auto description = TokenDescription { tokenKind, text };
203203
out.mapRequired("tokenKind", description);
204204

205-
auto leadingTrivia = value->getLeadingTrivia();
205+
auto leadingTrivia = value.getLeadingTrivia();
206206
out.mapRequired("leadingTrivia", leadingTrivia);
207207

208-
auto trailingTrivia = value->getTrailingTrivia();
208+
auto trailingTrivia = value.getTrailingTrivia();
209209
out.mapRequired("trailingTrivia", trailingTrivia);
210210
} else {
211-
auto kind = value->getKind();
211+
auto kind = value.getKind();
212212
out.mapRequired("kind", kind);
213213

214-
auto layout = value->getLayout();
214+
auto layout = value.getLayout();
215215
out.mapRequired("layout", layout);
216216
}
217-
auto presence = value->getPresence();
217+
auto presence = value.getPresence();
218218
out.mapRequired("presence", presence);
219219
}
220220
};
221+
222+
template<>
223+
struct NullableTraits<RC<syntax::RawSyntax>> {
224+
using value_type = syntax::RawSyntax;
225+
static bool isNull(RC<syntax::RawSyntax> &value) {
226+
return value == nullptr;
227+
}
228+
static syntax::RawSyntax &get(RC<syntax::RawSyntax> &value) {
229+
return *value;
230+
}
231+
};
221232
} // end namespace json
222233
} // end namespace swift
223234

Diff for: include/swift/Syntax/Syntax.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ class Syntax {
7272

7373
public:
7474
Syntax(const RC<SyntaxData> Root, const SyntaxData *Data)
75-
: Root(Root), Data(Data) {}
75+
: Root(Root), Data(Data) {
76+
assert(Data != nullptr);
77+
}
7678

7779
virtual ~Syntax() {}
7880

@@ -87,7 +89,7 @@ class Syntax {
8789
size_t getNumChildren() const;
8890

8991
/// Get the Nth child of this piece of syntax.
90-
Syntax getChild(const size_t N) const;
92+
llvm::Optional<Syntax> getChild(const size_t N) const;
9193

9294
/// Returns true if the syntax node is of the given type.
9395
template <typename T>

Diff for: include/swift/Syntax/SyntaxBuilders.h.gyb

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace syntax {
3232
class ${node.name}Builder {
3333
std::vector<RC<RawSyntax>> Layout = {
3434
% for child in node.children:
35-
${make_missing_child(child)},
35+
nullptr,
3636
% end
3737
};
3838

Diff for: include/swift/Syntax/SyntaxCollection.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,7 @@ class SyntaxCollection : public Syntax {
106106
Element operator[](const size_t Index) const {
107107
assert(Index < size());
108108
assert(!empty());
109-
110-
auto ChildData = Data->getChild(Index);
111-
return Element { Root, ChildData.get() };
109+
return { Root, Data->getChild(Index).get() };
112110
}
113111

114112
/// Return a new collection with the given element added to the end.

Diff for: include/swift/Syntax/SyntaxData.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ class SyntaxData final : public llvm::ThreadSafeRefCountedBase<SyntaxData> {
111111
/// at the provided index.
112112
/// DO NOT expose this as public API.
113113
RC<SyntaxData> realizeSyntaxNode(CursorIndex Index) const {
114-
auto &RawChild = Raw->getChild(Index);
115-
return SyntaxData::make(RawChild, this, Index);
114+
if (auto &RawChild = Raw->getChild(Index))
115+
return SyntaxData::make(RawChild, this, Index);
116+
return nullptr;
116117
}
117118

118119
/// Replace a child in the raw syntax and recursively rebuild the
@@ -215,6 +216,8 @@ class SyntaxData final : public llvm::ThreadSafeRefCountedBase<SyntaxData> {
215216
/// cache it. This is safe because AtomicCache only ever mutates its cache
216217
/// one time -- the first initialization that wins a compare_exchange_strong.
217218
RC<SyntaxData> getChild(size_t Index) const {
219+
if (!getRaw()->getChild(Index))
220+
return nullptr;
218221
return Children[Index].getOrCreate([&]() {
219222
return realizeSyntaxNode(Index);
220223
});

Diff for: include/swift/Syntax/SyntaxVisitor.h.gyb

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ struct SyntaxVisitor {
4646

4747
void visitChildren(Syntax node) {
4848
for (unsigned i = 0, e = node.getNumChildren(); i != e; ++i) {
49-
visit(node.getChild(i));
49+
if (auto Child = node.getChild(i))
50+
visit(*Child);
5051
}
5152
}
5253
};

Diff for: lib/FrontendTool/FrontendTool.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ static bool emitSyntax(SourceFile *SF, LangOptions &LangOpts,
263263

264264
json::Output jsonOut(*os);
265265
auto Root = SF->getSyntaxRoot().getRaw();
266-
jsonOut << Root;
266+
jsonOut << *Root;
267267
*os << "\n";
268268
return false;
269269
}

Diff for: lib/Syntax/RawSyntax.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ void RawSyntax::print(llvm::raw_ostream &OS, SyntaxPrintOptions Opts) const {
201201
printSyntaxKind(Kind, OS, Opts, true);
202202

203203
for (const auto &LE : getLayout())
204-
LE->print(OS, Opts);
204+
if (LE)
205+
LE->print(OS, Opts);
205206

206207
if (PrintKind)
207208
printSyntaxKind(Kind, OS, Opts, false);

Diff for: lib/Syntax/Syntax.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ SyntaxKind Syntax::getKind() const {
2626
}
2727

2828
void Syntax::print(llvm::raw_ostream &OS, SyntaxPrintOptions Opts) const {
29-
getRaw()->print(OS, Opts);
29+
if (auto Raw = getRaw())
30+
Raw->print(OS, Opts);
3031
}
3132

3233
void Syntax::dump() const {
@@ -89,8 +90,11 @@ size_t Syntax::getNumChildren() const {
8990
return Data->getNumChildren();
9091
}
9192

92-
Syntax Syntax::getChild(const size_t N) const {
93-
return Syntax { Root, Data->getChild(N).get() };
93+
llvm::Optional<Syntax> Syntax::getChild(const size_t N) const {
94+
auto ChildData = Data->getChild(N);
95+
if (!ChildData)
96+
return llvm::None;
97+
return Syntax {Root, ChildData.get()};
9498
}
9599

96100
AbsolutePosition Syntax::getAbsolutePosition() const {

Diff for: lib/Syntax/SyntaxBuilders.cpp.gyb

+13-1
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,25 @@ ${node.name}Builder::use${child.name}(${child.type_name} ${child.name}) {
4141
${node.name}Builder &
4242
${node.name}Builder::add${child_elt}(${child_elt_type} ${child_elt}) {
4343
auto &raw = Layout[cursorIndex(${node.name}::Cursor::${child.name})];
44-
raw = raw->append(${child_elt}.getRaw());
44+
if (!raw)
45+
raw = RawSyntax::make(SyntaxKind::${child_node.syntax_kind},
46+
{${child_elt}.getRaw()}, SourcePresence::Present);
47+
else
48+
raw = raw->append(${child_elt}.getRaw());
4549
return *this;
4650
}
4751
% end
4852
% end
4953
${node.name}
5054
${node.name}Builder::build() {
55+
% if node.children:
56+
% for (idx, child) in enumerate(node.children):
57+
% if not child.is_optional:
58+
if (!Layout[${idx}])
59+
Layout[${idx}] = ${make_missing_child(child)};
60+
% end
61+
% end
62+
% end
5163
auto raw = RawSyntax::make(SyntaxKind::${node.syntax_kind},
5264
Layout, SourcePresence::Present);
5365
return make<${node.name}>(raw);

Diff for: lib/Syntax/SyntaxData.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ using namespace swift::syntax;
1919
RC<SyntaxData> SyntaxData::make(RC<RawSyntax> Raw,
2020
const SyntaxData *Parent,
2121
CursorIndex IndexInParent) {
22+
if (!Raw)
23+
return nullptr;
2224
return RC<SyntaxData> {
2325
new SyntaxData(Raw, Parent, IndexInParent)
2426
};

Diff for: lib/Syntax/SyntaxFactory.cpp.gyb

+6-3
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ RC<RawSyntax> SyntaxFactory::createRaw(SyntaxKind Kind,
128128
if (I == Elements.size() ||
129129
!${check_child_condition_raw(child)}(Elements[I])) {
130130
% if child.is_optional:
131-
Layout[${child_idx}] = ${make_missing_child(child)};
131+
Layout[${child_idx}] = nullptr;
132132
% else:
133133
return nullptr;
134134
% end
@@ -183,8 +183,7 @@ SyntaxFactory::make${node.syntax_kind}(${child_params}) {
183183
auto Raw = RawSyntax::make(SyntaxKind::${node.syntax_kind}, {
184184
% for child in node.children:
185185
% if child.is_optional:
186-
${child.name}.hasValue() ? ${child.name}->getRaw() :
187-
cast<RawSyntax>(${make_missing_child(child)}),
186+
${child.name}.hasValue() ? ${child.name}->getRaw() : nullptr,
188187
% else:
189188
${child.name}.getRaw(),
190189
% end
@@ -211,7 +210,11 @@ ${node.name}
211210
SyntaxFactory::makeBlank${node.syntax_kind}() {
212211
auto raw = RawSyntax::make(SyntaxKind::${node.syntax_kind}, {
213212
% for child in node.children:
213+
% if child.is_optional:
214+
nullptr,
215+
% else:
214216
${make_missing_child(child)},
217+
% end
215218
% end
216219
}, SourcePresence::Present);
217220
return make<${node.name}>(raw);

Diff for: lib/Syntax/SyntaxNodes.cpp.gyb

+19-14
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ using namespace swift::syntax;
2727
% for node in SYNTAX_NODES:
2828
% if node.requires_validation():
2929
void ${node.name}::validate() const {
30-
if (!Data || !Data->Raw) return;
30+
#ifndef NDEBUG
3131
auto raw = Data->Raw;
3232
if (isMissing()) return;
3333
assert(raw->getLayout().size() == ${len(node.children)});
@@ -45,28 +45,25 @@ void ${node.name}::validate() const {
4545
tok::${token_kind}, ${choices});
4646
% end
4747
% if child.node_choices:
48-
#ifndef NDEBUG
49-
assert(${check_child_condition_raw(child)}(
50-
raw->getChild(Cursor::${child.name})));
51-
#endif
48+
if (auto &__Child = raw->getChild(Cursor::${child.name}))
49+
assert(${check_child_condition_raw(child)}(__Child));
5250
% end
5351
% end
52+
#endif
5453
}
5554
% end
5655

5756
% for child in node.children:
5857
% if child.is_optional:
5958
llvm::Optional<${child.type_name}> ${node.name}::get${child.name}() {
60-
if (getRaw()->getChild(Cursor::${child.name})->isMissing()) {
59+
auto ChildData = Data->getChild(Cursor::${child.name});
60+
if (!ChildData)
6161
return llvm::None;
62-
}
63-
return llvm::Optional<${child.type_name}> {
64-
${child.type_name} { Root, Data->getChild(Cursor::${child.name}).get() }
65-
};
62+
return ${child.type_name} {Root, ChildData.get()};
6663
}
6764
% else:
6865
${child.type_name} ${node.name}::get${child.name}() {
69-
return ${child.type_name} { Root, Data->getChild(Cursor::${child.name}).get() };
66+
return ${child.type_name} {Root, Data->getChild(Cursor::${child.name}).get()};
7067
}
7168
% end
7269

@@ -75,9 +72,13 @@ ${child.type_name} ${node.name}::get${child.name}() {
7572
% child_elt = child_node.collection_element_name
7673
% child_elt_type = child_node.collection_element_type
7774
${node.name} ${node.name}::add${child_elt}(${child_elt_type} ${child_elt}) {
78-
auto childRaw = getRaw()->getChild(Cursor::${child.name})
79-
->append(${child_elt}.getRaw());
80-
return Data->replaceChild<${node.name}>(childRaw, Cursor::${child.name});
75+
RC<RawSyntax> raw = getRaw()->getChild(Cursor::${child.name});
76+
if (raw)
77+
raw = raw->append(${child_elt}.getRaw());
78+
else
79+
raw = RawSyntax::make(SyntaxKind::${child_node.syntax_kind},
80+
{${child_elt}.getRaw()}, SourcePresence::Present);
81+
return Data->replaceChild<${node.name}>(raw, Cursor::${child.name});
8182
}
8283
% end
8384

@@ -87,7 +88,11 @@ ${node.name} ${node.name}::with${child.name}(
8788
if (New${child.type_name}.hasValue()) {
8889
raw = New${child.type_name}->getRaw();
8990
} else {
91+
% if child.is_optional:
92+
raw = nullptr; //${make_missing_child(child)};
93+
% else:
9094
raw = ${make_missing_child(child)};
95+
% end
9196
}
9297
return Data->replaceChild<${node.name}>(raw, Cursor::${child.name});
9398
}

Diff for: lib/Syntax/SyntaxParsingContext.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,7 @@ void SyntaxParsingContext::collectNodesInPlace(SyntaxKind ColletionKind) {
140140
auto Parts = getParts();
141141
auto Count = 0;
142142
for (auto I = Parts.rbegin(), End = Parts.rend(); I != End; ++I) {
143-
if (!SyntaxFactory::canServeAsCollectionMember(ColletionKind,
144-
make<Syntax>(*I)))
143+
if (!SyntaxFactory::canServeAsCollectionMemberRaw(ColletionKind, *I))
145144
break;
146145
++Count;
147146
}

Diff for: test/SwiftSyntax/ParseFile.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ ParseFile.test("ParseSingleFile") {
3131
let currentFile = URL(fileURLWithPath: #file)
3232
expectDoesNotThrow({
3333
let currentFileContents = try String(contentsOf: currentFile)
34-
let parsed = try Syntax.parse(currentFile)
34+
let parsed = try SourceFileSyntax.parse(currentFile)
3535
expectEqual("\(parsed)", currentFileContents)
3636
})
3737
}

0 commit comments

Comments
 (0)