Skip to content

Commit e7bac89

Browse files
committed
Add casting methods to protocols
These return the non type-erased types of a node if it conforms to the given protocol and nil otherwise. With these methods returning the non type-erased type we can get rid of _asConcreteType.
1 parent 29e58b5 commit e7bac89

15 files changed

+720
-600
lines changed

Changelog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,15 @@ For increased performance, the modelling of the syntax node hierarchy has been s
101101
exprSyntax.is(IdentifierExprSyntax.self)
102102
```
103103

104+
- To retrieve the non-type erased version of a type, use the `as(_: SyntaxProtocol.self)` method
105+
106+
```swift
107+
let identifierExprSyntax: IdentifierExprSyntax = /* ... */
108+
let node = Syntax(identifierExprSyntax)
109+
node.as(SyntaxProtocol.self) // returns a IdentifierExprSyntax with static type SyntaxProtocol
110+
node.as(ExprSyntaxProtocol.self) // returns a IdentifierExprSyntax with static type ExprSyntaxProtocol?
111+
```
112+
104113

105114
- Downcasting can no longer be performed using the `as` operator. For downcasting use the `as(_: SyntaxProtocol)` method on any type eraser. ([#155](https://github.com/apple/swift-syntax/pull/155))
106115

Sources/SwiftSyntax/Misc.swift.gyb

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,16 @@ extension SyntaxNode {
3939
% end
4040
}
4141

42-
public extension Syntax {
43-
/// Retrieve the concretely typed node that this Syntax node wraps.
44-
/// This property is exposed for testing purposes only.
45-
var _asConcreteType: Any {
42+
extension Syntax {
43+
/// Syntax nodes always conform to SyntaxProtocol. This API is just added
44+
/// for consistency.
45+
@available(*, deprecated, message: "Expression always evaluates to true")
46+
public func `is`(_: SyntaxProtocol.Protocol) -> Bool {
47+
return true
48+
}
49+
50+
/// Return the non-type erased version of this syntax node.
51+
public func `as`(_: SyntaxProtocol.Protocol) -> SyntaxProtocol {
4652
switch self.as(SyntaxEnum.self) {
4753
case .token(let node):
4854
return node

Sources/SwiftSyntax/Syntax.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ extension Syntax: CustomReflectable {
5353
/// Reconstructs the real syntax type for this type from the node's kind and
5454
/// provides a mirror that reflects this type.
5555
public var customMirror: Mirror {
56-
return Mirror(reflecting: self._asConcreteType)
56+
return Mirror(reflecting: self.as(SyntaxProtocol.self))
5757
}
5858
}
5959

Sources/SwiftSyntax/SyntaxBaseNodes.swift.gyb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@
2929
/// DO NOT CONFORM TO THIS PROTOCOL YOURSELF!
3030
public protocol ${node.name}Protocol: ${base_type}Protocol {}
3131

32+
public extension Syntax {
33+
/// Check whether the non-type erased version of this syntax node conforms to
34+
/// ${node.name}Protocol.
35+
func `is`(_: ${node.name}Protocol.Protocol) -> Bool {
36+
return self.as(${node.name}Protocol.self) != nil
37+
}
38+
39+
/// Return the non-type erased version of this syntax node if it conforms to
40+
/// ${node.name}Protocol. Otherwise return nil.
41+
func `as`(_: ${node.name}Protocol.Protocol) -> ${node.name}Protocol? {
42+
return self.as(SyntaxProtocol.self) as? ${node.name}Protocol
43+
}
44+
}
45+
3246
% for line in dedented_lines(node.description):
3347
/// ${line}
3448
% end
@@ -89,7 +103,7 @@ extension ${node.name}: CustomReflectable {
89103
/// Reconstructs the real syntax type for this type from the node's kind and
90104
/// provides a mirror that reflects this type.
91105
public var customMirror: Mirror {
92-
return Mirror(reflecting: Syntax(self)._asConcreteType)
106+
return Mirror(reflecting: Syntax(self).as(SyntaxProtocol.self))
93107
}
94108
}
95109

Sources/SwiftSyntax/SyntaxNodes.swift.gyb.template

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,9 @@ extension ${node.name}: CustomReflectable {
162162
return Mirror(self, children: [
163163
% for child in node.children:
164164
% if child.is_optional:
165-
"${child.swift_name}": ${child.swift_name}.map(Syntax.init)?._asConcreteType as Any,
165+
"${child.swift_name}": ${child.swift_name}.map(Syntax.init)?.as(SyntaxProtocol.self) as Any,
166166
% else:
167-
"${child.swift_name}": Syntax(${child.swift_name})._asConcreteType,
167+
"${child.swift_name}": Syntax(${child.swift_name}).as(SyntaxProtocol.self),
168168
% end
169169
% end
170170
])

Sources/SwiftSyntax/gyb_generated/Misc.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,10 +1348,16 @@ extension SyntaxNode {
13481348
}
13491349
}
13501350

1351-
public extension Syntax {
1352-
/// Retrieve the concretely typed node that this Syntax node wraps.
1353-
/// This property is exposed for testing purposes only.
1354-
var _asConcreteType: Any {
1351+
extension Syntax {
1352+
/// Syntax nodes always conform to SyntaxProtocol. This API is just added
1353+
/// for consistency.
1354+
@available(*, deprecated, message: "Expression always evaluates to true")
1355+
public func `is`(_: SyntaxProtocol.Protocol) -> Bool {
1356+
return true
1357+
}
1358+
1359+
/// Return the non-type erased version of this syntax node.
1360+
public func `as`(_: SyntaxProtocol.Protocol) -> SyntaxProtocol {
13551361
switch self.as(SyntaxEnum.self) {
13561362
case .token(let node):
13571363
return node

Sources/SwiftSyntax/gyb_generated/SyntaxBaseNodes.swift

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@
1919
/// DO NOT CONFORM TO THIS PROTOCOL YOURSELF!
2020
public protocol DeclSyntaxProtocol: SyntaxProtocol {}
2121

22+
public extension Syntax {
23+
/// Check whether the non-type erased version of this syntax node conforms to
24+
/// DeclSyntaxProtocol.
25+
func `is`(_: DeclSyntaxProtocol.Protocol) -> Bool {
26+
return self.as(DeclSyntaxProtocol.self) != nil
27+
}
28+
29+
/// Return the non-type erased version of this syntax node if it conforms to
30+
/// DeclSyntaxProtocol. Otherwise return nil.
31+
func `as`(_: DeclSyntaxProtocol.Protocol) -> DeclSyntaxProtocol? {
32+
return self.as(SyntaxProtocol.self) as? DeclSyntaxProtocol
33+
}
34+
}
35+
2236
public struct DeclSyntax: DeclSyntaxProtocol, SyntaxHashable {
2337
public let _syntaxNode: Syntax
2438

@@ -70,7 +84,7 @@ extension DeclSyntax: CustomReflectable {
7084
/// Reconstructs the real syntax type for this type from the node's kind and
7185
/// provides a mirror that reflects this type.
7286
public var customMirror: Mirror {
73-
return Mirror(reflecting: Syntax(self)._asConcreteType)
87+
return Mirror(reflecting: Syntax(self).as(SyntaxProtocol.self))
7488
}
7589
}
7690

@@ -81,6 +95,20 @@ extension DeclSyntax: CustomReflectable {
8195
/// DO NOT CONFORM TO THIS PROTOCOL YOURSELF!
8296
public protocol ExprSyntaxProtocol: SyntaxProtocol {}
8397

98+
public extension Syntax {
99+
/// Check whether the non-type erased version of this syntax node conforms to
100+
/// ExprSyntaxProtocol.
101+
func `is`(_: ExprSyntaxProtocol.Protocol) -> Bool {
102+
return self.as(ExprSyntaxProtocol.self) != nil
103+
}
104+
105+
/// Return the non-type erased version of this syntax node if it conforms to
106+
/// ExprSyntaxProtocol. Otherwise return nil.
107+
func `as`(_: ExprSyntaxProtocol.Protocol) -> ExprSyntaxProtocol? {
108+
return self.as(SyntaxProtocol.self) as? ExprSyntaxProtocol
109+
}
110+
}
111+
84112
public struct ExprSyntax: ExprSyntaxProtocol, SyntaxHashable {
85113
public let _syntaxNode: Syntax
86114

@@ -132,7 +160,7 @@ extension ExprSyntax: CustomReflectable {
132160
/// Reconstructs the real syntax type for this type from the node's kind and
133161
/// provides a mirror that reflects this type.
134162
public var customMirror: Mirror {
135-
return Mirror(reflecting: Syntax(self)._asConcreteType)
163+
return Mirror(reflecting: Syntax(self).as(SyntaxProtocol.self))
136164
}
137165
}
138166

@@ -143,6 +171,20 @@ extension ExprSyntax: CustomReflectable {
143171
/// DO NOT CONFORM TO THIS PROTOCOL YOURSELF!
144172
public protocol StmtSyntaxProtocol: SyntaxProtocol {}
145173

174+
public extension Syntax {
175+
/// Check whether the non-type erased version of this syntax node conforms to
176+
/// StmtSyntaxProtocol.
177+
func `is`(_: StmtSyntaxProtocol.Protocol) -> Bool {
178+
return self.as(StmtSyntaxProtocol.self) != nil
179+
}
180+
181+
/// Return the non-type erased version of this syntax node if it conforms to
182+
/// StmtSyntaxProtocol. Otherwise return nil.
183+
func `as`(_: StmtSyntaxProtocol.Protocol) -> StmtSyntaxProtocol? {
184+
return self.as(SyntaxProtocol.self) as? StmtSyntaxProtocol
185+
}
186+
}
187+
146188
public struct StmtSyntax: StmtSyntaxProtocol, SyntaxHashable {
147189
public let _syntaxNode: Syntax
148190

@@ -194,7 +236,7 @@ extension StmtSyntax: CustomReflectable {
194236
/// Reconstructs the real syntax type for this type from the node's kind and
195237
/// provides a mirror that reflects this type.
196238
public var customMirror: Mirror {
197-
return Mirror(reflecting: Syntax(self)._asConcreteType)
239+
return Mirror(reflecting: Syntax(self).as(SyntaxProtocol.self))
198240
}
199241
}
200242

@@ -205,6 +247,20 @@ extension StmtSyntax: CustomReflectable {
205247
/// DO NOT CONFORM TO THIS PROTOCOL YOURSELF!
206248
public protocol TypeSyntaxProtocol: SyntaxProtocol {}
207249

250+
public extension Syntax {
251+
/// Check whether the non-type erased version of this syntax node conforms to
252+
/// TypeSyntaxProtocol.
253+
func `is`(_: TypeSyntaxProtocol.Protocol) -> Bool {
254+
return self.as(TypeSyntaxProtocol.self) != nil
255+
}
256+
257+
/// Return the non-type erased version of this syntax node if it conforms to
258+
/// TypeSyntaxProtocol. Otherwise return nil.
259+
func `as`(_: TypeSyntaxProtocol.Protocol) -> TypeSyntaxProtocol? {
260+
return self.as(SyntaxProtocol.self) as? TypeSyntaxProtocol
261+
}
262+
}
263+
208264
public struct TypeSyntax: TypeSyntaxProtocol, SyntaxHashable {
209265
public let _syntaxNode: Syntax
210266

@@ -256,7 +312,7 @@ extension TypeSyntax: CustomReflectable {
256312
/// Reconstructs the real syntax type for this type from the node's kind and
257313
/// provides a mirror that reflects this type.
258314
public var customMirror: Mirror {
259-
return Mirror(reflecting: Syntax(self)._asConcreteType)
315+
return Mirror(reflecting: Syntax(self).as(SyntaxProtocol.self))
260316
}
261317
}
262318

@@ -267,6 +323,20 @@ extension TypeSyntax: CustomReflectable {
267323
/// DO NOT CONFORM TO THIS PROTOCOL YOURSELF!
268324
public protocol PatternSyntaxProtocol: SyntaxProtocol {}
269325

326+
public extension Syntax {
327+
/// Check whether the non-type erased version of this syntax node conforms to
328+
/// PatternSyntaxProtocol.
329+
func `is`(_: PatternSyntaxProtocol.Protocol) -> Bool {
330+
return self.as(PatternSyntaxProtocol.self) != nil
331+
}
332+
333+
/// Return the non-type erased version of this syntax node if it conforms to
334+
/// PatternSyntaxProtocol. Otherwise return nil.
335+
func `as`(_: PatternSyntaxProtocol.Protocol) -> PatternSyntaxProtocol? {
336+
return self.as(SyntaxProtocol.self) as? PatternSyntaxProtocol
337+
}
338+
}
339+
270340
public struct PatternSyntax: PatternSyntaxProtocol, SyntaxHashable {
271341
public let _syntaxNode: Syntax
272342

@@ -318,7 +388,7 @@ extension PatternSyntax: CustomReflectable {
318388
/// Reconstructs the real syntax type for this type from the node's kind and
319389
/// provides a mirror that reflects this type.
320390
public var customMirror: Mirror {
321-
return Mirror(reflecting: Syntax(self)._asConcreteType)
391+
return Mirror(reflecting: Syntax(self).as(SyntaxProtocol.self))
322392
}
323393
}
324394

0 commit comments

Comments
 (0)