Skip to content

Commit 4af9b16

Browse files
authored
Merge pull request #2359 from DougGregor/with-optional-code-block
Add WithOptionalCodeBlock trait and adopt it where there's a body
2 parents d5ab1c7 + ed7e66d commit 4af9b16

File tree

6 files changed

+63
-22
lines changed

6 files changed

+63
-22
lines changed

CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ public let DECL_NODES: [Node] = [
8282
base: .decl,
8383
nameForDiagnostics: "accessor",
8484
parserFunction: "parseAccessorDecl",
85-
traits: ["WithAttributes"],
85+
traits: [
86+
"WithOptionalCodeBlock",
87+
"WithAttributes",
88+
],
8689
children: [
8790
Child(
8891
name: "attributes",
@@ -493,6 +496,7 @@ public let DECL_NODES: [Node] = [
493496
traits: [
494497
"WithAttributes",
495498
"WithModifiers",
499+
"WithOptionalCodeBlock",
496500
],
497501
children: [
498502
Child(
@@ -879,6 +883,7 @@ public let DECL_NODES: [Node] = [
879883
"WithAttributes",
880884
"WithGenericParameters",
881885
"WithModifiers",
886+
"WithOptionalCodeBlock",
882887
],
883888
children: [
884889
Child(
@@ -1217,6 +1222,7 @@ public let DECL_NODES: [Node] = [
12171222
"WithAttributes",
12181223
"WithGenericParameters",
12191224
"WithModifiers",
1225+
"WithOptionalCodeBlock",
12201226
],
12211227
children: [
12221228
Child(

CodeGeneration/Sources/SyntaxSupport/Traits.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ public let TRAITS: [Trait] = [
151151
Child(name: "modifiers", kind: .node(kind: .declModifierList))
152152
]
153153
),
154+
Trait(
155+
traitName: "WithOptionalCodeBlock",
156+
children: [
157+
Child(name: "body", kind: .node(kind: .codeBlock), isOptional: true)
158+
]
159+
),
154160
Trait(
155161
traitName: "WithStatements",
156162
children: [

Release Notes/511.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
- Description: Enum to exhaustively switch over all different syntax nodes of each base type.
2121
- Pull Request: https://github.com/apple/swift-syntax/pull/2351
2222

23+
- `WithOptionalCodeBlock`
24+
- Description: A trait for syntax nodes that have an optional code block, such as `FunctionDeclSyntax` and `InitializerDeclSyntax`.
25+
- Pull Request: https://github.com/apple/swift-syntax/pull/2359
26+
2327
## API Behavior Changes
2428

2529
## Deprecations

Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ These articles are intended for developers wishing to contribute to SwiftSyntax
401401
- <doc:SwiftSyntax/WithCodeBlockSyntax>
402402
- <doc:SwiftSyntax/WithGenericParametersSyntax>
403403
- <doc:SwiftSyntax/WithModifiersSyntax>
404+
- <doc:SwiftSyntax/WithOptionalCodeBlockSyntax>
404405
- <doc:SwiftSyntax/WithStatementsSyntax>
405406
- <doc:SwiftSyntax/WithTrailingCommaSyntax>
406407

Sources/SwiftSyntax/generated/SyntaxTraits.swift

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,43 @@ public extension SyntaxProtocol {
570570
}
571571
}
572572

573+
// MARK: - WithOptionalCodeBlockSyntax
574+
575+
576+
public protocol WithOptionalCodeBlockSyntax: SyntaxProtocol {
577+
var body: CodeBlockSyntax? {
578+
get
579+
set
580+
}
581+
}
582+
583+
public extension WithOptionalCodeBlockSyntax {
584+
/// Without this function, the `with` function defined on `SyntaxProtocol`
585+
/// does not work on existentials of this protocol type.
586+
@_disfavoredOverload
587+
func with<T>(_ keyPath: WritableKeyPath<WithOptionalCodeBlockSyntax, T>, _ newChild: T) -> WithOptionalCodeBlockSyntax {
588+
var copy: WithOptionalCodeBlockSyntax = self
589+
copy[keyPath: keyPath] = newChild
590+
return copy
591+
}
592+
}
593+
594+
public extension SyntaxProtocol {
595+
/// Check whether the non-type erased version of this syntax node conforms to
596+
/// `WithOptionalCodeBlockSyntax`.
597+
/// Note that this will incur an existential conversion.
598+
func isProtocol(_: WithOptionalCodeBlockSyntax.Protocol) -> Bool {
599+
return self.asProtocol(WithOptionalCodeBlockSyntax.self) != nil
600+
}
601+
602+
/// Return the non-type erased version of this syntax node if it conforms to
603+
/// `WithOptionalCodeBlockSyntax`. Otherwise return `nil`.
604+
/// Note that this will incur an existential conversion.
605+
func asProtocol(_: WithOptionalCodeBlockSyntax.Protocol) -> WithOptionalCodeBlockSyntax? {
606+
return Syntax(self).asProtocol(SyntaxProtocol.self) as? WithOptionalCodeBlockSyntax
607+
}
608+
}
609+
573610
// MARK: - WithStatementsSyntax
574611

575612

@@ -649,7 +686,7 @@ public extension SyntaxProtocol {
649686

650687
extension AccessorBlockSyntax: BracedSyntax {}
651688

652-
extension AccessorDeclSyntax: WithAttributesSyntax {}
689+
extension AccessorDeclSyntax: WithOptionalCodeBlockSyntax, WithAttributesSyntax {}
653690

654691
extension AccessorEffectSpecifiersSyntax: EffectSpecifiersSyntax {}
655692

@@ -693,7 +730,7 @@ extension DeclNameArgumentsSyntax: ParenthesizedSyntax {}
693730

694731
extension DeferStmtSyntax: WithCodeBlockSyntax {}
695732

696-
extension DeinitializerDeclSyntax: WithAttributesSyntax, WithModifiersSyntax {}
733+
extension DeinitializerDeclSyntax: WithAttributesSyntax, WithModifiersSyntax, WithOptionalCodeBlockSyntax {}
697734

698735
extension DictionaryElementSyntax: WithTrailingCommaSyntax {}
699736

@@ -723,7 +760,7 @@ extension ExtensionDeclSyntax: DeclGroupSyntax, WithAttributesSyntax, WithModifi
723760

724761
extension ForStmtSyntax: WithCodeBlockSyntax {}
725762

726-
extension FunctionDeclSyntax: NamedDeclSyntax, WithAttributesSyntax, WithGenericParametersSyntax, WithModifiersSyntax {}
763+
extension FunctionDeclSyntax: NamedDeclSyntax, WithAttributesSyntax, WithGenericParametersSyntax, WithModifiersSyntax, WithOptionalCodeBlockSyntax {}
727764

728765
extension FunctionEffectSpecifiersSyntax: EffectSpecifiersSyntax {}
729766

@@ -747,7 +784,7 @@ extension ImportDeclSyntax: WithAttributesSyntax, WithModifiersSyntax {}
747784

748785
extension InheritedTypeSyntax: WithTrailingCommaSyntax {}
749786

750-
extension InitializerDeclSyntax: WithAttributesSyntax, WithGenericParametersSyntax, WithModifiersSyntax {}
787+
extension InitializerDeclSyntax: WithAttributesSyntax, WithGenericParametersSyntax, WithModifiersSyntax, WithOptionalCodeBlockSyntax {}
751788

752789
extension LabeledExprSyntax: WithTrailingCommaSyntax {}
753790

Sources/SwiftSyntaxBuilder/SyntaxNodeWithBody.swift

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,9 @@ extension SyntaxStringInterpolation {
4040
}
4141
}
4242

43-
// MARK: - HasCodeBlock
44-
45-
public protocol HasTrailingCodeBlock {
46-
var body: CodeBlockSyntax { get set }
43+
// MARK: - HasTrailingCodeBlock
4744

45+
public protocol HasTrailingCodeBlock: WithCodeBlockSyntax {
4846
/// Constructs a syntax node where `header` builds the text of the node before the body in braces and `bodyBuilder` is used to build the node’s body.
4947
///
5048
/// For example, you can construct
@@ -90,11 +88,9 @@ extension ForStmtSyntax: HasTrailingCodeBlock {}
9088
extension GuardStmtSyntax: HasTrailingCodeBlock {}
9189
extension WhileStmtSyntax: HasTrailingCodeBlock {}
9290

93-
// MARK: - HasOptionalCodeBlock
94-
95-
public protocol HasTrailingOptionalCodeBlock {
96-
var body: CodeBlockSyntax? { get set }
91+
// MARK: - WithOptionalCodeBlockSyntax
9792

93+
public extension WithOptionalCodeBlockSyntax where Self: DeclSyntaxProtocol {
9894
/// Constructs a syntax node where `header` builds the text of the node before the body in braces and `bodyBuilder` is used to build the node’s body.
9995
///
10096
/// For example, you can construct
@@ -114,10 +110,6 @@ public protocol HasTrailingOptionalCodeBlock {
114110
/// ```
115111
///
116112
/// Throws an error if `header` defines a different node type than the type the initializer is called on. E.g. if calling `try FunctionDeclSyntax("init") {}`
117-
init(_ header: SyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () throws -> CodeBlockItemListSyntax) throws
118-
}
119-
120-
public extension HasTrailingOptionalCodeBlock where Self: DeclSyntaxProtocol {
121113
init(_ header: SyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () throws -> CodeBlockItemListSyntax) throws {
122114
let decl = DeclSyntax("\(header) {}")
123115
guard let castedDecl = decl.as(Self.self) else {
@@ -128,11 +120,6 @@ public extension HasTrailingOptionalCodeBlock where Self: DeclSyntaxProtocol {
128120
}
129121
}
130122

131-
extension AccessorDeclSyntax: HasTrailingOptionalCodeBlock {}
132-
extension DeinitializerDeclSyntax: HasTrailingOptionalCodeBlock {}
133-
extension FunctionDeclSyntax: HasTrailingOptionalCodeBlock {}
134-
extension InitializerDeclSyntax: HasTrailingOptionalCodeBlock {}
135-
136123
// MARK: HasTrailingMemberDeclBlock
137124

138125
public protocol HasTrailingMemberDeclBlock {

0 commit comments

Comments
 (0)