Equality of functions

It only memcmps the inline storage of view structs. SwiftUI would certainly like to also look into closure contexts (though, even more, they'd like the out-of-line closure allocation to go away entirely), but there's no way to do so with the runtime information closures have now. The ABI for function values is intentionally general—the only guarantees are that the invocation function is a valid function pointer, and that for escaping closures the context word can be passed to swift_retain and swift_release. Any other details of what the context points to are a private contract between the invocation function and the context object. It is not necessarily even a valid pointer, because swift_retain on some platforms recognizes certain input values as obviously invalid and ignores them, and when it is, it isn't necessarily a pointer to something that's specifically a closure context, since a closure capturing a single refcounted value will directly adopt that one pointer as its context value.

Within this ABI, we could still add functionality to make it possible for some closure contexts to be deeply memcmp'ed, by having the compiler emit them with a new MetadataKind that guarantees that there is size information stored in the metadata somewhere that the runtime can find it. Maybe the runtime could then provide a runtime function that conservatively compares two closure values, by memcmp-ing the function values themselves, then if the context pointer is not an ignored-by-swift_retain value and therefore a valid pointer, checking the metadata of the pointers to see if they're one of these new kinds with size information, and then memcmp-ing the contexts if they are. That would probably be best vended from the runtime itself since it would rely on platform-specific details of the runtime implementation.

In this world with generic function constraints, it should be possible to make it so today's function types also serve as the any (...) -> T existential type, since the closure representation can accommodate all the information it needs—the invocation function is effectively the witness for the one callAsFunction requirement. Composition types like Equatable & () -> Void don't exist today, so they don't have any preexisting ABI compatibility concerns, so they ought to be able to use the same implementation as other existential types. This is similar to how Error works, where the Error type itself uses a specialized representation to be able to toll-free-bridge with NSError, but compositions like Error & SomeOtherProtocol use the normal representation.

Sure, the types that closures-as-generic-parameters would form seem like they ought to be as reflectable as other types are. The closure contexts that are generated today are not, really, because there's no ABI guarantee for what the compiler may generate in the future.

9 Likes