TODO:
- Select the KeyPath subclass corresponding to the write capability of the key path components
- Figure out an issue with unresolved solutions being chosen with contextually-typed keypaths
- Diagnostic QoI
When in Swift 3 compatibility mode without
`-warn-swift3-objc-inference`, warn on the *uses* of declarations that
depend on the Objective-C runtime that became `@objc` due to the
deprecated inference rule. This far more directly captures important
uses of the deprecated Objective-C entrypoints. We diagnose:
* `#selector` expressions that refer to one of these `@objc` members
* `#keyPath` expressions that refer to one of these `@objc` members
* Dynamic lookup (i.e., member access via `AnyObject`) that refers to
one of these `@objc` members.
In Swift 3, unqualified lookup would skip static methods
when performing a lookup from instance context.
In Swift 4 mode, if a module method is shadowed by a static
method, you will need to qualify the module method with the
module name.
It would have been nice to isolate the quirk in Sema and
not AST, but unfortunately UnqualifiedLookup only proceeds
to lookup in the module if scope-based lookup failed to find
anything, and I don't want to change that since it risks
introducing performance regressions.
Fixes <rdar://problem/29961715>.
We do this in a more general way higher up in the constraint
solver. Filtering out methods in name lookup only hurts
diagnostics.
In fact I don't think this behavior was intentional at all,
since the code in question was originally written in 2013
before a lot of the more recent member lookup and diagnostic
code was added.
This does break source compatibility though, but in a minor
way. See the change to the CoreGraphics overlay. Again,
though, I think this was an accident and not intentional.
Implement the Objective-C #keyPath expression, which maps a sequence
of @objc property accesses to a key-path suitable for use with
Cocoa[Touch]. The implementation handles @objc properties of types
that are either @objc or can be bridged to Objective-C, including the
collections that work with key-value coding (Array/NSArray,
Dictionary/NSDictionary, Set/NSSet).
Still to come: code completion support and Fix-Its to migrate string
literal keypaths to #keyPath.
Implements the bulk of SR-1237 / rdar://problem/25710611.
When we see a string literal used to initializer a Selector, and that
string literal names the selector for the getter or setter of an
Objective-C property, suggest #selector(getter: ...) or
This completes SE-0064. Big thanks for Alex Hoppen (@ahoppen) for his
contributions here.
Implements the core functionality of SE-0064 / SR-1239, which
introduces support for accessing the Objective-C selectors of the
getter and setter of an @objc property via #selector(getter:
propertyName) and #selector(setter: propertyName).
Introduce a bunch of QoI around mistakes using #selector to refer to a
property without the "getter:" or "setter:", using Fix-Its to help the
user get it right. There is more to do in this area, still, but we
have an end-to-end feature working.
Much of the implementation and nearly all of the test cases are from
Alex Hoppen (@ahoppen). I've done a bit of refactoring, simplified the
AST representation, and replaced Alex's custom
expression-to-declaration logic with an extension to the constraint
solver. The last bit might be short-lived, based on swift-evolution
PR280, which narrows the syntax of #selector considerably.
Type level lookups can fail because the lookup is on an existential
metatype, like `MyProtocol.staticMethod(_:)` is invalid; however the
error message is unclear: “static member 'staticMethod(_:)' cannot be
used on instance of type ‘MyProtocol.Protocol’”.
This fix checks the base of member lookups that failed with the reason
UR_TypeMemberOnInstance for being existential metatypes. It produces
the clearer message “static member ‘staticMethod(_:)’ cannot be used on
protocol metatype ‘MyProtocol.Protocol’”. This change makes it clear
that the use of a static member on the *existential* metatype is the
problem.
When the selector named by Selector("foo") does not map to a known
Objective-C method, allow one to suppress the warning by wrapping the
string literal in an extra set of parentheses, e.g.,
Selector(("foo"))
Suggest this via a Fix-It on a note so it's discoverable. Addresses
rdar://problem/24791200.
Introduce Fix-Its to aid migration from selectors spelled as string
literals ("foo:bar:", which is deprecated), as well as from
construction of Selector instances from string literals
(Selector("foo:bar"), which is still acceptable but not recommended),
to the #selector syntax. Jump through some hoops to disambiguate
method references if there are overloads:
fixits.swift:51:7: warning: use of string literal for Objective-C
selectors is deprecated; use '#selector' instead
_ = "overloadedWithInt:" as Selector
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#selector(Bar.overloaded(_:) as (Bar) -> (Int) -> ())
In the cases where we cannot provide a Fix-It to a #selector
expression, we wrap the string literal in a Selector(...) construction
to suppress the deprecation warning. These are also easily searchable
in the code base.
This also means we're doing more validation of the string literals
that go into Selector, i.e., that they are well-formed selectors and
that we know about some method that is @objc and has that
selector. We'll warn if either is untrue.