Skip to content

Commit a57f3be

Browse files
authored
Merge pull request #2933 from swiftlang/revert-2925-syntax-data-arena
Revert "[Syntax] Use BumpPtrAllocator for Syntax node internals"
2 parents 56a746d + 71e1cee commit a57f3be

28 files changed

+902
-608
lines changed

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

+14-4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
4242
"""
4343
)
4444

45+
DeclSyntax(
46+
"""
47+
/// 'Syntax' object factory recycling 'Syntax.Info' instances.
48+
private let nodeFactory: SyntaxNodeFactory = SyntaxNodeFactory()
49+
"""
50+
)
51+
4552
DeclSyntax(
4653
"""
4754
public init(viewMode: SyntaxTreeViewMode = .sourceAccurate) {
@@ -323,11 +330,11 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
323330
// with 'Syntax'
324331
var rewrittens: ContiguousArray<RetainedSyntaxArena> = []
325332
326-
for case let childDataRef? in node.layoutBuffer where viewMode.shouldTraverse(node: childDataRef.pointee.raw) {
333+
for case let (child?, info) in RawSyntaxChildren(node) where viewMode.shouldTraverse(node: child) {
327334
328335
// Build the Syntax node to rewrite
329-
let childNode = visitImpl(Syntax(arena: node.arena, dataRef: childDataRef))
330-
if childNode.raw.id != childDataRef.pointee.raw.id {
336+
var childNode = visitImpl(nodeFactory.create(parent: node, raw: child, absoluteInfo: info))
337+
if childNode.raw.id != child.id {
331338
// The node was rewritten, let's handle it
332339
333340
if newLayout.baseAddress == nil {
@@ -338,10 +345,13 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
338345
}
339346
340347
// Update the rewritten child.
341-
newLayout[Int(childDataRef.pointee.absoluteInfo.layoutIndexInParent)] = childNode.raw
348+
newLayout[Int(info.indexInParent)] = childNode.raw
342349
// Retain the syntax arena of the new node until it's wrapped with Syntax node.
343350
rewrittens.append(childNode.raw.arenaReference.retained)
344351
}
352+
353+
// Recycle 'childNode.info'
354+
nodeFactory.dispose(&childNode)
345355
}
346356
347357
if newLayout.baseAddress != nil {

CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/SyntaxVisitorFile.swift

+11-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ let syntaxVisitorFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
3232
try! ClassDeclSyntax("open class SyntaxVisitor") {
3333
DeclSyntax("public let viewMode: SyntaxTreeViewMode")
3434

35+
DeclSyntax(
36+
"""
37+
/// 'Syntax' object factory recycling 'Syntax.Info' instances.
38+
private let nodeFactory: SyntaxNodeFactory = SyntaxNodeFactory()
39+
"""
40+
)
41+
3542
DeclSyntax(
3643
"""
3744
public init(viewMode: SyntaxTreeViewMode) {
@@ -214,8 +221,10 @@ let syntaxVisitorFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
214221
DeclSyntax(
215222
"""
216223
private func visitChildren(_ node: Syntax) {
217-
for case let childDataRef? in node.layoutBuffer where viewMode.shouldTraverse(node: childDataRef.pointee.raw) {
218-
dispatchVisit(Syntax(arena: node.arena, dataRef: childDataRef))
224+
for case let (child?, info) in RawSyntaxChildren(node) where viewMode.shouldTraverse(node: child) {
225+
var childNode = nodeFactory.create(parent: node, raw: child, absoluteInfo: info)
226+
dispatchVisit(childNode)
227+
nodeFactory.dispose(&childNode)
219228
}
220229
}
221230
"""

Release Notes/602.md

-6
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@
2020
- Migration steps: Do not use `SyntaxArena` or `ParsingSyntaxArena` directly.
2121
- Notes: Although the type itself was `public`, most initializers were already SPI and there was no way to retrive them from existing types via public API.
2222

23-
- `SyntaxChildrenIndex` is no longer `ExpressibleByNilLiteral`
24-
- Description: `nil` used to represent the end index. However, due to a change in the internal structure, the end index must now be retrieved from the collection.
25-
- Pull Request: https://github.com/swiftlang/swift-syntax/pull/2925
26-
- Migration steps: Use `SyntaxChildren.endIndex` instead.
27-
- Notes: `ExpressibleByNilLiteral` was a mistake. In general, `Collection.Index` should only be created and managed by the collection itself. For example, `Collection.index(after:)` exists, but `Index.advanced(by:)` does not.
28-
2923
## Template
3024

3125
- *Affected API or two word description*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
struct AbsoluteRawSyntax: Sendable {
14+
let raw: RawSyntax
15+
let info: AbsoluteSyntaxInfo
16+
17+
/// Returns first `present` child.
18+
func firstChild(viewMode: SyntaxTreeViewMode) -> AbsoluteRawSyntax? {
19+
guard let layoutView = raw.layoutView else { return nil }
20+
var curInfo = info.advancedToFirstChild()
21+
for childOpt in layoutView.children {
22+
if let child = childOpt, viewMode.shouldTraverse(node: child) {
23+
return AbsoluteRawSyntax(raw: child, info: curInfo)
24+
}
25+
curInfo = curInfo.advancedBySibling(childOpt)
26+
}
27+
return nil
28+
}
29+
30+
/// Returns next `present` sibling.
31+
func nextSibling(parent: AbsoluteRawSyntax, viewMode: SyntaxTreeViewMode) -> AbsoluteRawSyntax? {
32+
var curInfo = info.advancedBySibling(raw)
33+
for siblingOpt in parent.raw.layoutView!.children.dropFirst(Int(info.indexInParent + 1)) {
34+
if let sibling = siblingOpt, viewMode.shouldTraverse(node: sibling) {
35+
return AbsoluteRawSyntax(raw: sibling, info: curInfo)
36+
}
37+
curInfo = curInfo.advancedBySibling(siblingOpt)
38+
}
39+
return nil
40+
}
41+
42+
func replacingSelf(_ newRaw: RawSyntax, newRootId: UInt) -> AbsoluteRawSyntax {
43+
let nodeId = SyntaxIdentifier(rootId: newRootId, indexInTree: info.nodeId.indexInTree)
44+
let newInfo = AbsoluteSyntaxInfo(position: info.position, nodeId: nodeId)
45+
return .init(raw: newRaw, info: newInfo)
46+
}
47+
}

Sources/SwiftSyntax/AbsoluteSyntaxInfo.swift

+33-36
Original file line numberDiff line numberDiff line change
@@ -2,60 +2,57 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
struct AbsoluteSyntaxPosition: Sendable {
14+
/// The UTF-8 offset of the syntax node in the source file
15+
let offset: UInt32
16+
let indexInParent: UInt32
17+
18+
func advancedBySibling(_ raw: RawSyntax?) -> AbsoluteSyntaxPosition {
19+
let newOffset = self.offset + UInt32(truncatingIfNeeded: raw?.totalLength.utf8Length ?? 0)
20+
let newIndexInParent = self.indexInParent + 1
21+
return .init(offset: newOffset, indexInParent: newIndexInParent)
22+
}
23+
24+
func advancedToFirstChild() -> AbsoluteSyntaxPosition {
25+
return .init(offset: self.offset, indexInParent: 0)
26+
}
27+
28+
static var forRoot: AbsoluteSyntaxPosition {
29+
return .init(offset: 0, indexInParent: 0)
30+
}
31+
}
32+
1333
/// `AbsoluteSyntaxInfo` represents the information that relates a `RawSyntax`
1434
/// to a source file tree, like its absolute source offset.
1535
struct AbsoluteSyntaxInfo: Sendable {
16-
/// The UTF-8 offset at which the syntax node’s leading trivia start in the source file.
17-
let offset: UInt32
18-
19-
/// Index in parent's layout. Note that this counts `nil` children.
20-
let layoutIndexInParent: UInt32
36+
let position: AbsoluteSyntaxPosition
37+
let nodeId: SyntaxIdentifier
2138

22-
/// Index of the node when traversing the syntax tree using a depth-first traversal.
23-
/// This skips `nil` children in the parent's layout.
24-
let indexInTree: UInt32
39+
/// The UTF-8 offset of the syntax node in the source file
40+
var offset: UInt32 { return position.offset }
41+
var indexInParent: UInt32 { return position.indexInParent }
2542

2643
func advancedBySibling(_ raw: RawSyntax?) -> AbsoluteSyntaxInfo {
27-
if let raw {
28-
// '&+' operations are safe because we have the preconditions in 'forRoot(_:)'.
29-
return AbsoluteSyntaxInfo(
30-
offset: offset &+ UInt32(truncatingIfNeeded: raw.totalLength.utf8Length),
31-
layoutIndexInParent: layoutIndexInParent &+ 1,
32-
indexInTree: indexInTree &+ UInt32(truncatingIfNeeded: raw.totalNodes)
33-
)
34-
} else {
35-
return AbsoluteSyntaxInfo(
36-
offset: offset,
37-
layoutIndexInParent: layoutIndexInParent &+ 1,
38-
indexInTree: indexInTree
39-
)
40-
}
44+
let newPosition = position.advancedBySibling(raw)
45+
let newNodeId = nodeId.advancedBySibling(raw)
46+
return .init(position: newPosition, nodeId: newNodeId)
4147
}
4248

4349
func advancedToFirstChild() -> AbsoluteSyntaxInfo {
44-
return AbsoluteSyntaxInfo(
45-
offset: offset,
46-
layoutIndexInParent: 0,
47-
indexInTree: indexInTree &+ 1
48-
)
50+
let newPosition = position.advancedToFirstChild()
51+
let newNodeId = nodeId.advancedToFirstChild()
52+
return .init(position: newPosition, nodeId: newNodeId)
4953
}
5054

5155
static func forRoot(_ raw: RawSyntax) -> AbsoluteSyntaxInfo {
52-
// These checks ensure the safety of the unchecked arithmetic operations in 'advancedBySibling(_:)'.
53-
precondition(raw.totalLength.utf8Length <= UInt32.max, "too long")
54-
precondition(raw.totalNodes <= UInt32.max, "too many nodes")
55-
return AbsoluteSyntaxInfo(
56-
offset: 0,
57-
layoutIndexInParent: 0,
58-
indexInTree: 0
59-
)
56+
return .init(position: .forRoot, nodeId: .forRoot(raw))
6057
}
6158
}

Sources/SwiftSyntax/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
add_swift_syntax_library(SwiftSyntax
1010
AbsolutePosition.swift
11+
AbsoluteRawSyntax.swift
1112
AbsoluteSyntaxInfo.swift
1213
Assert.swift
1314
BumpPtrAllocator.swift
@@ -30,6 +31,7 @@ add_swift_syntax_library(SwiftSyntax
3031
SyntaxCollection.swift
3132
SyntaxHashable.swift
3233
SyntaxIdentifier.swift
34+
SyntaxNodeFactory.swift
3335
SyntaxNodeStructure.swift
3436
SyntaxProtocol.swift
3537
SyntaxText.swift

Sources/SwiftSyntax/MemoryLayout.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
// See `MemoryLayoutTest.swift`.
1414
@_spi(Testing) public enum SyntaxMemoryLayout: Sendable {
1515
public struct Value: Equatable, Sendable {
16-
public let size: Int
17-
public let stride: Int
18-
public let alignment: Int
16+
var size: Int
17+
var stride: Int
18+
var alignment: Int
1919

2020
public init(size: Int, stride: Int, alignment: Int) {
2121
self.size = size

Sources/SwiftSyntax/Raw/RawSyntax.swift

+3-10
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,10 @@ extension RawSyntaxData.ParsedToken {
186186

187187
extension RawSyntaxData.MaterializedToken {
188188
var leadingTrivia: RawTriviaPieceBuffer {
189-
RawTriviaPieceBuffer(rebasing: triviaPieces[..<Int(numLeadingTrivia)])
189+
triviaPieces[..<Int(numLeadingTrivia)]
190190
}
191191
var trailingTrivia: RawTriviaPieceBuffer {
192-
RawTriviaPieceBuffer(rebasing: triviaPieces[Int(numLeadingTrivia)...])
192+
triviaPieces[Int(numLeadingTrivia)...]
193193
}
194194
}
195195

@@ -954,7 +954,7 @@ extension RawSyntax {
954954
extension RawSyntax: Identifiable {
955955
public struct ID: Hashable, @unchecked Sendable {
956956
/// The pointer to the start of the `RawSyntax` node.
957-
fileprivate var pointer: UnsafeRawPointer
957+
private var pointer: UnsafeRawPointer
958958
fileprivate init(_ raw: RawSyntax) {
959959
self.pointer = raw.pointer.unsafeRawPointer
960960
}
@@ -965,13 +965,6 @@ extension RawSyntax: Identifiable {
965965
}
966966
}
967967

968-
extension UInt {
969-
/// Convert `RawSymtax.ID` to `UInt`. Lossless.
970-
init(rawID: RawSyntax.ID) {
971-
self.init(bitPattern: rawID.pointer)
972-
}
973-
}
974-
975968
/// See `SyntaxMemoryLayout`.
976969
let RawSyntaxDataMemoryLayouts: [String: SyntaxMemoryLayout.Value] = [
977970
"RawSyntaxData": .init(RawSyntaxData.self),

0 commit comments

Comments
 (0)