Skip to content

Commit aff3411

Browse files
committed
Add an arena parameter to SyntaxData.forRoot
The `arena` parameter must be the same one that `raw` is allocated in and ensures that the arena of `raw` doesn’t get deallocated before the `SyntaxData` can retain it. This removes the need for a few `withExtendedLifetime` calls that we had earlier.
1 parent d79b876 commit aff3411

19 files changed

+748
-670
lines changed

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/ParserEntryFile.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,16 @@ let parserEntryFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
6363
"""
6464
extension \(node.kind.syntaxType): SyntaxParseable {
6565
public static func parse(from parser: inout Parser) -> Self {
66+
// Keep the parser alive so that the arena in which `raw` is allocated
67+
// doesn’t get deallocated before we have a chance to create a syntax node
68+
// from it. We can’t use `parser.arena` as the parameter to
69+
// `Syntax(raw:arena:)` because the node might have been re-used during an
70+
// incremental parse and would then live in a different arena than
71+
// `parser.arena`.
72+
defer { withExtendedLifetime(parser) {} }
6673
let node = parser.\(raw: parserFunction)()
6774
let raw = RawSyntax(parser.parseRemainder(into: node))
68-
return Syntax(raw: raw).cast(Self.self)
75+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
6976
}
7077
}
7178
"""

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxCollectionsFile.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,10 @@ let syntaxCollectionsFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
168168
DeclSyntax(
169169
"""
170170
public init(_ children: [Element]) {
171-
let data: SyntaxData = withExtendedLifetime(SyntaxArena()) { arena in
172-
let raw = RawSyntax.makeLayout(kind: SyntaxKind.\(node.varOrCaseName),
173-
from: children.map { $0.raw }, arena: arena)
174-
return SyntaxData.forRoot(raw)
175-
}
176-
self.init(data)
171+
let arena = SyntaxArena()
172+
let raw = RawSyntax.makeLayout(kind: SyntaxKind.\(node.varOrCaseName),
173+
from: children.map { $0.raw }, arena: arena)
174+
self.init(SyntaxData.forRoot(raw, arena: arena))
177175
}
178176
"""
179177
)

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxNodesFile.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func syntaxNode(emitKind: SyntaxNodeKind) -> SourceFileSyntax {
129129
"""
130130
)
131131
}
132-
StmtSyntax("return SyntaxData.forRoot(raw)")
132+
StmtSyntax("return SyntaxData.forRoot(raw, arena: arena)")
133133
}
134134
)
135135

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxRewriterFile.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
326326
let newRaw = node.raw.layoutView!.replacingLayout(with: Array(newLayout), arena: arena)
327327
// 'withExtendedLifetime' to keep 'SyntaxArena's of them alive until here.
328328
return withExtendedLifetime((arena, rewrittens)) {
329-
Syntax(raw: newRaw).cast(SyntaxType.self)
329+
Syntax(raw: newRaw, arena: arena).cast(SyntaxType.self)
330330
}
331331
} else {
332332
// No child node was rewritten. So no need to change this node as well.
@@ -342,8 +342,9 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
342342
/// a parent if `node` had one.
343343
public func rewrite(_ node: Syntax) -> Syntax {
344344
let rewritten = self.visit(node)
345-
let arena = SyntaxArena()
346-
return Syntax(node.data.replacingSelf(rewritten.raw, arena: arena))
345+
return withExtendedLifetime(rewritten) {
346+
return Syntax(node.data.replacingSelf(rewritten.raw, arena: rewritten.raw.arena))
347+
}
347348
}
348349
"""
349350
)

Sources/SwiftParser/generated/Parser+Entry.swift

Lines changed: 176 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,129 +43,289 @@ public protocol SyntaxParseable: SyntaxProtocol {
4343

4444
extension AccessorDeclSyntax: SyntaxParseable {
4545
public static func parse(from parser: inout Parser) -> Self {
46+
// Keep the parser alive so that the arena in which `raw` is allocated
47+
// doesn’t get deallocated before we have a chance to create a syntax node
48+
// from it. We can’t use `parser.arena` as the parameter to
49+
// `Syntax(raw:arena:)` because the node might have been re-used during an
50+
// incremental parse and would then live in a different arena than
51+
// `parser.arena`.
52+
defer {
53+
withExtendedLifetime(parser) {
54+
}
55+
}
4656
let node = parser.parseAccessorDecl()
4757
let raw = RawSyntax(parser.parseRemainder(into: node))
48-
return Syntax(raw: raw).cast(Self.self)
58+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
4959
}
5060
}
5161

5262
extension AttributeSyntax: SyntaxParseable {
5363
public static func parse(from parser: inout Parser) -> Self {
64+
// Keep the parser alive so that the arena in which `raw` is allocated
65+
// doesn’t get deallocated before we have a chance to create a syntax node
66+
// from it. We can’t use `parser.arena` as the parameter to
67+
// `Syntax(raw:arena:)` because the node might have been re-used during an
68+
// incremental parse and would then live in a different arena than
69+
// `parser.arena`.
70+
defer {
71+
withExtendedLifetime(parser) {
72+
}
73+
}
5474
let node = parser.parseAttribute()
5575
let raw = RawSyntax(parser.parseRemainder(into: node))
56-
return Syntax(raw: raw).cast(Self.self)
76+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
5777
}
5878
}
5979

6080
extension CatchClauseSyntax: SyntaxParseable {
6181
public static func parse(from parser: inout Parser) -> Self {
82+
// Keep the parser alive so that the arena in which `raw` is allocated
83+
// doesn’t get deallocated before we have a chance to create a syntax node
84+
// from it. We can’t use `parser.arena` as the parameter to
85+
// `Syntax(raw:arena:)` because the node might have been re-used during an
86+
// incremental parse and would then live in a different arena than
87+
// `parser.arena`.
88+
defer {
89+
withExtendedLifetime(parser) {
90+
}
91+
}
6292
let node = parser.parseCatchClause()
6393
let raw = RawSyntax(parser.parseRemainder(into: node))
64-
return Syntax(raw: raw).cast(Self.self)
94+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
6595
}
6696
}
6797

6898
extension ClosureParameterSyntax: SyntaxParseable {
6999
public static func parse(from parser: inout Parser) -> Self {
100+
// Keep the parser alive so that the arena in which `raw` is allocated
101+
// doesn’t get deallocated before we have a chance to create a syntax node
102+
// from it. We can’t use `parser.arena` as the parameter to
103+
// `Syntax(raw:arena:)` because the node might have been re-used during an
104+
// incremental parse and would then live in a different arena than
105+
// `parser.arena`.
106+
defer {
107+
withExtendedLifetime(parser) {
108+
}
109+
}
70110
let node = parser.parseClosureParameter()
71111
let raw = RawSyntax(parser.parseRemainder(into: node))
72-
return Syntax(raw: raw).cast(Self.self)
112+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
73113
}
74114
}
75115

76116
extension CodeBlockItemSyntax: SyntaxParseable {
77117
public static func parse(from parser: inout Parser) -> Self {
118+
// Keep the parser alive so that the arena in which `raw` is allocated
119+
// doesn’t get deallocated before we have a chance to create a syntax node
120+
// from it. We can’t use `parser.arena` as the parameter to
121+
// `Syntax(raw:arena:)` because the node might have been re-used during an
122+
// incremental parse and would then live in a different arena than
123+
// `parser.arena`.
124+
defer {
125+
withExtendedLifetime(parser) {
126+
}
127+
}
78128
let node = parser.parseNonOptionalCodeBlockItem()
79129
let raw = RawSyntax(parser.parseRemainder(into: node))
80-
return Syntax(raw: raw).cast(Self.self)
130+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
81131
}
82132
}
83133

84134
extension DeclSyntax: SyntaxParseable {
85135
public static func parse(from parser: inout Parser) -> Self {
136+
// Keep the parser alive so that the arena in which `raw` is allocated
137+
// doesn’t get deallocated before we have a chance to create a syntax node
138+
// from it. We can’t use `parser.arena` as the parameter to
139+
// `Syntax(raw:arena:)` because the node might have been re-used during an
140+
// incremental parse and would then live in a different arena than
141+
// `parser.arena`.
142+
defer {
143+
withExtendedLifetime(parser) {
144+
}
145+
}
86146
let node = parser.parseDeclaration()
87147
let raw = RawSyntax(parser.parseRemainder(into: node))
88-
return Syntax(raw: raw).cast(Self.self)
148+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
89149
}
90150
}
91151

92152
extension EnumCaseParameterSyntax: SyntaxParseable {
93153
public static func parse(from parser: inout Parser) -> Self {
154+
// Keep the parser alive so that the arena in which `raw` is allocated
155+
// doesn’t get deallocated before we have a chance to create a syntax node
156+
// from it. We can’t use `parser.arena` as the parameter to
157+
// `Syntax(raw:arena:)` because the node might have been re-used during an
158+
// incremental parse and would then live in a different arena than
159+
// `parser.arena`.
160+
defer {
161+
withExtendedLifetime(parser) {
162+
}
163+
}
94164
let node = parser.parseEnumCaseParameter()
95165
let raw = RawSyntax(parser.parseRemainder(into: node))
96-
return Syntax(raw: raw).cast(Self.self)
166+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
97167
}
98168
}
99169

100170
extension ExprSyntax: SyntaxParseable {
101171
public static func parse(from parser: inout Parser) -> Self {
172+
// Keep the parser alive so that the arena in which `raw` is allocated
173+
// doesn’t get deallocated before we have a chance to create a syntax node
174+
// from it. We can’t use `parser.arena` as the parameter to
175+
// `Syntax(raw:arena:)` because the node might have been re-used during an
176+
// incremental parse and would then live in a different arena than
177+
// `parser.arena`.
178+
defer {
179+
withExtendedLifetime(parser) {
180+
}
181+
}
102182
let node = parser.parseExpression()
103183
let raw = RawSyntax(parser.parseRemainder(into: node))
104-
return Syntax(raw: raw).cast(Self.self)
184+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
105185
}
106186
}
107187

108188
extension FunctionParameterSyntax: SyntaxParseable {
109189
public static func parse(from parser: inout Parser) -> Self {
190+
// Keep the parser alive so that the arena in which `raw` is allocated
191+
// doesn’t get deallocated before we have a chance to create a syntax node
192+
// from it. We can’t use `parser.arena` as the parameter to
193+
// `Syntax(raw:arena:)` because the node might have been re-used during an
194+
// incremental parse and would then live in a different arena than
195+
// `parser.arena`.
196+
defer {
197+
withExtendedLifetime(parser) {
198+
}
199+
}
110200
let node = parser.parseFunctionParameter()
111201
let raw = RawSyntax(parser.parseRemainder(into: node))
112-
return Syntax(raw: raw).cast(Self.self)
202+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
113203
}
114204
}
115205

116206
extension GenericParameterClauseSyntax: SyntaxParseable {
117207
public static func parse(from parser: inout Parser) -> Self {
208+
// Keep the parser alive so that the arena in which `raw` is allocated
209+
// doesn’t get deallocated before we have a chance to create a syntax node
210+
// from it. We can’t use `parser.arena` as the parameter to
211+
// `Syntax(raw:arena:)` because the node might have been re-used during an
212+
// incremental parse and would then live in a different arena than
213+
// `parser.arena`.
214+
defer {
215+
withExtendedLifetime(parser) {
216+
}
217+
}
118218
let node = parser.parseGenericParameters()
119219
let raw = RawSyntax(parser.parseRemainder(into: node))
120-
return Syntax(raw: raw).cast(Self.self)
220+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
121221
}
122222
}
123223

124224
extension MemberDeclBlockSyntax: SyntaxParseable {
125225
public static func parse(from parser: inout Parser) -> Self {
226+
// Keep the parser alive so that the arena in which `raw` is allocated
227+
// doesn’t get deallocated before we have a chance to create a syntax node
228+
// from it. We can’t use `parser.arena` as the parameter to
229+
// `Syntax(raw:arena:)` because the node might have been re-used during an
230+
// incremental parse and would then live in a different arena than
231+
// `parser.arena`.
232+
defer {
233+
withExtendedLifetime(parser) {
234+
}
235+
}
126236
let node = parser.parseMemberDeclList()
127237
let raw = RawSyntax(parser.parseRemainder(into: node))
128-
return Syntax(raw: raw).cast(Self.self)
238+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
129239
}
130240
}
131241

132242
extension PatternSyntax: SyntaxParseable {
133243
public static func parse(from parser: inout Parser) -> Self {
244+
// Keep the parser alive so that the arena in which `raw` is allocated
245+
// doesn’t get deallocated before we have a chance to create a syntax node
246+
// from it. We can’t use `parser.arena` as the parameter to
247+
// `Syntax(raw:arena:)` because the node might have been re-used during an
248+
// incremental parse and would then live in a different arena than
249+
// `parser.arena`.
250+
defer {
251+
withExtendedLifetime(parser) {
252+
}
253+
}
134254
let node = parser.parsePattern()
135255
let raw = RawSyntax(parser.parseRemainder(into: node))
136-
return Syntax(raw: raw).cast(Self.self)
256+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
137257
}
138258
}
139259

140260
extension SourceFileSyntax: SyntaxParseable {
141261
public static func parse(from parser: inout Parser) -> Self {
262+
// Keep the parser alive so that the arena in which `raw` is allocated
263+
// doesn’t get deallocated before we have a chance to create a syntax node
264+
// from it. We can’t use `parser.arena` as the parameter to
265+
// `Syntax(raw:arena:)` because the node might have been re-used during an
266+
// incremental parse and would then live in a different arena than
267+
// `parser.arena`.
268+
defer {
269+
withExtendedLifetime(parser) {
270+
}
271+
}
142272
let node = parser.parseSourceFile()
143273
let raw = RawSyntax(parser.parseRemainder(into: node))
144-
return Syntax(raw: raw).cast(Self.self)
274+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
145275
}
146276
}
147277

148278
extension StmtSyntax: SyntaxParseable {
149279
public static func parse(from parser: inout Parser) -> Self {
280+
// Keep the parser alive so that the arena in which `raw` is allocated
281+
// doesn’t get deallocated before we have a chance to create a syntax node
282+
// from it. We can’t use `parser.arena` as the parameter to
283+
// `Syntax(raw:arena:)` because the node might have been re-used during an
284+
// incremental parse and would then live in a different arena than
285+
// `parser.arena`.
286+
defer {
287+
withExtendedLifetime(parser) {
288+
}
289+
}
150290
let node = parser.parseStatement()
151291
let raw = RawSyntax(parser.parseRemainder(into: node))
152-
return Syntax(raw: raw).cast(Self.self)
292+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
153293
}
154294
}
155295

156296
extension SwitchCaseSyntax: SyntaxParseable {
157297
public static func parse(from parser: inout Parser) -> Self {
298+
// Keep the parser alive so that the arena in which `raw` is allocated
299+
// doesn’t get deallocated before we have a chance to create a syntax node
300+
// from it. We can’t use `parser.arena` as the parameter to
301+
// `Syntax(raw:arena:)` because the node might have been re-used during an
302+
// incremental parse and would then live in a different arena than
303+
// `parser.arena`.
304+
defer {
305+
withExtendedLifetime(parser) {
306+
}
307+
}
158308
let node = parser.parseSwitchCase()
159309
let raw = RawSyntax(parser.parseRemainder(into: node))
160-
return Syntax(raw: raw).cast(Self.self)
310+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
161311
}
162312
}
163313

164314
extension TypeSyntax: SyntaxParseable {
165315
public static func parse(from parser: inout Parser) -> Self {
316+
// Keep the parser alive so that the arena in which `raw` is allocated
317+
// doesn’t get deallocated before we have a chance to create a syntax node
318+
// from it. We can’t use `parser.arena` as the parameter to
319+
// `Syntax(raw:arena:)` because the node might have been re-used during an
320+
// incremental parse and would then live in a different arena than
321+
// `parser.arena`.
322+
defer {
323+
withExtendedLifetime(parser) {
324+
}
325+
}
166326
let node = parser.parseType()
167327
let raw = RawSyntax(parser.parseRemainder(into: node))
168-
return Syntax(raw: raw).cast(Self.self)
328+
return Syntax(raw: raw, arena: raw.arena).cast(Self.self)
169329
}
170330
}
171331

Sources/SwiftSyntax/Raw/RawSyntax.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,8 @@ public struct RawSyntax {
209209
rawData.arenaReference
210210
}
211211

212-
internal var arena: SyntaxArena {
212+
@_spi(RawSyntax)
213+
public var arena: SyntaxArena {
213214
rawData.arenaReference.value
214215
}
215216

0 commit comments

Comments
 (0)