Skip to content

MacroApplication should not recursively perform expansions on modified nodes #3151

@bnbarham

Description

@bnbarham

Description

MacroApplication currently applies the member attribute macro, then expands peer macros on the resulting modified node (MacroApplication.visit(MemberBlockSyntax)). This can result in slightly different behavior to the expansion in the compiler, as the peer macro there will receive the original (unmodified) member. This usually doesn't matter too much in practice, but can if the macro isn't handling trivia correctly.

Consider a member attribute macro (@someMemberMacro) that adds an attribute for a peer macro, which then adds a peer to copy the original member with some small modifications (renaming the member and adding an extra attribute, without trivia handling).

@someMemberMacro
struct Foo {
  @someAttribute // some trailing comment
  let foo: Int
}

MacroApplication will first apply the member macro, resulting in:

struct Foo {
  @someAttribute
  @somePeerMacro // some trailing comment
  let foo: Int
}

Then the peer:

struct Foo {
  @someAttribute // some trailing comment
  let foo: Int

  @someAttribute
  @extraAttribute
  let _foo: Int
}

Note the move of the trailing comment to @somePeerMacro, which is then removed after the expansion of said peer macro.

This differs from the compiler itself, which will have @somePeerMacro in a separate buffer, then passing the original decl to the expansion. That would then result in (with this buggy macro implementation):

  @someAttribute // some trailing comment@extraAttribute let _foo: Int

So from the swift-syntax side, everything seems "fine", but that's not actually the case - this can lead to a fair amount of confusion for macro authors.

See also: swiftlang/swift#84145

Steps to Reproduce

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions