@@ -49,7 +49,10 @@ public class SyntaxArena {
49
49
#if DEBUG || SWIFTSYNTAX_ENABLE_ASSERTIONS
50
50
/// Whether or not this arena has been added to other arenas as a child.
51
51
/// Used to make sure we don’t introduce retain cycles between arenas.
52
- private var hasParent : Bool
52
+ ///
53
+ /// - Important: This is only intended to be used for assertions to catch
54
+ /// retain cycles in syntax arenas.
55
+ var hasParent : Bool
53
56
#endif
54
57
55
58
/// Construct a new ``SyntaxArena`` in which syntax nodes can be allocated.
@@ -146,20 +149,11 @@ public class SyntaxArena {
146
149
if childRefs. insert ( otherRef) . inserted {
147
150
otherRef. retain ( )
148
151
#if DEBUG || SWIFTSYNTAX_ENABLE_ASSERTIONS
149
- // FIXME: This may trigger a data race warning in Thread Sanitizer.
150
- // Can we use atomic bool here?
151
- otherRef. value. hasParent = true
152
+ otherRef. setHasParent ( true )
152
153
#endif
153
154
}
154
155
}
155
156
156
- /// Recursively checks if this arena contains given `arenaRef` as a descendant.
157
- func contains( arenaRef: SyntaxArenaRef ) -> Bool {
158
- childRefs. contains { childRef in
159
- childRef == arenaRef || childRef. value. contains ( arenaRef: arenaRef)
160
- }
161
- }
162
-
163
157
/// Checks if the given syntax text is managed by this arena.
164
158
///
165
159
/// "managed" means it's empty, a part of "source buffer", or in the memory
@@ -264,15 +258,15 @@ struct SyntaxArenaRef: Hashable, @unchecked Sendable {
264
258
}
265
259
266
260
/// Returns the ``SyntaxArena``
267
- var value : SyntaxArena {
261
+ private var value : SyntaxArena {
268
262
get { self . _value. takeUnretainedValue ( ) }
269
263
}
270
264
271
265
/// Assuming that this references a `ParsingSyntaxArena`,
272
266
func parseTrivia( source: SyntaxText , position: TriviaPosition ) -> [ RawTriviaPiece ] {
273
267
// It is safe to access `_value` here because `parseTrivia` only accesses
274
268
// `parseTriviaFunction`, which is a constant.
275
- ( _value . takeUnretainedValue ( ) as! ParsingSyntaxArena ) . parseTrivia ( source: source, position: position)
269
+ ( value as! ParsingSyntaxArena ) . parseTrivia ( source: source, position: position)
276
270
}
277
271
278
272
func retain( ) {
@@ -285,9 +279,25 @@ struct SyntaxArenaRef: Hashable, @unchecked Sendable {
285
279
286
280
/// Get an opaque wrapper that keeps the syntax arena alive.
287
281
var retained : RetainedSyntaxArena {
288
- return RetainedSyntaxArena ( _value. takeUnretainedValue ( ) )
282
+ return RetainedSyntaxArena ( value)
283
+ }
284
+
285
+ #if DEBUG || SWIFTSYNTAX_ENABLE_ASSERTIONS
286
+ /// Accessor for ther underlying's `SyntaxArena.hasParent`
287
+ var hasParent : Bool {
288
+ // FIXME: This accesses mutable state across actor boundaries and is thus not concurrency-safe.
289
+ // We should use an atomic for `hasParent` to make it concurrency safe.
290
+ value. hasParent
289
291
}
290
292
293
+ /// Sets the `SyntaxArena.hasParent` on the referenced arena.
294
+ func setHasParent( _ newValue: Bool ) {
295
+ // FIXME: This modifies mutable state across actor boundaries and is thus not concurrency-safe.
296
+ // We should use an atomic for `hasParent` to make it concurrency safe.
297
+ value. hasParent = newValue
298
+ }
299
+ #endif
300
+
291
301
func hash( into hasher: inout Hasher ) {
292
302
hasher. combine ( _value. toOpaque ( ) )
293
303
}
0 commit comments