swift-macro-toolkit icon indicating copy to clipboard operation
swift-macro-toolkit copied to clipboard

Implement helper macro to reduce boilerplate in `Type` implementation

Open stackotter opened this issue 2 years ago • 4 comments

The Type enum has two computed properties specifically for extracting certain cases: asSimpleType and asFunctionType. To implement such properties for all cases would require a lot of boilerplate code, and considering that similar properties will eventually need to be implemented for many other enums in the code base, I think it would be best to create a MacroToolkitHelperMacros target with a macro designed to automatically generate these computed properties for enums. Somewhat ironically, the macro won't be able to use the toolkit because it'll be used to implement the toolkit 😅

The macro should be an attached member macro which works something like this; (just throw an error if any of the enum cases don't have exactly one associated value)

input.swift

@CaseAccessors // Feel free to come up with a better name
enum Type {
    case simpleType(SimpleType)
    case functionType(FunctionType)
    // ...
}

expanded.swift

enum Type {
    case simpleType(SimpleType)
    case functionType(FunctionType)
    // ...
    
    var asSimpleType: SimpleType? {
        switch self {
            case let .simpleType(value): value
            default: nil
        }
    }
    
    var asFunctionType: FunctionType? {
        switch self {
            case let .functionType(value): value
            default: nil
        }
    }
    
    // ...
}

The macro must be implemented in a separate target from the Toolkit (hence the MacroToolkitHelpers target suggestion), however the macro can be declared in the MacroToolkit target (declaration is separate from implementation):

// This declaration is taken from the proposal, so the API may have changed since
// then, I haven't kept up with all that
@attached(member, names: arbitrary) macro CaseAccessors()

After implementing the macro you can apply it to Type, AttributeListElement, DestructuredType, and EnumCaseValue (I can't see any others that would make sense to use it on).

This could be quite involved, so feel free (as always) to contact me on Discord (@stackotter), Twitter (X) (@stackotter), or via email ([email protected])

stackotter avatar Oct 10 '23 11:10 stackotter

Pointfree's case paths macro essentially does this amongst other things 😉

ajkolean avatar May 16 '24 00:05 ajkolean

Pointfree's case paths macro essentially does this amongst other things 😉

Woah, thanks for bringing that to my attention! I hadn't checked out case paths since macros, didn't realise that they had that handy macro now.

Due to MacroToolkit being a foundational library for making macros, it'd be best not to get to tied to whatever swift-syntax version pointfree's case paths macros are built on (and maybe case paths will want to use macro toolkit one day hahah). I reckon it'd be best for the toolkit to reimplement a similar macro to use internally so that we don't have to depend on case paths.

stackotter avatar May 17 '24 04:05 stackotter

Ahh yeah totally derped on that, especially with the volatility syntax has been exhibiting. Anyway the source might be beneficial when implementing this. Also the CaseDetection macro example in the swift-syntax library and this one (Although doesn't seem maintained so syntax will be a little outdated)

ajkolean avatar May 17 '24 14:05 ajkolean

Yeah definitely 👍

stackotter avatar May 20 '24 02:05 stackotter