Skip to content

Commit 9754d51

Browse files
authored
Further changes to source compatibility
1 parent e6c7235 commit 9754d51

File tree

1 file changed

+2
-39
lines changed

1 file changed

+2
-39
lines changed

proposals/NNNN-generalize-keypath-function-conversions.md

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ let f: (User) -> String? = { kp in { root in root[keyPath: kp] } }(\User.email)
7070

7171
## Source compatibility
7272

73-
While this proposal _mostly_ only makes previously invalid code valid, [@jrose](https://forums.swift.org/u/jrose) pointed out a case where this proposal could potentially change the meaning of existing code:
73+
This proposal makes previously invalid conversions valid, and should not affect source compatibility. In situations such as:
7474

7575
```swift
7676
func evil<T, U>(_: (T) -> U) { print("generic") }
@@ -79,44 +79,7 @@ func evil(_ x: (String) -> Bool?) { print("concrete") }
7979
evil(\String.isEmpty)
8080
```
8181

82-
Previously, the `evil` call would select the first overload of `evil` (printing "generic", since the `KeyPath<String, Bool>` to `(String) -> Bool?` conversion was considered invalid), but this proposal would select the second overload of `evil` (printing "concrete").
83-
84-
This proposal opts to treat such differences as a bug in the implementation of SE-0249, which promises that the keypath-to-function conversion will have "semantics equivalent to capturing the key path and applying it to the Root argument":
85-
86-
```swift
87-
evil({ kp in { $0[keyPath: kp] } }(\String.isEmpty)) // Prints 'concrete'
88-
```
89-
90-
The circumstances necessary are exceedingly narrow to reproduce the above behavior. It is not enough merely to declare the `evil` overloads. The following naive reproduction attempt fails to compile, thus posing no source compatibility error:
91-
92-
```swift
93-
struct S {
94-
let x: Bool
95-
}
96-
97-
func evil<T, U>(_: (T) -> U) { }
98-
func evil(_: (S) -> Bool?) { }
99-
evil(\S.x)
100-
```
101-
102-
That this compilation fails seems to be a bug of its own. The additional necessary ingredient appears to be overloading `x`—with the following additions, the snipped above compiles without error:
103-
104-
```swift
105-
protocol P {}
106-
extension P {
107-
var x: Bool { true }
108-
}
109-
extension S: P {}
110-
```
111-
112-
So, to summarize, in order to cause a source compatibility issue, one must have:
113-
1. Function overloads A and B accepting function arguments
114-
2. A call to the overloaded function name, passed a keypath literal using an overloaded property
115-
3. The keypath is viable for conversion to exactly one of A or B's parameter types under currently-implemented rules, but viable for conversion to _both_ A and B's parameter types under the rules in this proposal
116-
4. The overload which is *not* currently viable would outrank the currently-viable overload once both are made viable under this proposal
117-
5. A and B are not semantically interchangable such that calling one instead of the other results in a substantive change in behavior
118-
119-
In the author's judgement, the liklihood of any significant compatibility issue is negligible.
82+
we today resolve the `evil` call as referring to the generic function, since the conversion necessary for the concrete function is invalid. This proposal would make both overloads viable, but the concrete version is still considered a worse solution since it requires more conversions to reach a solution (not only does the keypath need to be converted to a function, but the 'natural' type of the keypath function is `(String) -> Bool`, which requires an additional conversion from the type system's perspective).
12083

12184
## Effect on ABI stability
12285

0 commit comments

Comments
 (0)