Compiler picks the wrong overloaded function when using existentials

This might be a bug or a limitation, but when given the following two definitions:

func receive(action: any Action) { ... }
func receive<A>(action: A) where A: Action & Hashable { ... }

the compiler always picks the first, no matter if the concrete type conforms to Hashable or not.

enum AccountAction: Action, Hashable {
    case login
    case error
}

...
// Always picks the first implementation, although the second should be picked IMO
cluster.receive(action: AccountAction.login)

Shouldn't the more specialized one be picked?

1 Like

The compiler considers non-generic functions to always be more specific than generic ones, for better or worse. If you can make both functions generic, or both use existentials, then you should get the behavior you expect.

4 Likes

Thanks for the reply. I would have expected specialization to be generic-independent (i.e., no matter when the type is resolved, the definition will either have an existential Action or an Action & Hashable), but good to know it's a known fact.

Unfortunately for me, the first definition is part of another protocol (which requires an existential Action) and the second has the Hashable requirement.

1 Like