Skip to content

Accessor macro executing wrong code #71070

Closed as not planned
Closed as not planned
@stephencelis

Description

@stephencelis

Description

We've implemented a macro similar to @ObservationTracked that swaps out a stored property for accessors that call down to some private storage. Much to my surprise, though, that private storage is not being called.

See attached for repro: MyMacro.zip

Reproduction

Macro plugin:

import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct MyMacroMacro: AccessorMacro, PeerMacro {
  public static func expansion(
    of node: AttributeSyntax,
    providingAccessorsOf declaration: some DeclSyntaxProtocol,
    in context: some MacroExpansionContext
  ) throws -> [AccessorDeclSyntax] {
    guard
      let property = declaration.as(VariableDeclSyntax.self),
      let binding = property.bindings.first,
      let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier.trimmed
    else {
      return []
    }
    return [
      """
      @storageRestrictions(initializes: _\(raw: identifier))
      init(initialValue) {
      _\(identifier) = initialValue
      }
      """,
      """
      get {
      _\(identifier)
      }
      """,
      """
      set {
      _\(identifier) = newValue
      }
      """,
    ]
  }

  public static func expansion(
    of node: AttributeSyntax,
    providingPeersOf declaration: some DeclSyntaxProtocol,
    in context: some MacroExpansionContext
  ) throws -> [DeclSyntax] {
    guard
      let property = declaration.as(VariableDeclSyntax.self),
      let binding = property.bindings.first,
      let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier.trimmed
    else {
      return []
    }
    return [
      """
      private var _\(identifier): () -> Bool = { fatalError() }
      """
    ]
  }
}

@main
struct MyMacroPlugin: CompilerPlugin {
  let providingMacros: [Macro.Type] = [
    MyMacroMacro.self,
  ]
}

Library:

@attached(accessor, names: named(init), named(get), named(set))
@attached(peer, names: arbitrary)
public macro MyMacro() =
  #externalMacro(module: "MyMacroMacros", type: "MyMacroMacro")

Executable:

import MyMacro

struct Foo {
  @MyMacro
  var bar: () -> Bool = { false }
}

let foo = Foo()
print(foo.bar())

What the above should expand to:

image

Expected behavior

I expect foo.bar() to crash in the executable because @MyMacro has swapped var bar for a getter that invokes _bar, which is a member that defaults to calling fatalError().

Instead, I get false printed to the console, which shows that Swift is somehow invoking the original storage.

Environment

swift-driver version: 1.87.3 Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5)
Target: arm64-apple-macosx14.0

Additional information

No response

Metadata

Metadata

Assignees

Labels

bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.macro expansionsFeature → expressions: Macro expansion expressionsswift macroFeature → declarations: Swift `macro` declarations

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions