@@ -307,7 +307,7 @@ private func expandAccessorMacroWithExistingAccessors(
307307 return nil
308308 }
309309
310- // Separate the accessor from any existing accessors by two spaces
310+ // Separate the accessor from any existing accessors by an empty line
311311 let indentedSource = " \n " + expanded. indented ( by: attachedTo. indentationOfFirstLine + indentationWidth)
312312 return " \( raw: indentedSource) "
313313}
@@ -636,13 +636,26 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
636636 context. addDiagnostics ( from: MacroApplicationError . accessorMacroOnVariableWithMultipleBindings, node: node)
637637 return DeclSyntax ( node)
638638 }
639- node. bindings [ node. bindings. startIndex] . accessorBlock = expandAccessors ( of: node, existingAccessors: binding. accessorBlock)
639+
640+ let expansion = expandAccessors ( of: node, existingAccessors: binding. accessorBlock)
641+ if expansion. accessors != binding. accessorBlock {
642+ if binding. initializer != nil , expansion. expandsGetSet {
643+ // The accessor block will have a leading space, but there will already be a
644+ // space between the variable and the to-be-removed initializer. Remove the
645+ // leading trivia on the accessor block so we don't double up.
646+ node. bindings [ node. bindings. startIndex] . accessorBlock = expansion. accessors? . with ( \. leadingTrivia, [ ] )
647+ node. bindings [ node. bindings. startIndex] . initializer = nil
648+ } else {
649+ node. bindings [ node. bindings. startIndex] . accessorBlock = expansion. accessors
650+ }
651+ }
652+
640653 return DeclSyntax ( node)
641654 }
642655
643656 override func visit( _ node: SubscriptDeclSyntax ) -> DeclSyntax {
644657 var node = super. visit ( node) . cast ( SubscriptDeclSyntax . self)
645- node. accessorBlock = expandAccessors ( of: node, existingAccessors: node. accessorBlock)
658+ node. accessorBlock = expandAccessors ( of: node, existingAccessors: node. accessorBlock) . accessors
646659 return DeclSyntax ( node)
647660 }
648661}
@@ -803,14 +816,23 @@ extension MacroApplication {
803816 }
804817 }
805818
806- /// Expand all 'accessor' macros attached to `storage` and return the `storage`
807- /// node.
819+ /// Expand all 'accessor' macros attached to `storage`.
808820 ///
809- /// - Returns: The storage node with all macro-synthesized accessors applied.
810- private func expandAccessors( of storage: some DeclSyntaxProtocol , existingAccessors: AccessorBlockSyntax ? ) -> AccessorBlockSyntax ? {
821+ /// - Returns: The final accessors block that includes both the existing
822+ /// and expanded accessors, as well as whether any `get`/`set` were
823+ /// expanded (in which case any initializer on `storage` should be
824+ /// removed).
825+ private func expandAccessors( of storage: some DeclSyntaxProtocol , existingAccessors: AccessorBlockSyntax ? ) -> (
826+ accessors: AccessorBlockSyntax ? , expandsGetSet: Bool
827+ ) {
811828 let accessorMacros = macroAttributes ( attachedTo: DeclSyntax ( storage) , ofType: AccessorMacro . Type. self)
812829
813830 var newAccessorsBlock = existingAccessors
831+ var expandsGetSet = false
832+ func checkExpansions( _ accessors: AccessorDeclListSyntax ? ) {
833+ guard let accessors else { return }
834+ expandsGetSet = expandsGetSet || accessors. contains ( where: \. isGetOrSet)
835+ }
814836
815837 for macro in accessorMacros {
816838 do {
@@ -828,6 +850,8 @@ extension MacroApplication {
828850 in: context,
829851 indentationWidth: indentationWidth
830852 ) {
853+ checkExpansions ( newAccessors)
854+
831855 // If existingAccessors is not `nil`, then we also set
832856 // `newAccessorBlock` above to a a non-nil value, so
833857 // `newAccessorsBlock` also isn’t `nil`.
@@ -836,31 +860,33 @@ extension MacroApplication {
836860 indentationWidth: self . indentationWidth
837861 )
838862 }
839- } else {
840- let newAccessors = try expandAccessorMacroWithoutExistingAccessors (
841- definition : macro. definition ,
842- attributeNode : macro . attributeNode ,
843- attachedTo : DeclSyntax ( storage ) ,
844- in : context ,
845- indentationWidth : indentationWidth
846- )
847- if newAccessorsBlock == nil {
848- newAccessorsBlock = newAccessors
849- } else if let newAccessors = newAccessors {
850- guard case . accessors ( let accessorList) = newAccessors . accessors else {
851- throw MacroApplicationError . malformedAccessor
852- }
853- newAccessorsBlock = newAccessorsBlock! . addingAccessors (
863+ } else if let newAccessors = try expandAccessorMacroWithoutExistingAccessors (
864+ definition : macro . definition ,
865+ attributeNode : macro. attributeNode ,
866+ attachedTo : DeclSyntax ( storage ) ,
867+ in : context ,
868+ indentationWidth : indentationWidth
869+ ) {
870+ guard case . accessors ( let accessorList ) = newAccessors . accessors else {
871+ throw MacroApplicationError . malformedAccessor
872+ }
873+
874+ checkExpansions ( accessorList)
875+
876+ if let oldBlock = newAccessorsBlock {
877+ newAccessorsBlock = oldBlock . addingAccessors (
854878 from: accessorList,
855879 indentationWidth: self . indentationWidth
856880 )
881+ } else {
882+ newAccessorsBlock = newAccessors
857883 }
858884 }
859885 } catch {
860886 context. addDiagnostics ( from: error, node: macro. attributeNode)
861887 }
862888 }
863- return newAccessorsBlock
889+ return ( newAccessorsBlock, expandsGetSet )
864890 }
865891}
866892
@@ -1064,3 +1090,9 @@ private extension AttributeSyntax {
10641090 return ( detach ( in: context, foldingWith: operatorTable) as Syntax ) . cast ( Self . self)
10651091 }
10661092}
1093+
1094+ private extension AccessorDeclSyntax {
1095+ var isGetOrSet : Bool {
1096+ return accessorSpecifier. tokenKind == . keyword( . get) || accessorSpecifier. tokenKind == . keyword( . set)
1097+ }
1098+ }
0 commit comments