8000 re-implement replacement logic inside MacroReplacement.swift · swiftlang/swift-syntax@87176ef · GitHub
[go: up one dir, main page]

Skip to content

Commit 87176ef

Browse files
committed
re-implement replacement logic inside MacroReplacement.swift
1 parent f8b70bb commit 87176ef

File tree

3 files changed

+102
-37
lines changed

3 files changed

+102
-37
lines changed

Release Notes/511.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
- `String.isValidIdentifier(for:)`
3636
- Description: `SwiftParser` adds an extension on `String` to check if it can be used as an identifier in a given context.
3737
- Pull Request: https://github.com/apple/swift-syntax/pull/2434
38+
39+
- `MacroDeclSyntax.expand`
40+
- the `expand(argumentList:definition:replacements:)` method gains a new parameter 'genericReplacements:' that is defaulted to an empty array.
41+
- The method's signature is now `expand(argumentList:definition:replacements:genericReplacements:)`
42+
- Pull Request: https://github.com/apple/swift-syntax/pull/2450
3843

3944
## API Behavior Changes
4045

Sources/SwiftSyntaxMacroExpansion/MacroReplacement.swift

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -299,17 +299,21 @@ extension MacroDeclSyntax {
299299
/// uses of macro parameters with their corresponding arguments.
300300
private final class MacroExpansionRewriter: SyntaxRewriter {
301301
let parameterReplacements: [DeclReferenceExprSyntax: Int]
302-
let genericParameterReplacements: [DeclReferenceExprSyntax: Int]
303302
let arguments: [ExprSyntax]
303+
// let genericParameterReplacements: [DeclReferenceExprSyntax: Int]
304+
let genericParameterReplacements: [GenericArgumentSyntax: Int]
305+
let genericArguments: [TypeSyntax]
304306

305307
init(
306308
parameterReplacements: [DeclReferenceExprSyntax: Int],
307-
genericReplacements: [DeclReferenceExprSyntax: Int],
308-
arguments: [ExprSyntax]
309+
arguments: [ExprSyntax],
310+
genericReplacements: [GenericArgumentSyntax: Int],
311+
genericArguments: [TypeSyntax]
309312
) {
310313
self.parameterReplacements = parameterReplacements
311-
self.genericParameterReplacements = genericReplacements
312314
self.arguments = arguments
315+
self.genericParameterReplacements = genericReplacements
316+
self.genericArguments = genericArguments
313317
super.init(viewMode: .sourceAccurate)
314318
}
315319

@@ -321,37 +325,68 @@ private final class MacroExpansionRewriter: SyntaxRewriter {
321325
// Swap in the argument for this parameter
322326
return arguments[parameterIndex].trimmed
323327
}
328+
329+
override func visit(_ node: GenericArgumentSyntax) -> GenericArgumentSyntax {
330+
guard let parameterIndex = genericParameterReplacements[node] else {
331+
return super.visit(node)
332+
}
333+
334+
// Swap in the argument for type parameter
335+
return GenericArgumentSyntax(
336+
leadingTrivia: node.leadingTrivia,
337+
node.unexpectedBeforeArgument,
338+
argument: genericArguments[parameterIndex].trimmed,
339+
node.unexpectedBetweenArgumentAndTrailingComma,
340+
trailingComma: node.trailingComma,
341+
node.unexpectedAfterTrailingComma
342+
// TODO: seems we're getting spurious trailing " " here,
343+
// skipping trailing trivia for now
344+
// trailingTrivia: node.trailingTrivia
345+
)
346+
}
324347
}
325348

326349
extension MacroDeclSyntax {
327350
/// Expand the definition of this macro when provided with the given
328351
/// argument list.
329352
private func expand(
330353
argumentList: LabeledExprListSyntax?,
354+
genericArgumentList: GenericArgumentClauseSyntax?,
331355
definition: MacroExpansionExprSyntax,
332356
replacements: [MacroDefinition.Replacement],
333-
genericReplacements: [MacroDefinition.GenericArgumentReplacement]
357+
genericReplacements: [MacroDefinition.GenericArgumentReplacement] = []
334358
) -> ExprSyntax {
335359
// FIXME: Do real call-argument matching between the argument list and the
336360
// macro parameter list, porting over from the compiler.
361+
let parameterReplacements = Dictionary(
362+
uniqueKeysWithValues: replacements.map { replacement in
363+
(replacement.reference, replacement.parameterIndex)
364+
}
365+
)
337366
let arguments: [ExprSyntax] =
338367
argumentList?.map { element in
339368
element.expression
340369
} ?? []
341370

342-
return MacroExpansionRewriter(
343-
parameterReplacements: Dictionary(
344-
uniqueKeysWithValues: replacements.map { replacement in
345-
(replacement.reference, replacement.parameterIndex)
346-
}
347-
),
348-
genericReplacements: Dictionary(
349-
uniqueKeysWithValues: replacements.map { replacement in
350-
(replacement.reference, replacement.parameterIndex)
351-
}
352-
),
353-
arguments: arguments
354-
).visit(definition)
371+
372+
let genericReplacements = Dictionary(
373+
uniqueKeysWithValues: genericReplacements.map { replacement in
374+
(replacement.reference, replacement.parameterIndex)
375+
}
376+
)
377+
let genericArguments: [TypeSyntax] =
378+
genericArgumentList?.arguments.map { element in
379+
element.argument
380+
} ?? []
381+
382+
383+
let rewriter: MacroExpansionRewriter = MacroExpansionRewriter(
384+
parameterReplacements: parameterReplacements,
385+
arguments: arguments,
386+
genericReplacements: genericReplacements,
387+
genericArguments: genericArguments
388+
)
389+
return rewriter.visit(definition)
355390
}
356391

357392
/// Given a freestanding macro expansion syntax node that references this
@@ -365,6 +400,7 @@ extension MacroDeclSyntax {
365400
) -> ExprSyntax {
366401
return expand(
367402
argumentList: node.arguments,
403+
genericArgumentList: node.genericArgumentClause,
368404
definition: definition,
369405
replacements: replacements,
370406
genericReplacements: genericReplacements
@@ -390,6 +426,7 @@ extension MacroDeclSyntax {
390426

391427
return expand(
392428
argumentList: argumentList,
429+
genericArgumentList: .init(arguments: []),
393430
definition: definition,
394431
replacements: replacements,
395432
genericReplacements: genericReplacements

Tests/SwiftSyntaxMacroExpansionTest/MacroReplacementTests.swift

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ final class MacroReplacementTests: XCTestCase {
115115
)
116116
}
117117

118-
func testMacroGenericArgumentExpansion() throws {
118+
func testMacroGenericArgumentExpansion_base() throws {
119119
let macro: DeclSyntax =
120120
"""
121121
macro gen<A, B>(a: A, b: B) = #otherMacro<A, B>(first: a, second: b)
@@ -132,15 +132,10 @@ final class MacroReplacementTests: XCTestCase {
132132
XCTFail("not a normal expansion")
133133
return
134134
}
135-
135+
136136
let replacementA = try XCTUnwrap(genericReplacements.first)
137-
XCTFail("Expected generic replacement for A")
138-
return
139-
}
140-
guard let replacementB = genericReplacements.dropFirst().first else {
141-
XCTFail("Expected generic replacement for B")
142-
return
143-
}
137+
let replacementB = try XCTUnwrap(genericReplacements.dropFirst().first)
138+
144139
XCTAssertEqual(genericReplacements.count, 2)
145140

146141
XCTAssertEqual(replacementA.parameterIndex, 0)
@@ -158,7 +153,7 @@ final class MacroReplacementTests: XCTestCase {
158153
assertStringsEqualWithDiff(
159154
expandedSyntax.description,
160155
"""
161-
#otherMacro<A, B>(first: 5, second: "Hello")
156+
#otherMacro<Int, String>(first: 5, second: "Hello")
162157
"""
163158
)
164159
}
@@ -181,14 +176,8 @@ final class MacroReplacementTests: XCTestCase {
181176
return
182177
}
183178

184-
guard let replacementA = genericReplacements.first else {
185-
XCTFail("Expected generic replacement for A")
186-
return
187-
}
188-
guard let replacementB = genericReplacements.dropFirst().first else {
189-
XCTFail("Expected generic replacement for B")
190-
return
191-
}
179+
let replacementA = try XCTUnwrap(genericReplacements.first)
180+
let replacementB = try XCTUnwrap(genericReplacements.dropFirst().first)
192181
XCTAssertEqual(genericReplacements.count, 2)
193182

194183
XCTAssertEqual(replacementA.parameterIndex, 0)
@@ -206,7 +195,7 @@ final class MacroReplacementTests: XCTestCase {
206195
assertStringsEqualWithDiff(
207196
expandedSyntax.description,
208197
"""
209-
#otherMacro<A, B>(first: 5, second: "Hello")
198+
#otherMacro<Int, String>(first: 5, second: "Hello")
210199
"""
211200
)
212201
}
@@ -244,4 +233,38 @@ final class MacroReplacementTests: XCTestCase {
244233
"""
245234
)
246235
}
236+
237+
func testMacroGenericArgumentExpansion_replaceInner() throws {
238+
let macro: DeclSyntax =
239+
"""
240+
macro gen<A>(a: Array<A>) = #otherMacro(first: a)
241+
"""
242+
243+
let use: ExprSyntax =
244+
"""
245+
#gen(a: [1, 2, 3])
246+
"""
247+
248+
let macroDecl = macro.as(MacroDeclSyntax.self)!
249+
let definition = try macroDecl.checkDefinition()
250+
guard case let .expansion(expansion, replacements, genericReplacements) = definition else {
251+
XCTFail("not a normal expansion")
252+
return
253+
}
254+
255+
XCTAssertEqual(genericReplacements.count, 0)
256+
257+
let expandedSyntax = macroDecl.expand(
258+
use.as(MacroExpansionExprSyntax.self)!,
259+
definition: expansion,
260+
replacements: replacements,
261+
genericReplacements: genericReplacements
262+
)
263+
assertStringsEqualWithDiff(
264+
expandedSyntax.description,
265+
"""
266+
#otherMacro(first: [1, 2, 3])
267+
"""
268+
)
269+
}
247270
}

0 commit comments

Comments
 (0)
0