Skip to content

Adopting Hashable from Extension #15

@vanvoorden

Description

@vanvoorden

We currently support adding Equatable to types that adopt Hashable:

@Equatable
struct User: Hashable {
    let id: Int
    @EquatableIgnored var name = ""
}

Will then synthesize an == operator and a hash function.

Product engineers might choose to adopt Hashable on an extension:

@Equatable
struct User {
    let id: Int
    @EquatableIgnored var name = ""
}

extension User: Hashable {
  
}

Because the Hashable adoption is not part of the main declaration our Equatable macro does not "see" that we should synthesize a hash function. The swift compiler will synthesize its own. The swift compiler might synthesize a hash function that is inconsistent with the expectations of our == operator… which is the original bug we intended to fix.

One potential workaround is to synthesize a "bad" hash function if Equatable is attached to a type that does not adopt Hashable on its main declaration:

@Equatable
struct User {
    let id: Int
    @EquatableIgnored var name = ""
}

extension User {
    nonisolated public func hash(into hasher: inout Hasher) {
        fatalError()
    }
}

extension User: Hashable {
  
}

var set: Set = [
  User(id: 0)
]

At runtime we will crash when attempting to insert User in Set or Dictionary. Our runtime error message might instruct product engineers that Hashable must only be adopted on the main declaration.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions