@@ -81,10 +81,13 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
8181 }
8282 }
8383
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 withUnownedSyntax ( self ) {
86+ var node = $0
87+ while let parent = node. parent {
88+ node = parent
89+ }
90+ return node. value
8891 }
8992 }
9093
@@ -129,7 +132,8 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
129132 }
130133
131134 /// "designated" memberwise initializer of `Syntax`.
132- init ( _ raw: RawSyntax , info: Info ) {
135+ @_transparent
136+ init ( _ raw: RawSyntax , info: __shared Info) {
133137 self . raw = raw
134138 self . info = info
135139 }
@@ -309,7 +313,7 @@ public struct Syntax: SyntaxProtocol, SyntaxHashable {
309313 /// Create a ``Syntax`` node from a specialized syntax node.
310314 // Inline always so the optimizer can optimize this to a member access on `syntax` without having to go through
311315 // generics.
312- @inline ( __always )
316+ @_transparent
313317 public init ( _ syntax: __shared some SyntaxProtocol ) {
314318 self = syntax. _syntaxNode
315319 }
@@ -380,6 +384,57 @@ extension Syntax {
380384 }
381385}
382386
387+ /// Temporary non-owning Syntax.
388+ ///
389+ /// This can be used for handling Syntax node without ARC traffic.
390+ struct UnownedSyntax {
391+ var raw : RawSyntax
392+ var info : Unmanaged < Syntax . Info >
393+
394+ @_transparent
395+ init ( _ node: __shared Syntax) {
396+ self . raw = node. raw
397+ self . info = . passUnretained( node. info. unsafelyUnwrapped)
398+ }
399+
400+ /// Extract the Syntax value.
401+ @inline ( __always)
402+ var value : Syntax {
403+ Syntax ( raw, info: info. takeUnretainedValue ( ) )
404+ }
405+
406+ /// Get the parent of the Syntax value, but without retaining it.
407+ @inline ( __always)
408+ var parent : UnownedSyntax ? {
409+ return info. _withUnsafeGuaranteedRef {
410+ switch $0. info. unsafelyUnwrapped {
411+ case . nonRoot( let info) :
412+ return UnownedSyntax ( info. parent)
413+ case . root( _) :
414+ return nil
415+ }
416+ }
417+ }
418+
419+ /// Temporarily use the Syntax value.
420+ @inline ( __always)
421+ func withValue< T> ( _ body: ( Syntax ) -> T ) -> T {
422+ info. _withUnsafeGuaranteedRef {
423+ body ( Syntax ( self . raw, info: $0) )
424+ }
425+ }
426+ }
427+
428+ /// Execute the `body` with ``UnownedSyntax`` of `node`.
429+ ///
430+ /// This guarantees the life time of the `node` during the `body` is executed.
431+ @inline ( __always)
432+ func withUnownedSyntax< T> ( _ node: some SyntaxProtocol , _ body: ( UnownedSyntax ) -> T ) -> T {
433+ return withExtendedLifetime ( node) {
434+ body ( UnownedSyntax ( Syntax ( $0) ) )
435+ }
436+ }
437+
383438/// ``SyntaxNode`` used to be a pervasive type name in SwiftSyntax that has been
384439/// replaced by the ``Syntax`` type.
385440@available ( * , unavailable, message: " use 'Syntax' instead " )
0 commit comments