-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[CSSimplify] Reject key path if root type is AnyObject #23820
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
[CSSimplify] Reject key path if root type is AnyObject #23820
Conversation
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.
Thank you for following up on this!
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.
LGTM! Before we merge could you please add some more tests e.g.
let _: KeyPath<AnyObject, Int> = \.<valid-member>
and something like:
func foo(_ obj: AnyObject, _ kp: KeyPath<AnyObject, Int>) {
_ = obj[keyPath: \.<valid-member>]
_ = obj[keyPath: kp]
}
@xedin Done! |
Also added a custom diagnostic for this scenario
@jckarter Can you please take a look as well? |
@swift-ci please smoke test |
Two code completion related failures, not sure how these tests work so need to figure out what's broken. Also some failures in stdlib/Keypath.swift tests. I think this has to do with returning an unsolved constraint. |
Ok so the code that's broken is keyPath.test("offsets") {
let SLayout = MemoryLayout<S<Int>>.self
...
expectEqual(SLayout.offset(of: \.self), 0) // expression type 'Int?' is ambiguous without more context
} is this expected? Auto complete does not provide any suggestions as well after the dot. |
That code looks like it ought to compile. |
Hmm it's due to creating an unsolved KeyPath constraint if the root type of the KeyPath is a type variable. If I don't do that, then the test passes. @xedin any ideas? Below is the CS dump:
Do we actually need the unsolved constraint (at least in |
@theblixguy Unfortunately we have to do that for correctness, otherwise there is no way to ensure that such type variable is not going to get bound to I also want to clean up keypath constraint when I get a chance because we shouldn't even consider it until all of the components are resolved. |
@xedin Do you mean something like: if (isa<KeyPathExpr>(typeVar->getImpl().getLocator()->getAnchor())) {
if (type->isAnyObject()) {
// Create and record fix
}
} ? I am not sure if there is a way to check if a locator points to the root of a key path (we don't have a path element for that, only for a key path component and we don't have one for the example above). I was thinking if we could record the ID of the type variable for the key path's root type then we can later check which type we're assigning to the type variable. |
@theblixguy Must suggestion is to create a separate locator path element for root and value type variables related to subscript so it's easily identifiable. |
@xedin Sorry, I don't understand. Are you saying I should add new path elements to the PathElementKind enum and then specify them in CSGen when creating the KeyPath constraint or type variable for the root type?. Also, why related to subscripts? |
Sorry, I meant keypath :) Yeah, that's exactly what I mean, root type variable should be identified as |
I will take a look at the a bit later today, but we should diagnose that. I remember that keypath overload is treated specially, so it might be possible to identify root type or diagnose inline. |
@theblixguy You can check for |
Thanks, I have made the change in commit d11b259, however the fix isn't being picked up and the switch statement in fixMemberRef isn't triggered as well. Maybe I am missing something... |
Ah, that's probably because that choice doesn't have a declaration, see at the top of d11b259#diff-69306f7b0822cf52e8c0639307ad7407R4269 . It looks |
That would be great @xedin! |
@swift-ci please smoke test |
Unrelated build failure on macOS (something to do with lldb apparently) |
@swift-ci please smoke test macOS platform |
Hmm the macOS test failed because the any object error is being created twice for |
I don’t understand, I thought that you mentioned in your previous comments that this case is not being diagnosed at all? It being diagnosed twice now goes contrary to that comment. |
Sorry, the case that was not being diagnosed was func doNotCrash_1(_ obj: AnyObject, _ kp: KeyPath<AnyObject, Int>) {
let _ = obj[keyPath: \.abc] // error
let _ = obj[keyPath: kp] // no error
} Now it's being diagnosed, which is great, however the first example is being diagnosed twice now. Maybe we can skip creating a fix in matchTypesBindTypeVars if the anchor points to a subscript because we're already doing that in fixMemberRef. |
Ok that makes more sense :) I think locators of the choice and root type supposed to be common besides ‘KeyPathRoot’ element, right? I think the way to resolve this situation would be to check if we already have a fix for choice before creating one for root via |
Yeah, that's right! Although we're creating a fix for the subscript member and one for the key path root: let _ = obj[keyPath: \.abc]
^ here & ^ here they have separate locators, so cannot use |
Yeah, that’s what I was asking - how do these locators look, are there common parts to them? |
They're both different:
It would be nice if we could dump each path element so I can see all the parts that make up the path (could write one if needed). I think the KeyPath path should have the subscript path element in it (?), let me check... EDIT: Yes, seems like they do:
That's what I get in matchTypesBindTypeVar when I dump the locator if the locator's path contains a SubscriptMember path element. Is there a better way to erase a path element in a locator? |
Actually I think it's okay to diagnose it twice, once for each keypath for now, let's not over-complicate the changes further. |
@swift-ci please test |
Sure! I have updated the expected-error count to 2 for that test now, so all tests should pass🤞 |
@swift-ci please test |
@swift-ci please test source compatibility |
I'll get this squashed and cherry-pick to 5.1 as well. |
Build failed |
@swift-ci please test macOS platform |
@theblixguy Thank you again! |
Follow up to #23497 based on Slava's suggestion. Moved the logic for checking if a
KeyPath
root type isAnyObject
from CSApply to solver, so we can reject a solution if the root type isAnyObject
.Resolves: rdar://problem/49413561