Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SyntaxProtocol.expand() does not expand peer macros introduced by other macros #1805

Open
tgoyne opened this issue Jun 16, 2023 · 3 comments
Labels
bug Something isn't working Macros Issues in the SwiftSyntaxMacro… modules

Comments

@tgoyne
Copy link

tgoyne commented Jun 16, 2023

Description

This test fails due to Foo not having the second bar field (while Bar passes). This works correctly when expanded by the compiler plugin (although in this example it obviously result in a compilation error due to the property being redeclared).

public struct DuplicateAll: MemberAttributeMacro {
    public static func expansion(
        of node: AttributeSyntax,
        attachedTo declaration: some DeclGroupSyntax,
        providingAttributesFor member: some DeclSyntaxProtocol,
        in context: some MacroExpansionContext
    ) throws -> [AttributeSyntax] {
        return [AttributeSyntax(attributeName: SimpleTypeIdentifierSyntax(name: .identifier("Duplicate")))]
    }
}

public struct Duplicate: PeerMacro {
    public static func expansion(of node: AttributeSyntax, providingPeersOf declaration: some DeclSyntaxProtocol, in context: some MacroExpansionContext) throws -> [DeclSyntax] {
        if var decl = declaration.as(VariableDeclSyntax.self) {
            decl.attributes = nil
            return [DeclSyntax(decl)]
        }
        return []
    }
}

final class reproTests: XCTestCase {
    func testMacro() {
        assertMacroExpansion(
            """
            @DuplicateAll
            class Foo {
                var bar: Int = 0
            }
            class Bar {
                @Duplicate
                var bar: Int = 0
            }
            """,
            expandedSource: """

            class Foo {
                var bar: Int = 0
                var bar: Int = 0
            }
            class Bar {
                var bar: Int = 0
                var bar: Int = 0
            }
            """,
            macros:  [
                "DuplicateAll": DuplicateAll.self,
                "Duplicate": Duplicate.self,
            ]
        )
    }
}

Steps to Reproduce

No response

@tgoyne tgoyne added the bug Something isn't working label Jun 16, 2023
@ahoppen
Copy link
Member

ahoppen commented Jun 16, 2023

Tracked in Apple’s issue tracker as rdar://110923449

@DougGregor
Copy link
Member

SyntaxProtocol.expand is really a "full" macro expansion system, and only handles one level of expansion. We could perhaps make it a full expansion system at some point.

@ahoppen ahoppen added the Macros Issues in the SwiftSyntaxMacro… modules label Jul 7, 2023
@liamnichols
Copy link

liamnichols commented Jul 17, 2023

In 509.0.0-swift-5.9-DEVELOPMENT-SNAPSHOT-2023-04-25-b, i'm currently observing inconsistent behaviour.

When expanding a MemberMacro that produces code containing an ExpressionMacro, it seems to expand both levels. However doing the same with a DeclarationMacro that produces code containing an ExpressionMacro, it only expands the outer declaration macro.

This can be reproduced in the following example:

struct MyMemberMacro: MemberMacro {
    static func expansion<Declaration, Context>(
        of node: AttributeSyntax,
        providingMembersOf declaration: Declaration,
        in context: Context
    ) throws -> [DeclSyntax] where Declaration : DeclGroupSyntax, Context : MacroExpansionContext {
        [
            """
            func doSomething() {
                #myFreestandingMacro
            }
            """
        ]
    }
}

struct MyFreestandingMacro: ExpressionMacro {
    static func expansion<Node, Context>(
        of node: Node,
        in context: Context
    ) throws -> ExprSyntax where Node : FreestandingMacroExpansionSyntax, Context : MacroExpansionContext {
        #"print("Hello World")"#
    }
}

struct MyDeclarationMacro: DeclarationMacro {
    static func expansion<Node, Context>(
        of node: Node,
        in context: Context
    ) throws -> [DeclSyntax] where Node : FreestandingMacroExpansionSyntax, Context : MacroExpansionContext {
        [
            """
            func doSomething() {
                #myFreestandingMacro
            }
            """
        ]
    }
}

final class MacroTests: XCTestCase {
    func testExpansionOfFreestandingMacroInMemberMacro() {
        assertMacroExpansion(
            """
            @MyMemberMacro
            struct Foo {
            }
            """,
            expandedSource: """

            struct Foo {
                func doSomething() {
                    print("Hello World")
                }
            }
            """,
            macros: [
                "MyMemberMacro": MyMemberMacro.self,
                "myFreestandingMacro": MyFreestandingMacro.self
            ]
        )
    }

    func testExpansionOfFreestandingMacroInFreestandingMacro() {
        assertMacroExpansion(
            """
            struct Foo {
                #myDeclarationMacro
            }
            """,
            expandedSource: """

            struct Foo {
                func doSomething() {
                    print("Hello World")
                }
            }
            """,
            macros: [
                "myDeclarationMacro": MyDeclarationMacro.self,
                "myFreestandingMacro": MyFreestandingMacro.self
            ]
        )
    }
}

The second test fails with the following:

failed - Actual output (+) differed from expected output (-):
–
 struct Foo {
     func doSomething() {
–        print("Hello World")
+        #myFreestandingMacro
     }
 }

I'd expect the levels of expansion to be consistent either way so i'm wondering if this was intentional or worth addressing before the final 5.9 release?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Macros Issues in the SwiftSyntaxMacro… modules
Projects
None yet
Development

No branches or pull requests

4 participants