@@ -23,21 +23,58 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
23
23
final class Info : @unchecked Sendable {
24
24
// For root node.
25
25
struct Root : Sendable {
26
- private var arena : RetainedSyntaxArena
26
+ private let arena : RetainedSyntaxArena
27
27
28
28
init ( arena: RetainedSyntaxArena ) {
29
29
self . arena = arena
30
30
}
31
31
}
32
32
33
+ /// Class that owns a `Root`, is responsible for keeping it alive and also offers an unsafe pointer way to
34
+ /// access it.
35
+ ///
36
+ /// This way, the root node of a tree can own the root info and all other nodes in the tree can have an unsafe
37
+ /// pointer reference to the root info, which doesn't involve ref counting.
38
+ final class RefCountedRoot : Sendable {
39
+ /// `nonisolated(unsafe)` if fine because there are only two ways this gets accessed:
40
+ /// - `pointer`: Here we reference `value` via inout to get a pointer to `Root` but the pointer is not mutable
41
+ /// so no mutation happens here
42
+ #if swift(>=6)
43
+ private nonisolated ( unsafe) var value: Root
44
+ #else
45
+ private var value : Root
46
+ #endif
47
+
48
+ fileprivate init ( _ value: Root ) {
49
+ self . value = value
50
+ }
51
+
52
+ fileprivate var pointer : UnsafePointer < Root > {
53
+ return withUnsafePointer ( to: & value) { $0 }
54
+ }
55
+ }
56
+
33
57
// For non-root nodes.
34
58
struct NonRoot : Sendable {
35
59
var parent : Syntax
36
60
var absoluteInfo : AbsoluteSyntaxInfo
61
+ // `nonisolated(unsafe)` is fine because `Root` is owned by `RefCountedRoot` and `RefCountedRoot` guarantees that
62
+ // `Root` is not changing after the tree has been created.
63
+ #if swift(>=6)
64
+ nonisolated ( unsafe) var rootInfo: UnsafePointer < Root >
65
+ #else
66
+ var rootInfo : UnsafePointer < Root >
67
+ #endif
68
+
69
+ init ( parent: Syntax , absoluteInfo: AbsoluteSyntaxInfo , rootInfo: UnsafePointer < Root > ) {
70
+ self . parent = parent
71
+ self . absoluteInfo = absoluteInfo
72
+ self . rootInfo = rootInfo
73
+ }
37
74
}
38
75
39
76
enum InfoImpl : Sendable {
40
- case root( Root )
77
+ case root( RefCountedRoot )
41
78
case nonRoot( NonRoot )
42
79
}
43
80
@@ -67,9 +104,9 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
67
104
var info : Info !
68
105
let raw : RawSyntax
69
106
70
- private var rootInfo : Info . Root {
107
+ var rootInfo : UnsafePointer < Info . Root > {
71
108
switch info. info! {
72
- case . root( let info) : return info
109
+ case . root( let info) : return info. pointer
73
110
case . nonRoot( let info) : return info. parent. rootInfo
74
111
}
75
112
}
@@ -135,7 +172,7 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
135
172
}
136
173
137
174
init ( _ raw: RawSyntax , parent: Syntax , absoluteInfo: AbsoluteSyntaxInfo ) {
138
- self . init ( raw, info: Info ( . nonRoot( . init( parent: parent, absoluteInfo: absoluteInfo) ) ) )
175
+ self . init ( raw, info: Info ( . nonRoot( . init( parent: parent, absoluteInfo: absoluteInfo, rootInfo : parent . rootInfo ) ) ) )
139
176
}
140
177
141
178
/// Creates a `Syntax` with the provided raw syntax and parent.
@@ -155,12 +192,15 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
155
192
/// has a chance to retain it.
156
193
static func forRoot( _ raw: RawSyntax , rawNodeArena: RetainedSyntaxArena ) -> Syntax {
157
194
precondition ( rawNodeArena == raw. arenaReference)
158
- return Syntax ( raw, info: Info ( . root( . init ( arena: rawNodeArena) ) ) )
195
+ return Syntax ( raw, info: Info ( . root( Syntax . Info . RefCountedRoot ( Syntax . Info . Root ( arena: rawNodeArena) ) ) ) )
159
196
}
160
197
161
198
static func forRoot( _ raw: RawSyntax , rawNodeArena: SyntaxArena ) -> Syntax {
162
199
precondition ( rawNodeArena == raw. arenaReference)
163
- return Syntax ( raw, info: Info ( . root( . init( arena: RetainedSyntaxArena ( rawNodeArena) ) ) ) )
200
+ return Syntax (
201
+ raw,
202
+ info: Info ( . root( Syntax . Info. RefCountedRoot ( Syntax . Info. Root ( arena: RetainedSyntaxArena ( rawNodeArena) ) ) ) )
203
+ )
164
204
}
165
205
166
206
/// Returns the child data at the provided index in this data's layout.
0 commit comments