A macro that makes all members of type public by default: possible?

For funsies, I wanted to try to write a macro @PublicByDefault that would change the default access level for a type's members from internal to public. Something like this:

// This code:
@PublicByDefault
public struct S {
    var a: Int
    private var b: Int
}

// Should expand into (note the added 'public' modifier for 'var a'):
public struct S {
    public var a: Int
    private var b: Int // macro preserves explicit annotation

    // Also generate a public memberwise init,
    // but that's not the problem I want to discuss.
}

So I would need a type of attached macro that would allow me to add access control modifiers to the members of the type the macro is attached to.

From the list of possible macro types in SE-0389: Attached macros, a member attribute macro almost fits the bill as it allows me to add one or more attributes to members. Unfortunately, access control specifiers aren't attributes (they don't start with '@'), so it doesn't work after all: I could use this to add @available to members, but not public.

Does anyone remember whether these fairly restrictive capabilities of member attribute macros (admittedly, they're aptly named) were discussed during the pitch or review for SE-0389? Was it considered to also allow adding non-attribute modifiers? I searched and couldn't find anything, but I didn't follow the discussions at the time.

Or is there another way to implement a @PublicByDefault macro?

2 Likes

Hmm… it's possible this is just pushing up against the limits of macros that do not have the ability to destructively edit existing code. Your macro expansion can suggest fix-its… which AFAIK can be destructive… but it's not "one step" to both expand the macro and destructively edit the code.

1 Like

It wouldn't be destructive though, would it? At least as long as the macro only added access modifiers and didn't remove or modify any explicit access modifiers in the code. (The compiler will emit an error if you place two conflicting access modifiers on a single declaration, such as public private var b: Int.)

I can see though that giving macros the ability to add non-attribute "modifiers" (what's the right term for these?) can have drastic effects, e.g. when adding static or final. Maybe that's a good enough reason to not allow this, I'm not sure. I'd love to know if it was considered and rejected or if it would be a potential future feature for macros.

SE-0389 mentions additional macro roles as a future direction:

There are numerous ways in which this proposal could be extended to provide new macro roles. Each new macro role would introduce a new role kind to the @attached attribute, along with a corresponding protocol. The macro vision document has a number of such suggestions.

But none of the roles listed in the Macros vision doc match this case.

1 Like