Hey folks!
I've got a PR up now to add a warning, and I wanted to get some feedback here before hitting merge. It's about everyone's favorite feature: retroactive conformances.
Specifically, retroactive conformances that conform a type defined outside the current module to a protocol defined outside the current module. For example, the following extension declares such a conformance (poorly, I might add):
extension String: Identifiable {
public var id: Int { self.count }
}
Such an extension may seem fine -- I would like to provide a custom notion of identity. But the issue is that these conformances are global. There can only be one conformance of any given type to any given protocol at runtime. If the standard library chooses to add such a conformance in a later OS release, that will result in duplicate symbols at load time conformances at runtime, and the dynamic loader Swift runtime's dynamic dispatch logic will just pick
one.
If an app defines one of these, the issue is limited in scope -- this will just result in undefined behavior for that app until they recompile against the new SDK and delete their conformance.
Where it becomes a much larger issue is with distributed libraries and frameworks declaring these conformances. Given that there can only be one such conformance at runtime, if two frameworks declare the same conformance, then every app that uses them both will have the same issue. This might still not be a huge issue -- I'd be willing to assume the vast majority of Swift frameworks are developed and bundled within a single app.
So because of that, this warning mostly applies to libraries that are meant to be distributed. As such, I'd like to emit a warning for an extension when:
- The module has library evolution enabled (which includes those having adopted
Build Libraries for Distribution
in Xcode) - The type being extended comes from a module outside the current compiled module (or the underlying Clang module, if this is an overlay)
- The extension introduces a new conformance to any protocol that comes from outside the current module (or the underlying Clang module, if this is an overlay).
For the above code, the warning will read:
warning: extension declares a conformance of imported type 'String' to imported protocol 'Identifiable'; this is not supported when library evolution is enabled
And this warning can be silenced by explicitly module-qualifying all the types involved that come from outside the module. The example above would need to be rewritten:
extension Swift.String: Swift.Identifiable {
public var id: Int { self.count }
}
And the compiler will offer a fix-it to insert the appropriate qualification.
So my main questions here are:
- Do folks think this is a good thing to warn about?
- Is the scope of when the warning applies too broad, or not broad enough?
- Is the proposed way to silence the warning too easy to silence?
Thanks!