@@ -81,10 +81,13 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
81
81
}
82
82
}
83
83
84
- private var root : Syntax {
85
- switch info. info! {
86
- case . root( _) : return self
87
- case . nonRoot( let info) : return info. parent. root
84
+ public var root : Syntax {
85
+ return self . withUnownedSyntax {
86
+ var node = $0
87
+ while let parent = node. parent {
88
+ node = parent
89
+ }
90
+ return node. value
88
91
}
89
92
}
90
93
@@ -129,7 +132,10 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
129
132
}
130
133
131
134
/// "designated" memberwise initializer of `Syntax`.
132
- init ( _ raw: RawSyntax , info: Info ) {
135
+ // transparent because normal inlining is too late for eliminating ARC traffic for Info.
136
+ // FIXME: Remove @_transparent after OSSA enabled.
137
+ @_transparent
138
+ init ( _ raw: RawSyntax , info: __shared Info) {
133
139
self . raw = raw
134
140
self . info = info
135
141
}
@@ -309,7 +315,7 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
309
315
/// Create a ``Syntax`` node from a specialized syntax node.
310
316
// Inline always so the optimizer can optimize this to a member access on `syntax` without having to go through
311
317
// generics.
312
- @inline ( __always )
318
+ @_transparent
313
319
public init ( _ syntax: __shared some SyntaxProtocol ) {
314
320
self = syntax. _syntaxNode
315
321
}
@@ -380,6 +386,59 @@ extension Syntax {
380
386
}
381
387
}
382
388
389
+ /// Temporary non-owning Syntax.
390
+ ///
391
+ /// This can be used for handling Syntax node without ARC traffic.
392
+ struct UnownedSyntax {
393
+ private let raw : RawSyntax
394
+ private let info : Unmanaged < Syntax . Info >
395
+
396
+ @_transparent
397
+ init ( _ node: __shared Syntax) {
398
+ self . raw = node. raw
399
+ self . info = . passUnretained( node. info. unsafelyUnwrapped)
400
+ }
401
+
402
+ /// Extract the Syntax value.
403
+ @inline ( __always)
404
+ var value : Syntax {
405
+ Syntax ( raw, info: info. takeUnretainedValue ( ) )
406
+ }
407
+
408
+ /// Get the parent of the Syntax value, but without retaining it.
409
+ @inline ( __always)
410
+ var parent : UnownedSyntax ? {
411
+ return info. _withUnsafeGuaranteedRef {
412
+ switch $0. info. unsafelyUnwrapped {
413
+ case . nonRoot( let info) :
414
+ return UnownedSyntax ( info. parent)
415
+ case . root( _) :
416
+ return nil
417
+ }
418
+ }
419
+ }
420
+
421
+ /// Temporarily use the Syntax value.
422
+ @inline ( __always)
423
+ func withValue< T> ( _ body: ( Syntax ) -> T ) -> T {
424
+ info. _withUnsafeGuaranteedRef {
425
+ body ( Syntax ( self . raw, info: $0) )
426
+ }
427
+ }
428
+ }
429
+
430
+ extension SyntaxProtocol {
431
+ /// Execute the `body` with ``UnownedSyntax`` of `node`.
432
+ ///
433
+ /// This guarantees the life time of the `node` during the `body` is executed.
434
+ @inline ( __always)
435
+ func withUnownedSyntax< T> ( _ body: ( UnownedSyntax ) -> T ) -> T {
436
+ return withExtendedLifetime ( self ) {
437
+ body ( UnownedSyntax ( Syntax ( $0) ) )
438
+ }
439
+ }
440
+ }
441
+
383
442
/// ``SyntaxNode`` used to be a pervasive type name in SwiftSyntax that has been
384
443
/// replaced by the ``Syntax`` type.
385
444
@available ( * , unavailable, message: " use 'Syntax' instead " )
0 commit comments