You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: proposals/NNNN-generalize-keypath-function-conversions.md
+2-39Lines changed: 2 additions & 39 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -70,7 +70,7 @@ let f: (User) -> String? = { kp in { root in root[keyPath: kp] } }(\User.email)
70
70
71
71
## Source compatibility
72
72
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:
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
-
structS {
94
-
let x: Bool
95
-
}
96
-
97
-
funcevil<T, U>(_: (T) -> U) { }
98
-
funcevil(_: (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
-
protocolP {}
106
-
extensionP {
107
-
var x: Bool { true }
108
-
}
109
-
extensionS: 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).
0 commit comments