-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[CSRanking] Favour concrete members over protocol requirements #18927
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…concrete types over protocols Changes in shadowing behaviour by swiftlang#15412 caused a property on a concrete type to no longer shadow a protocol property member, which created unintentional ambiguities in 4.2. This commit ensures we at least keep these cases unambiguous in Swift 5 under Swift 4 compatibility mode. This is intentionally narrow in order to best preserve source compatibility under Swift 4 mode by ensuring we don't introduce any new ambiguities. Resolves SR-7425, SR-7940 & SR-8343.
This commit adds a new rule to `isDeclAsSpecializedAs` in order to favour a member on a concrete type over a protocol member. This rule is effectively an extension of the existing rule that prefers concrete type members over protocol extension members.
…anking This rule caused us to lose ambiguities in places where we really want ambiguity for `AnyObject` lookup, so only apply it when not comparing such overloads. This whole situation is a bit of a hack – really we shouldn't be applying any type-based or context-based overload ranking rules to overloads found through `AnyObject` lookup, but unfortunately we don't have syntax to precisely disambiguate overloads. This commit can be reverted if/when we ever remove `AnyObject` lookup.
cc. @slavapestov – I believe this can supersede #18206. |
Excellent! |
@swift-ci Please test |
@swift-ci Please test source compatibility |
Build failed |
Apparently, we cannot use an initializer list to construct a std::tuple there. Use `make_tuple` instead, and also simplify a condition to use `isDynamicOverloadComparison` while I'm here.
Just fixed the Linux failure. The source compatibility suite succeeded, though looking through the projects I realise that we wouldn't have exercised |
@hamishknight No. What I would suggest is removing the version check for the sake of running the compat suite to check that there aren't any unexpected breaks (and see what actually will break for people moving to Swift 5). |
@rudkx Thanks, I've gone ahead and done that – could you kick off the compat suite again? |
@swift-ci Please test source compatibility |
Can you split the changes up into separate PRs we get some feedback from the source compatibility suite? I'll take a closer look at each once that's done. I am a little concerned that at first glance some of the changes remind me of #17995 |
// x.i // ensure ambiguous. | ||
// } | ||
// | ||
if (true && !isDynamicOverloadComparison) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should probably be simplified to if (!isDynamicOverloadComparison)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, gotcha!
// compatibility under Swift 4 mode by ensuring we don't introduce any new | ||
// ambiguities. This will become a more general "is more specialised" rule | ||
// in Swift 5 mode. | ||
if (false && !isDynamicOverloadComparison && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that this code shouldn't exist?
// All other things being equal, apply the Swift 4 compatibility hack for | ||
// preferring var members in concrete types over a protocol requirement | ||
// (see the comment above for the rationale of this hack). | ||
if (false && score1 == score2) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here?
@rudkx As this branch stands today it preserves behavior when it comes to protocol vs. protocol extension declarations, and would always pick declaration on protocol... |
@hamishknight Yes, we can close this out in favor of the two new PRs. Thanks! |
This PR comes in two pieces:
1. A narrow Swift 4.1 compatibility hack that favours properties in concrete types over protocol requirements
This was unintentionally regressed by #15412, and is tracked by SR-7425. This is added as a ranking tie-breaker in order to ensure we don’t introduce any new ambiguities.
2. A new Swift 5 mode ranking rule that favours arbitrary concrete type members over protocol requirements
We already have a similar rule that prefers concrete members over protocol extension members – IMO this new rule is a natural extension of it.
This allows the following code to become unambiguous in Swift 5 mode:
Note that this new rule isn’t applied to overloads found through dynamic lookup in order to ensure we keep cases such as SR-7299 ambiguous.
Note also that this new rule is potentially source breaking (hence why it requires Swift 5 mode) – for example, the following contrived case is currently unambiguous, but will be made ambiguous by the change:
Arguably this change is unifying the behaviour with that of protocol extensions, where a similar example is already ambiguous:
And currently, adding
static func foo()
as a protocol requirement to the above suddenly resolves the ambiguity – with this Swift 5 mode change, the ambiguity is kept in both cases, which seems more consistent.I’m happy to split this PR up if the Swift 5 mode change requires more discussion.
Resolves SR-7425.