Skip to content

[ClangImporter] Put subscripts in the same DC as the found accessor #13470

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

Merged
merged 1 commit into from
Dec 18, 2017

Conversation

jrose-apple
Copy link
Contributor

@jrose-apple jrose-apple commented Dec 15, 2017

Objective-C subscripts don't have special declarations like properties; they're just specially-named methods (or method pairs), and we have to make an independent SubscriptDecl in Swift. Previously, we tried to always put that SubscriptDecl in the same context as the setter, but that doesn't make sense if the setter was actually inherited from a superclass! Give up on a consistent "always with the setter" or "always with the getter" rule, which doesn't really affect anything in practice, and instead just use the context we know we can trust: the one containing the declaration we started with, whether getter or setter.

This all started because when an Objective-C subclass wants to make a subscript settable, they just add the appropriately-named setter method. Swift handled this by detecting when the getter and setter weren't declared in the same type, and assuming this meant it was a subclass adding a setter. Unfortunately, the same condition also picked up the case where the getter (and only the getter) is redeclared in a subclass (perhaps to add an attribute), and the new subscript was getting added to the base class instead of the subclass.

The fix relies on the fact that the original decl we provide is what we use to look up the other accessor. If the getter and setter are in different types, whichever one we started with must be the more-derived one. So the final change is just "did we start with the setter?" rather than "is there a setter at all?".

I'm not sure why this is only just now causing problems, given that we seem to have been getting this wrong for years, but it definitely was wrong and now it's not. Unfortunately, it's been this way so long I can't trace back to a reason why it was this way. All the tests still pass.

rdar://problem/36033356

@jrose-apple
Copy link
Contributor Author

@DougGregor, @milseman, @rjmccall, do any of you know why the old code would have been doing this?

@jrose-apple
Copy link
Contributor Author

@swift-ci Please test macOS

@jrose-apple
Copy link
Contributor Author

@swift-ci Please smoke test Linux

@jrose-apple
Copy link
Contributor Author

@swift-ci Please test source compatibility

@rjmccall
Copy link
Contributor

Doing it based on which declaration we're currently importing is incoherent, right? You can get different results depending on what source code you're processing.

We have two DCs; can we find some way to merge them, e.g. picking the more-derived one?

@jrose-apple
Copy link
Contributor Author

You can always get different results depending on what source code you're processing (private module adds a setter), but I guess we should try to minimize the chances of that. Relying on the fact that we import things in the original module first is fragile.

@rjmccall
Copy link
Contributor

Well, I mean the Swift source code you're processing, like two different files in the same Swift module could decide that the subscript has a different DC based on the function bodies they process.

@jrose-apple
Copy link
Contributor Author

Ah. Yeah, that would be pretty icky, whether or not it resulted in problems. Okay, back to the drawing board.

Objective-C subscripts don't have special declarations like
properties; they're just specially-named methods (or method pairs),
and we have to make an independent SubscriptDecl in Swift. This means
that when a subclass wants to make a subscript settable, they just add
the appropriately-named setter method.

Swift handled this by detecting when the getter and setter weren't
declared in the same type, and assuming this meant it was a subclass
adding a setter. Unfortunately, the same condition /also/ picked up
the case where the getter (and only the getter) is /redeclared/ in a
subclass (perhaps to add an attribute), and the new subscript was
getting added to the base class instead of the subclass.

The fix relies on the fact that the original decl we provide is what
we use to look up the other accessor. If the getter and setter are in
different types, whichever one we started with must be the
more-derived one. So the final change is just "did we start with the
setter?" rather than "is there a setter at all?".

I'm not sure why this is only just now causing problems, given that we
seem to have been getting this wrong for years, but it definitely
/was/ wrong and now it's not.

rdar://problem/36033356
@jrose-apple jrose-apple force-pushed the suboptimal-subscripts branch from c39c3bb to 310a025 Compare December 16, 2017 00:45
@jrose-apple
Copy link
Contributor Author

Thanks for making me think about this a little more, John. I understand what the old code was trying to do now and this new version makes more sense.

@swift-ci Please test macOS

@jrose-apple
Copy link
Contributor Author

@swift-ci Please smoke test Linux

@jrose-apple
Copy link
Contributor Author

@swift-ci Please test source compatibility

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - c39c3bb5b0920bdbff4cac0d45f89eb61a03ef45

@@ -6345,8 +6345,6 @@ SwiftDeclConverter::importSubscript(Decl *decl,
->getAsNominalTypeOrNominalTypeExtensionContext() ==
setter->getDeclContext()
->getAsNominalTypeOrNominalTypeExtensionContext());
// TODO: Possible that getter and setter are different instantiations
// of the same objc generic type?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unrelated, but we never have this problem given the final design of ObjC generics: they erase the generic argument rather than instantiating multiple types.

@jrose-apple
Copy link
Contributor Author

@swift-ci Please test source compatibility

Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks

@jrose-apple jrose-apple merged commit e1f46b5 into swiftlang:master Dec 18, 2017
@jrose-apple jrose-apple deleted the suboptimal-subscripts branch December 18, 2017 19:01
jrose-apple added a commit to jrose-apple/swift that referenced this pull request Dec 18, 2017
…iftlang#13470)

Objective-C subscripts don't have special declarations like
properties; they're just specially-named methods (or method pairs),
and we have to make an independent SubscriptDecl in Swift. This means
that when a subclass wants to make a subscript settable, they just add
the appropriately-named setter method.

Swift handled this by detecting when the getter and setter weren't
declared in the same type, and assuming this meant it was a subclass
adding a setter. Unfortunately, the same condition /also/ picked up
the case where the getter (and only the getter) is /redeclared/ in a
subclass (perhaps to add an attribute), and the new subscript was
getting added to the base class instead of the subclass.

The fix relies on the fact that the original decl we provide is what
we use to look up the other accessor. If the getter and setter are in
different types, whichever one we started with must be the
more-derived one. So the final change is just "did we start with the
setter?" rather than "is there a setter at all?".

I'm not sure why this is only just now causing problems, given that we
seem to have been getting this wrong for years, but it definitely
/was/ wrong and now it's not.

rdar://problem/36033356
(cherry picked from commit e1f46b5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants