Extension method added by ExtensionMacro not visible to compiler?

Hello! I've been continuing to work on my ExtensionMacro use case and have run into an issue where the generated code from the macro looks correct, but the compiler acts like it isn't there. Here's a simple example:

// Inside my MacroCompilerPlugin Module

public struct FooExtensionMacro: 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] {
        let decl: DeclSyntax =
        """
        extension Foo {
          var foo: String { "foo" }
          func printFoo() {
            print(foo)
          }
        }
        """
        guard let extensionDecl = decl.as(ExtensionDeclSyntax.self) else {
          return []
        }

        return [extensionDecl]
    }
}

// Inside my MacroLibrary module

@attached(extension, names: named(foo), named(printFoo))
public macro FooExtension() = #externalMacro(module: "MacroCompilerPlugin", type: "FooExtensionMacro")


// Inside the client project / final target

import MacroLibrary

@FooExtension    // <--- apply the macro to generate default property and method
protocol Foo {
  var foo: String { get }
}

/// The above correctly expands to:
/// 
/// protocol Foo {
///   var foo: String { get }
/// }
///
/// extension Foo {
///   var foo: String { "foo" }
///   func printFoo() {
///     print(foo)
///   }
/// }

extension String: Foo { }   // <--- This compiles! Hooray, that means the default implementation of the property foo from the extension macro worked!

"Test".printFoo()   // <--- This doesn't compile ("Value of type ''String" has no member 'printFoo'"). This seems to indicate that the compiler can't "see" the printFoo() extension method from the ExtensionMacro, even though it can see the default implementation of the protocol's foo property from the same macro.

Is there some other step I need to implement in order to cue the compiler to be aware of a new extension method from my ExtensionMacro? Or are extension methods added but not part of the protocol definition itself not yet supported by ExtensionMacros attached to protocols?

That does indeed sound like a bug to me. Could you file an issue at Sign in to GitHub Β· GitHub?

Sure β€” opened this issue

Hi @ahoppen β€” just a quick note: I updated the issue above with a new note after it was closed. Looks like there is a wrinkle that isn't caught by the test cases and may still be a bug. The issue is that visibility of ExtensionMacro extension methods seems to work when the methods are called in the same file that the macro is applied in. But code in other files still can't see them. It's sort of as if every ExtensionMacro extension method gets fileprivate access control regardless of what the access level is specified to be.

I added a comment and a very minimal example package to the issue on Github that demonstrates the problem precisely. Is this something that should piggyback on the existing issue above, or should I create a new issue for it?

I pinged @Douglas_Gregor about it. He’s taking a look.

1 Like

Thank you once again, Alex! :raised_hands:

Hi @ahoppen and @Douglas_Gregor, I think this issue may have fallen between chairs (or I may be misunderstanding expected behavior). I opened a new issue with an attached screenshot and minimal reproducible example here:

1 Like

Thanks for the ping, it looks like we did indeed lost track of it. @Douglas_Gregor Can you take a look at the issue?

1 Like