Open JosephDuffy opened 1 year ago
I believe this might be related to https://github.com/apple/swift/pull/66320. CC @DougGregor
Also tracked by: rdar://113994346
I've tested this using Xcode 15 beta 6 and beta 7 and have found it works for me, thank you for getting this fixed!
I'm not sure if there's some extra process here but I'm happy to close this issue if you are :)
Probably related. I tried both solutions but when I tried to add the == function for a child of NSObject
it did not work. It uses the default NSObject
implementation as I understand. It properly shows synthesized code when I expand the macro. The same lines entered manually work.
Breakpoint never fired also
// main.swift
@MyEquatable
class MyClass: NSObject {
let string: String = ""
}
let asd1 = MyClass()
let asd2 = MyClass()
print(asd1 == asd1) // true
print(asd1 == asd2) // false
// MyEquatableMacro.swift
public struct MyEquatable: MemberMacro {
public static func expansion(
of node: SwiftSyntax.AttributeSyntax,
providingMembersOf declaration: some SwiftSyntax.DeclGroupSyntax,
in context: some SwiftSyntaxMacros.MacroExpansionContext
) throws -> [SwiftSyntax.DeclSyntax] {
guard let classDeclSyntax = declaration.as(ClassDeclSyntax.self) else {
return []
}
let className = classDeclSyntax.name
let memberList = classDeclSyntax.memberBlock.members
let variableDecls = memberList.compactMap { $0.decl.as(VariableDeclSyntax.self) }
let identifierPatterns = variableDecls.compactMap { $0.bindings.first?.pattern.as(IdentifierPatternSyntax.self) }
let variableIdentifiers = identifierPatterns.map { $0.identifier }
let leadingTrivia = variableDecls.first?.leadingTrivia ?? Trivia(pieces: [])
let function = try FunctionDeclSyntax("static func ==(lhs: \(className), rhs: \(className)) -> Bool") {
for (index, variableIdentifier) in variableIdentifiers.enumerated() {
if index == 0 {
"lhs.\(variableIdentifier) == rhs.\(variableIdentifier)"
} else {
"\(leadingTrivia)&& lhs.\(variableIdentifier) == rhs.\(variableIdentifier)"
}
}
}
return [DeclSyntax(function)]
}
}
I made a workaround with the isEqual
override but the visibility of the ==
is still a bug
Testing this in the Xcode 15.0.1 release I see the issue again, but in Xcode 15.1 beta 2 it looks to be fixed again.
I can't see a way to prevent a package from being used in Xcode 15.0.1 but allow it in Xcode 15.1 though. Both swift-tools-version: 5.9.2
and swiftLanguageVersions: [.version("5.9.2")]
prevent the package being used in Xcode 15.1 beta 2.
Description
Writing a macro that outputs a
==
function is not considered when checking forEquatable
conformance.Steps to reproduce
Write a macro conforming to
ConformanceMacro
andMemberMacro
. AddHashable
conformance via theexpansion(of:providingConformancesOf:in:)
function and a validstatic func ==
implementation viaexpansion(of:providingMembersOf:in:)
.Expected behavior
The compiler should use the
==
function produced by the macro.Screenshots
Environment
Additional context
As shown in the screenshots the generated code looks right. Copy/pasting the generated code results in an "Invalid redeclaration of ==" error, then removing the
==
from the macro output allows the code to compile and the associated tests to pass, so I'm concluding (I hope correctly) that my implementation is correct!It's also possible to workaround this issue by conforming to a custom protocol that adds a
==
function via extension.I have an example of the workaround being used in a repo: https://github.com/JosephDuffy/CustomHashable. The remove-customHashable branch can be used to demonstrate the bug.
A topic I created on the Swift Forums a few weeks back for this: https://forums.swift.org/t/creating-a-macro-for-hashable-equatable-conformance/64711