8000 Macro shadows methods and properties defined in protocol extension a type inherits · Issue #70181 · swiftlang/swift · GitHub
[go: up one dir, main page]

Skip to content
Macro shadows methods and properties defined in protocol extension a type inherits #70181
@rayx

Description

@rayx

Description

I have a macro Foo which may add CustomStringConvertible conformance or does nothing, depending on a flag argument it takes. Below is a scenario why I'd like the macro to output nothing.

protocol BarProtocol: CustomStringConvertible {
    var value: String { get }
}

extension BarProtocol {
    var description: String {
        value
    }
}

@Foo(noOp: true)
struct Bar: BarProtocol {
    var value: String
}

In above case, since Bar conforms to CustomStringConvertible by inheriting BarProtocol and its extension, there is no need for the macro to generate any code. Unfortunately the above code doesn't compile. Error:

Type 'Bar' does not conform to protocol 'CustomStringConvertible'

It seems that the description computed variable defined in BarProtocol becomes invisible to compiler during conformance check.

(In case you're curious why I couldn't just remove the macro in above scenario, it's because the above code is a simplification. In my actual code the macro adds conformance to multiple protocols, so I can't remove it just because the type already conforms to one of the protocols through inheritance.)

Reproduction

Please note I simplied the macro code so that it always generate nothing.

Macro implementation:

public enum FooMacro: ExtensionMacro {
    public static func expansion(
        of node: AttributeSyntax,
        attachedTo declaration: some DeclGroupSyntax,
        providingExtensionsOf type: some TypeSyntaxProtocol,
        conformingTo protocols: [TypeSyntax],
        in context: some MacroExpansionContext
    ) throws -> [ExtensionDeclSyntax] {
        return []
    }
}

Macro interface:

@attached(extension, conformances: CustomStringConvertible, names: named(description))
public macro Foo() = #externalMacro(module: "impl", type: "FooMacro")

Test:

protocol BarProtocol: CustomStringConvertible {
    var value: String
}

extension BarProtocol {
    var description: String {
        value
    }
}

@Foo
struct Bar: BarProtocol {
    var value: String
}

The test caused compile error:

Type 'Bar' does not conform to protocol 'CustomStringConvertible'

Expected behavior

It should compile.

Environment

$ /Users/app/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -version
swift-driver version: 1.87.1 Apple Swift version 5.9 (swiftlang-5.9.0.128.108 clang-1500.0.40.1)
Target: x86_64-apple-macosx13.0

Xcode: 15.0, macOS: 13.6

Additional information

I think there are three ways to add protocol conformance to a type:

  1. Inheriting from another protocol (and its extension)
  2. Using macro
  3. Doing it manually

This bug makes it impossible to use method 1 and 2 together.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.triage neededThis issue needs more specific labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0