swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.55k stars 10.35k forks source link

Unable to access self from property didSet with accessor macro #66737

Open Jumhyn opened 1 year ago

Jumhyn commented 1 year ago

Description

public struct MakeComputedMacro {}

extension MakeComputedMacro: AccessorMacro {
  public static func expansion<Context, Declaration>(
    of node: AttributeSyntax,
    providingAccessorsOf declaration: Declaration,
    in context: Context
  ) throws -> [AccessorDeclSyntax] where Context : MacroExpansionContext, Declaration : DeclSyntaxProtocol {
    guard let varDecl = declaration.as(VariableDeclSyntax.self),
      let binding = varDecl.bindings.first,
      let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier
    else {
      return []
    }

    return [
      """

        get {
          _\(raw: identifier.text)
        }
      """,
      """

        set {
            _\(raw: identifier.text) = newValue
        }
      """,
    ]
  }
}

extension MakeComputedMacro: PeerMacro {
  public static func expansion<
    Context: MacroExpansionContext,
    Declaration: DeclSyntaxProtocol
  >(
    of node: SwiftSyntax.AttributeSyntax,
    providingPeersOf declaration: Declaration,
    in context: Context
  ) throws -> [DeclSyntax] {
    guard
      let property = declaration.as(VariableDeclSyntax.self),
      let binding = property.bindings.first,
      let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier,
      let type = binding.typeAnnotation?.type
    else {
      return []
    }

    let storage: DeclSyntax = "var _\(raw: identifier.text): \(type)"
    return [storage]
  }
}
@attached(peer, names: prefixed(_))
@attached(accessor)
public macro MakeComputed() = #externalMacro(module: "MacroExamplesPlugin", type: "MakeComputedMacro")
class Model {
  @MakeComputed
  var x: Int = 0 {
    didSet {
     print(_x) // Instance member '_x' cannot be used on type 'Model'; did you mean to use a value of this type instead?
    }
  }

  init(x: Int) {
    self._x = x
  }
}

Expected behavior The above code compiles and prints the value of x when the property observer is triggered.

Environment Xcode 15b1

swift-macro-examples.zip

Jumhyn commented 1 year ago

potentially related: #66630