Skip to content

Commit 75f6c3f

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 76a78b5 commit 75f6c3f

File tree

6 files changed

+121
-56
lines changed

6 files changed

+121
-56
lines changed

CodeGeneration/Sources/SyntaxSupport/CompatibilityLayer.swift

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ public struct CompatibilityLayer {
1515
/// Deprecated members that the compatibility layer needs for each node.
1616
private var deprecatedMembersByNode: [SyntaxNodeKind: DeprecatedMemberInfo] = [:]
1717

18+
/// Deprecated members that the compatibility layer needs for each trait.
19+
public var deprecatedMembersByTrait: [String: DeprecatedMemberInfo] = [:]
20+
1821
/// Cache for `replacementChild(for:)`. Ensures that we don't create
1922
/// two different replacement nodes even if we refactor the same child twice.
2023
private var cachedReplacementChildren: [Child: [Child]] = [:]
@@ -24,11 +27,19 @@ public struct CompatibilityLayer {
2427
return deprecatedMembersByNode[node.kind] ?? DeprecatedMemberInfo()
2528
}
2629

27-
internal init(nodes: [Node]) {
30+
/// Returns the deprecated members that the compatibility layer needs for `trait`.
31+
public func deprecatedMembers(for trait: Trait) -> DeprecatedMemberInfo {
32+
return deprecatedMembersByTrait[trait.traitName] ?? DeprecatedMemberInfo()
33+
}
34+
35+
internal init(nodes: [Node], traits: [Trait]) {
2836
// Note that we compute these up-front, greedily, so that all of the mutation is isolated by the lazy var's state.
2937
for node in nodes {
3038
computeMembers(for: node)
3139
}
40+
for trait in traits {
41+
computeMembers(for: trait)
42+
}
3243
}
3344

3445
/// Returns the child or children that would have existed in place of this
@@ -77,22 +88,54 @@ public struct CompatibilityLayer {
7788
return
7889
}
7990

91+
let result = computeMembersFor(
92+
typeName: layoutNode.kind.rawValue,
93+
initialChildren: layoutNode.children,
94+
history: layoutNode.childHistory,
95+
areRequirements: false
96+
)
97+
98+
deprecatedMembersByNode[node.syntaxNodeKind] = result
99+
}
100+
101+
private mutating func computeMembers(for trait: Trait) {
102+
guard deprecatedMembersByTrait[trait.traitName] == nil else {
103+
return
104+
}
105+
106+
let result = computeMembersFor(
107+
typeName: trait.traitName,
108+
initialChildren: trait.children,
109+
history: trait.childHistory,
110+
areRequirements: true
111+
)
112+
113+
deprecatedMembersByTrait[trait.traitName] = result
114+
}
115+
116+
/// Compute and cache compatibility layer information for the given children.
117+
private mutating func computeMembersFor(
118+
typeName: String,
119+
initialChildren: [Child],
120+
history: Child.History,
121+
areRequirements: Bool
122+
) -> DeprecatedMemberInfo {
80123
// The results that will ultimately be saved into the DeprecatedMemberInfo.
81124
var vars: [Child] = []
82125
var initSignatures: [InitSignature] = []
83126

84127
// Temporary working state for the loop.
85-
var children = layoutNode.children
128+
var children = initialChildren
86129
var knownVars = Set(children)
87130

88131
func firstIndexOfChild(named targetName: String) -> Int {
89132
guard let i = children.firstIndex(where: { $0.name == targetName }) else {
90-
fatalError("couldn't find '\(targetName)' in current children of \(node.syntaxNodeKind.rawValue): \(String(reflecting: children.map(\.name)))")
133+
fatalError("couldn't find '\(targetName)' in current children of \(typeName): \(String(reflecting: children.map(\.name)))")
91134
}
92135
return i
93136
}
94137

95-
for changeSet in layoutNode.childHistory {
138+
for changeSet in history {
96139
var unexpectedChildrenWithNewNames: Set<Child> = []
97140

98141
// First pass: Apply the changes explicitly specified in the change set.
@@ -102,12 +145,14 @@ public struct CompatibilityLayer {
102145
let replacementChildren = replacementChildren(for: children[i], by: refactoring)
103146
children.replaceSubrange(i...i, with: replacementChildren)
104147

105-
// Mark adjacent unexpected node children whose names have changed too.
106-
if currentName != replacementChildren.first?.name {
107-
unexpectedChildrenWithNewNames.insert(children[i - 1])
108-
}
109-
if currentName != replacementChildren.last?.name {
110-
unexpectedChildrenWithNewNames.insert(children[i + replacementChildren.count])
148+
if !areRequirements {
149+
// Mark adjacent unexpected node children whose names have changed too.
150+
if currentName != replacementChildren.first?.name {
151+
unexpectedChildrenWithNewNames.insert(children[i - 1])
152+
}
153+
if currentName != replacementChildren.last?.name {
154+
unexpectedChildrenWithNewNames.insert(children[i + replacementChildren.count])
155+
}
111156
}
112157
}
113158

@@ -130,10 +175,13 @@ public struct CompatibilityLayer {
130175
// 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.
131176
vars += children.filter { knownVars.insert($0).inserted }
132177

133-
initSignatures.append(InitSignature(children: children))
178+
// We don't create compatibility layers for protocol requirement inits.
179+
if !areRequirements {
180+
initSignatures.append(InitSignature(children: children))
181+
}
134182
}
135183

136-
deprecatedMembersByNode[node.syntaxNodeKind] = DeprecatedMemberInfo(vars: vars, inits: initSignatures)
184+
return DeprecatedMemberInfo(vars: vars, inits: initSignatures)
137185
}
138186
}
139187

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_LAYER = CompatibilityLayer(nodes: SYNTAX_NODES)
39+
public let SYNTAX_COMPATIBILITY_LAYER = CompatibilityLayer(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: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,21 @@ let renamedChildrenCompatibilityFile = try! SourceFileSyntax(leadingTrivia: copy
3333
}
3434
}
3535
}
36+
37+
for trait in TRAITS.filter({ !$0.childHistory.isEmpty }) {
38+
var deprecatedMembers = SYNTAX_COMPATIBILITY_LAYER.deprecatedMembers(for: trait)
39+
40+
try ExtensionDeclSyntax("extension \(trait.protocolName)") {
41+
for child in deprecatedMembers.vars {
42+
makeCompatibilityVar(for: child)
43+
if let addMethod = makeCompatibilityAddMethod(for: child) {
44+
addMethod
45+
}
46+
}
47+
48+
// Not currently generating compatibility inits for traits.
49+
}
50+
}
3651
}
3752

3853
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)