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鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Parse] [Sema] [SR-3174] Ignore local variables in selector #9496
Conversation
lib/Sema/TypeCheckConstraints.cpp
Outdated
@@ -813,6 +815,15 @@ namespace { | |||
return finish(true, TC.resolveDeclRefExpr(unresolved, DC)); | |||
} | |||
|
|||
if (auto selector = dyn_cast<ObjCSelectorExpr>(expr)) { |
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.
Can you leave a short comment explaining why selector references are exempt from circularity checks.
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.
I just added a short comment in the code (see latest commit).
|
||
// SR-3174 | ||
|
||
class Hello { |
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.
In addition to these tests, please add one with nested declarations and another that uses a top-level selector.
@swift-ci please smoke test |
@CodaFi I added another test, you can smoke test again. |
@swift-ci please smoke test |
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.
Thanks for working on this! This is what I called the "basic fix", which disallows this currently-legal code:
import Foundation
func test(_ obj: NSObject) {
let x = #selector(obj.copy)
print(x)
}
test(NSObject())
As such, we'd need to limit the change to Swift 4 mode. You can test TC.getLangOptions().isSwiftVersion3()
for that.
lib/Sema/TypeCheckConstraints.cpp
Outdated
// resolve the expression but ignore local variables to allow | ||
// conflicting method names | ||
if (auto selector = dyn_cast<ObjCSelectorExpr>(expr)) { | ||
if (selector->isMethodSelector()) { |
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.
What does being a method have to do with ignoring local variables?
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.
Well, correct me if I'm wrong but if it's a getter/setter selector, ignoring local variables doesn't make sense so there is only the method selector left where conflicts can occur with local variable names.
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.
To limit the change to Swift 4, should I wrap lines 821 to 828 with, would this be sufficient?
if !TC.getLangOptions().isSwiftVersion3() {
...
}
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.
Local variables still won't have selectors.
import Foundation
class Foo: NSObject {
@objc var value: Int = 0
func test() {
var value = 42
print(#selector(getter:value))
}
}
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.
And yes, that seems like the right way to limit it to Swift 4.
@DougGregor ping |
@jrose-apple I tried your currently-legal code that is now disallowed due to this PR (copied it to the end of the file In the screenshot below you can see the command I executed. |
Ah, that test probably runs against our fake version of the Mac SDK (in test/Inputs/clang-importer-sdk/), which wouldn't have all of NSObject's methods declared. It doesn't really matter which method you pick here; the point is it's accessing something on a local variable. |
@rmnblm I'm going to close this out since it's been two years, but I think the idea you've got is correct and can probably be retailored to fix this SR. If you're interested in picking this back up, either reopen this pull request after a rebase or open a new one. I'm also resetting the assignee for this SR so somebody else can take a look. Thanks for the work you've done so far. Hopefully it can help another contributor out in the future. |
Declaring a variable and assigning a selector that refers to a method with the same name as the variable is currently not possible. The compiler will complain with an error message.
However, the compiler should realise that not the variable, but instead, the method
bar()
was meant to be used. A local variable can't even be a selector.Again, the compiler will complain with an appropriate error message.
This pull request changes this behaviour and allows the usage of the same name in a selector.
The compiler does this now in two steps: Firstly, the parser ignores the
DisabledVars
property if a selector is currently being parsed. In addition, while the type checker walks the AST and stumbles across anObjCSelectorExpr
, it ignores local variables when trying to resolve anUnresolvedDeclRefExpr
.Resolves SR-3174.
Can you take a look at it, @DougGregor or @jrose-apple? 馃檹