Skip to content

Commit 23be62c

Browse files
authored
Merge pull request #2135 from ahoppen/ahoppen/509/multiple-errors
[509] Fix issue that caused errors thrown from macro expansion to show up twice in MacroSystem
2 parents 0687ad0 + 55a0237 commit 23be62c

File tree

2 files changed

+164
-17
lines changed

2 files changed

+164
-17
lines changed

Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -485,10 +485,14 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
485485
// Note that 'MacroExpansionExpr'/'MacroExpansionExprDecl' at code item
486486
// position are handled by 'visit(_:CodeBlockItemListSyntax)'.
487487
// Only expression expansions inside other syntax nodes is handled here.
488-
if let expanded = expandExpr(node: node) {
488+
switch expandExpr(node: node) {
489+
case .success(let expanded):
489490
return Syntax(visit(expanded))
491+
case .failure:
492+
return Syntax(node)
493+
case .notAMacro:
494+
break
490495
}
491-
492496
if let declSyntax = node.as(DeclSyntax.self),
493497
let attributedNode = node.asProtocol(WithAttributesSyntax.self),
494498
!attributedNode.attributes.isEmpty
@@ -510,16 +514,21 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
510514
var newItems: [CodeBlockItemSyntax] = []
511515
func addResult(_ node: CodeBlockItemSyntax) {
512516
// Expand freestanding macro.
513-
if let expanded = expandCodeBlockItem(node: node) {
517+
switch expandCodeBlockItem(node: node) {
518+
case .success(let expanded):
514519
for item in expanded {
515520
addResult(item)
516521
}
517522
return
523+
case .failure:
524+
// Expanding the macro threw an error. We don't have an expanded source.
525+
// Retain the macro node as-is.
526+
newItems.append(node)
527+
case .notAMacro:
528+
// Recurse on the child node
529+
newItems.append(visit(node))
518530
}
519531

520-
// Recurse on the child node
521-
newItems.append(visit(node))
522-
523532
// Expand any peer macro on this item.
524533
if case .decl(let decl) = node.item {
525534
for peer in expandCodeBlockPeers(of: decl) {
@@ -552,16 +561,19 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
552561

553562
func addResult(_ node: MemberBlockItemSyntax) {
554563
// Expand freestanding macro.
555-
if let expanded = expandMemberDecl(node: node) {
564+
switch expandMemberDecl(node: node) {
565+
case .success(let expanded):
556566
for item in expanded {
557567
addResult(item)
558568
}
559569
return
570+
case .failure:
571+
newItems.append(node)
572+
case .notAMacro:
573+
// Recurse on the child node.
574+
newItems.append(visit(node))
560575
}
561576

562-
// Recurse on the child node.
563-
newItems.append(visit(node))
564-
565577
// Expand any peer macro on this member.
566578
for peer in expandMemberDeclPeers(of: node.decl) {
567579
addResult(peer)
@@ -842,20 +854,36 @@ extension MacroApplication {
842854
// MARK: Freestanding macro expansion
843855

844856
extension MacroApplication {
857+
enum MacroExpansionResult<ResultType> {
858+
/// Expansion of the macro succeeded.
859+
case success(ResultType)
860+
861+
/// Macro system found the macro to expand but running the expansion threw
862+
/// an error and thus no expansion result exists.
863+
case failure
864+
865+
/// The node that should be expanded was not a macro known to the macro system.
866+
case notAMacro
867+
}
868+
845869
private func expandFreestandingMacro<ExpandedMacroType: SyntaxProtocol>(
846870
_ node: (any FreestandingMacroExpansionSyntax)?,
847871
expandMacro: (_ macro: Macro.Type, _ node: any FreestandingMacroExpansionSyntax) throws -> ExpandedMacroType?
848-
) -> ExpandedMacroType? {
872+
) -> MacroExpansionResult<ExpandedMacroType> {
849873
guard let node,
850874
let macro = macroSystem.lookup(node.macro.text)
851875
else {
852-
return nil
876+
return .notAMacro
853877
}
854878
do {
855-
return try expandMacro(macro, node)
879+
if let expanded = try expandMacro(macro, node) {
880+
return .success(expanded)
881+
} else {
882+
return .failure
883+
}
856884
} catch {
857885
context.addDiagnostics(from: error, node: node)
858-
return nil
886+
return .failure
859887
}
860888
}
861889

@@ -867,7 +895,7 @@ extension MacroApplication {
867895
/// #foo
868896
/// }
869897
/// ```
870-
func expandCodeBlockItem(node: CodeBlockItemSyntax) -> CodeBlockItemListSyntax? {
898+
func expandCodeBlockItem(node: CodeBlockItemSyntax) -> MacroExpansionResult<CodeBlockItemListSyntax> {
871899
return expandFreestandingMacro(node.item.asProtocol(FreestandingMacroExpansionSyntax.self)) { macro, node in
872900
return try expandFreestandingCodeItemList(
873901
definition: macro,
@@ -886,7 +914,7 @@ extension MacroApplication {
886914
/// #foo
887915
/// }
888916
/// ```
889-
func expandMemberDecl(node: MemberBlockItemSyntax) -> MemberBlockItemListSyntax? {
917+
func expandMemberDecl(node: MemberBlockItemSyntax) -> MacroExpansionResult<MemberBlockItemListSyntax> {
890918
return expandFreestandingMacro(node.decl.as(MacroExpansionDeclSyntax.self)) { macro, node in
891919
return try expandFreestandingMemberDeclList(
892920
definition: macro,
@@ -904,7 +932,7 @@ extension MacroApplication {
904932
/// ```swift
905933
/// let a = #foo
906934
/// ```
907-
func expandExpr(node: Syntax) -> ExprSyntax? {
935+
func expandExpr(node: Syntax) -> MacroExpansionResult<ExprSyntax> {
908936
return expandFreestandingMacro(node.as(MacroExpansionExprSyntax.self)) { macro, node in
909937
return try expandFreestandingExpr(
910938
definition: macro,

Tests/SwiftSyntaxMacroExpansionTest/MacroSystemTests.swift

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,4 +1775,123 @@ final class MacroSystemTests: XCTestCase {
17751775
)
17761776
}
17771777

1778+
func testThrowErrorFromExpressionMacro() {
1779+
struct MyError: Error, CustomStringConvertible {
1780+
let description: String = "my error"
1781+
}
1782+
1783+
struct TestMacro: ExpressionMacro {
1784+
public static func expansion(
1785+
of node: some FreestandingMacroExpansionSyntax,
1786+
in context: some MacroExpansionContext
1787+
) throws -> ExprSyntax {
1788+
throw MyError()
1789+
}
1790+
}
1791+
1792+
assertMacroExpansion(
1793+
"#test",
1794+
expandedSource: "#test",
1795+
diagnostics: [
1796+
DiagnosticSpec(message: "my error", line: 1, column: 1)
1797+
],
1798+
macros: ["test": TestMacro.self]
1799+
)
1800+
1801+
assertMacroExpansion(
1802+
"1 + #test",
1803+
expandedSource: "1 + #test",
1804+
diagnostics: [
1805+
DiagnosticSpec(message: "my error", line: 1, column: 5)
1806+
],
1807+
macros: ["test": TestMacro.self]
1808+
)
1809+
}
1810+
1811+
func testThrowErrorFromDeclMacro() {
1812+
struct MyError: Error, CustomStringConvertible {
1813+
let description: String = "my error"
1814+
}
1815+
1816+
struct TestMacro: DeclarationMacro {
1817+
static func expansion(
1818+
of node: some FreestandingMacroExpansionSyntax,
1819+
in context: some MacroExpansionContext
1820+
) throws -> [DeclSyntax] {
1821+
throw MyError()
1822+
}
1823+
}
1824+
1825+
assertMacroExpansion(
1826+
"#test",
1827+
expandedSource: "#test",
1828+
diagnostics: [
1829+
DiagnosticSpec(message: "my error", line: 1, column: 1)
1830+
],
1831+
macros: ["test": TestMacro.self]
1832+
)
1833+
1834+
assertMacroExpansion(
1835+
"""
1836+
struct Foo {
1837+
#test
1838+
}
1839+
""",
1840+
expandedSource: """
1841+
struct Foo {
1842+
#test
1843+
}
1844+
""",
1845+
diagnostics: [
1846+
DiagnosticSpec(message: "my error", line: 2, column: 3)
1847+
],
1848+
macros: ["test": TestMacro.self]
1849+
)
1850+
}
1851+
1852+
func testAttachedMacroOnFreestandingMacro() {
1853+
struct DeclMacro: DeclarationMacro {
1854+
static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> [DeclSyntax] {
1855+
return ["var x: Int"]
1856+
}
1857+
}
1858+
1859+
struct MyPeerMacro: PeerMacro {
1860+
static func expansion(of node: AttributeSyntax, providingPeersOf declaration: some DeclSyntaxProtocol, in context: some MacroExpansionContext) throws
1861+
-> [DeclSyntax]
1862+
{
1863+
return ["var peer: Int"]
1864+
}
1865+
}
1866+
1867+
assertMacroExpansion(
1868+
"""
1869+
struct Foo {
1870+
@Peer
1871+
#decl
1872+
}
1873+
""",
1874+
expandedSource: """
1875+
struct Foo {
1876+
var x: Int
1877+
1878+
var peer: Int
1879+
}
1880+
""",
1881+
macros: ["decl": DeclMacro.self, "Peer": MyPeerMacro.self]
1882+
)
1883+
1884+
assertMacroExpansion(
1885+
"""
1886+
@Peer
1887+
#decl
1888+
""",
1889+
expandedSource: """
1890+
var x: Int
1891+
1892+
var peer: Int
1893+
""",
1894+
macros: ["decl": DeclMacro.self, "Peer": MyPeerMacro.self]
1895+
)
1896+
}
17781897
}

0 commit comments

Comments
 (0)