Skip to content

Commit d20743c

Browse files
committed
[NFC-ish] Support child history for traits
It’s always been possible to specify deprecated children, but nothing was actually done with the info until now. Turns some manaully-generated decls into automatically-generated ones, but doesn’t change anything user-facing.
1 parent 34b2244 commit d20743c

File tree

6 files changed

+123
-58
lines changed

6 files changed

+123
-58
lines changed

CodeGeneration/Sources/SyntaxSupport/CompatibilityLayers.swift

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,19 @@ public struct CompatibilityLayers /*: Sendable*/ {
1818
/// Initializer signatures that are needed in the compatibility layer, in the order they ought to appear in the generated file.
1919
public var deprecatedInitSignaturesByNode: [SyntaxNodeKind: [InitSignature]] = [:]
2020

21-
internal init(nodes: [Node]) {
21+
/// Properties that are needed in the compatibility layer, in the order they ought to appear in the generated file.
22+
public var deprecatedVarsByTrait: [String: [Child]] = [:]
23+
24+
/// Initializer signatures that are needed in the compatibility layer, in the order they ought to appear in the generated file.
25+
public var deprecatedInitSignaturesByTrait: [String: [InitSignature]] = [:]
26+
27+
internal init(nodes: [Node], traits: [Trait]) {
2228
for node in nodes {
2329
realizeLayers(for: node)
2430
}
31+
for trait in traits {
32+
realizeLayers(for: trait)
33+
}
2534
}
2635

2736
/// Returns the child or children that would have existed in place of this
@@ -51,26 +60,60 @@ public struct CompatibilityLayers /*: Sendable*/ {
5160

5261
/// Compute and cache compatibility layer information for the given node, unless it is already present.
5362
private mutating func realizeLayers(for node: Node) {
54-
guard deprecatedVarsByNode[node.syntaxNodeKind] == nil && deprecatedInitSignaturesByNode[node.syntaxNodeKind] == nil, let layoutNode = node.layoutNode else {
63+
guard deprecatedVarsByNode[node.syntaxNodeKind] == nil, let layoutNode = node.layoutNode else {
64+
return
65+
}
66+
67+
let result = computeLayersFor(
68+
typeName: layoutNode.kind.rawValue,
69+
initialChildren: layoutNode.children,
70+
history: layoutNode.childHistory,
71+
areRequirements: false
72+
)
73+
74+
deprecatedVarsByNode[node.syntaxNodeKind] = result.vars
75+
deprecatedInitSignaturesByNode[node.syntaxNodeKind] = result.initSignatures
76+
}
77+
78+
private mutating func realizeLayers(for trait: Trait) {
79+
guard deprecatedVarsByTrait[trait.traitName] == nil else {
5580
return
5681
}
5782

83+
let result = computeLayersFor(
84+
typeName: trait.traitName,
85+
initialChildren: trait.children,
86+
history: trait.childHistory,
87+
areRequirements: true
88+
)
89+
90+
deprecatedVarsByTrait[trait.traitName] = result.vars
91+
deprecatedInitSignaturesByTrait[trait.traitName] = result.initSignatures
92+
}
93+
94+
/// Compute and cache compatibility layer information for the given children.
95+
private mutating func computeLayersFor(
96+
typeName: String,
97+
initialChildren: [Child],
98+
history: Child.History,
99+
areRequirements: Bool
100+
) -> (vars: [Child], initSignatures: [InitSignature]) {
58101
// The results that will ultimately be saved into the *ByNode dictionaries.
59102
var vars: [Child] = []
60103
var initSignatures: [InitSignature] = []
61104

62105
// Temporary working state for the loop.
63-
var children = layoutNode.children
106+
var children = initialChildren
64107
var knownVars = Set(children)
65108

66109
func firstIndexOfChild(named targetName: String) -> Int {
67110
guard let i = children.firstIndex(where: { $0.name == targetName }) else {
68-
fatalError("couldn't find '\(targetName)' in current children of \(node.syntaxNodeKind.rawValue): \(String(reflecting: children.map(\.name)))")
111+
fatalError("couldn't find '\(targetName)' in current children of \(typeName): \(String(reflecting: children.map(\.name)))")
69112
}
70113
return i
71114
}
72115

73-
for changeSet in layoutNode.childHistory {
116+
for changeSet in history {
74117
var unexpectedChildrenWithNewNames: Set<Child> = []
75118

76119
// First pass: Apply the changes explicitly specified in the change set.
@@ -80,12 +123,14 @@ public struct CompatibilityLayers /*: Sendable*/ {
80123
let replacementChildren = replacementChildren(for: children[i], by: refactoring)
81124
children.replaceSubrange(i...i, with: replacementChildren)
82125

83-
// Mark adjacented unexpected node children whose names have changed too.
84-
if currentName != (replacementChildren.first?.name ?? "") {
85-
unexpectedChildrenWithNewNames.insert(children[i - 1])
86-
}
87-
if currentName != (replacementChildren.last?.name ?? "") {
88-
unexpectedChildrenWithNewNames.insert(children[i + replacementChildren.count])
126+
if !areRequirements {
127+
// Mark adjacent unexpected node children whose names have changed too.
128+
if currentName != (replacementChildren.first?.name ?? "") {
129+
unexpectedChildrenWithNewNames.insert(children[i - 1])
130+
}
131+
if currentName != (replacementChildren.last?.name ?? "") {
132+
unexpectedChildrenWithNewNames.insert(children[i + replacementChildren.count])
133+
}
89134
}
90135
}
91136

@@ -108,11 +153,13 @@ public struct CompatibilityLayers /*: Sendable*/ {
108153
// Third pass: Append newly-created children to vars. We do this now so that changes from the first two passes are properly interleaved, preserving source order.
109154
vars += children.filter { knownVars.insert($0).inserted }
110155

111-
initSignatures.append(InitSignature(children: children))
156+
// We don't create compatibility layers for protocol requirement inits.
157+
if !areRequirements {
158+
initSignatures.append(InitSignature(children: children))
159+
}
112160
}
113161

114-
deprecatedVarsByNode[node.syntaxNodeKind] = vars
115-
deprecatedInitSignaturesByNode[node.syntaxNodeKind] = initSignatures
162+
return (vars, initSignatures)
116163
}
117164
}
118165

CodeGeneration/Sources/SyntaxSupport/SyntaxNodes.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ public let SYNTAX_NODE_MAP: [SyntaxNodeKind: Node] = Dictionary(
3636

3737
public let NON_BASE_SYNTAX_NODES = SYNTAX_NODES.filter { !$0.kind.isBase }
3838

39-
public let SYNTAX_COMPATIBILITY_LAYERS = CompatibilityLayers(nodes: SYNTAX_NODES)
39+
public let SYNTAX_COMPATIBILITY_LAYERS = CompatibilityLayers(nodes: SYNTAX_NODES, traits: TRAITS)

CodeGeneration/Sources/SyntaxSupport/Traits.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class Trait {
2222
public let protocolName: TokenSyntax
2323
public let documentation: SwiftSyntax.Trivia
2424
public let children: [Child]
25+
public let childHistory: Child.History
2526

2627
init(traitName: String, baseKind: SyntaxNodeKind? = nil, documentation: String? = nil, children: [Child], childHistory: Child.History = []) {
2728
precondition(baseKind?.isBase != false, "`baseKind` must be a base syntax node kind")
@@ -30,7 +31,7 @@ public class Trait {
3031
self.protocolName = .identifier("\(traitName)Syntax")
3132
self.documentation = SwiftSyntax.Trivia.docCommentTrivia(from: documentation)
3233
self.children = children
33-
// FIXME: We don't appear to have ever generated compatibility layers for children of traits!
34+
self.childHistory = childHistory
3435
}
3536
}
3637

@@ -98,6 +99,7 @@ public let TRAITS: [Trait] = [
9899
"pound": .renamed(from: "poundToken"),
99100
"macroName": .renamed(from: "macro"),
100101
"arguments": .renamed(from: "argumentList"),
102+
"genericArgumentClause": .renamed(from: "genericArguments"),
101103
]
102104
]
103105
),

CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/RenamedChildrenCompatibilityFile.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ let renamedChildrenCompatibilityFile = try! SourceFileSyntax(leadingTrivia: copy
3535
}
3636
}
3737
}
38+
39+
for trait in TRAITS.filter({ !$0.childHistory.isEmpty }) {
40+
var deprecatedVars = SYNTAX_COMPATIBILITY_LAYERS.deprecatedVarsByTrait[trait.traitName] ?? []
41+
var deprecatedArgLists = SYNTAX_COMPATIBILITY_LAYERS.deprecatedInitSignaturesByTrait[trait.traitName] ?? []
42+
43+
try ExtensionDeclSyntax("extension \(trait.protocolName)") {
44+
for child in deprecatedVars {
45+
makeCompatibilityVar(for: child)
46+
if let addMethod = makeCompatibilityAddMethod(for: child) {
47+
addMethod
48+
}
49+
}
50+
51+
// Not currently generating compatibility inits for traits.
52+
}
53+
}
3854
}
3955

4056
func makeCompatibilityVar(for child: Child) -> DeclSyntax {

Sources/SwiftSyntax/SwiftSyntaxCompatibility.swift

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -350,48 +350,6 @@ extension FunctionEffectSpecifiersSyntax {
350350
}
351351
}
352352

353-
extension FreestandingMacroExpansionSyntax {
354-
@available(*, deprecated, renamed: "pound")
355-
public var poundToken: TokenSyntax {
356-
get {
357-
return pound
358-
}
359-
set {
360-
pound = newValue
361-
}
362-
}
363-
364-
@available(*, deprecated, renamed: "macroName")
365-
public var macro: TokenSyntax {
366-
get {
367-
return macroName
368-
}
369-
set {
370-
macroName = newValue
371-
}
372-
}
373-
374-
@available(*, deprecated, renamed: "genericArgumentClause")
375-
public var genericArguments: GenericArgumentClauseSyntax? {
376-
get {
377-
return genericArgumentClause
378-
}
379-
set {
380-
genericArgumentClause = newValue
381-
}
382-
}
383-
384-
@available(*, deprecated, renamed: "arguments")
385-
public var argumentList: LabeledExprListSyntax {
386-
get {
387-
return arguments
388-
}
389-
set {
390-
arguments = newValue
391-
}
392-
}
393-
}
394-
395353
extension GenericRequirementSyntax {
396354
@available(*, deprecated, renamed: "Requirement")
397355
public typealias Body = Requirement

Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8559,3 +8559,45 @@ extension YieldedExpressionsClauseSyntax {
85598559
)
85608560
}
85618561
}
8562+
8563+
extension FreestandingMacroExpansionSyntax {
8564+
@available(*, deprecated, renamed: "pound")
8565+
public var poundToken: TokenSyntax {
8566+
get {
8567+
return pound
8568+
}
8569+
set {
8570+
pound = newValue
8571+
}
8572+
}
8573+
8574+
@available(*, deprecated, renamed: "macroName")
8575+
public var macro: TokenSyntax {
8576+
get {
8577+
return macroName
8578+
}
8579+
set {
8580+
macroName = newValue
8581+
}
8582+
}
8583+
8584+
@available(*, deprecated, renamed: "genericArgumentClause")
8585+
public var genericArguments: GenericArgumentClauseSyntax? {
8586+
get {
8587+
return genericArgumentClause
8588+
}
8589+
set {
8590+
genericArgumentClause = newValue
8591+
}
8592+
}
8593+
8594+
@available(*, deprecated, renamed: "arguments")
8595+
public var argumentList: LabeledExprListSyntax {
8596+
get {
8597+
return arguments
8598+
}
8599+
set {
8600+
arguments = newValue
8601+
}
8602+
}
8603+
}

0 commit comments

Comments
 (0)