Skip to content
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

SE-0352: Specify that parenthesizing "as any P" prevents opening suppression #1647

Merged
merged 1 commit into from
May 11, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions proposals/0352-implicit-open-existentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,20 +462,43 @@ Swift 6 will be a major language version change that can incorporate some semant

### Suppressing explicit opening with `as any P` / `as! any P`

If for some reason one wants to suppress the implicit opening of an existential value, one can explicitly write a coercion or forced cast to an existential type. For example:
If for some reason one wants to suppress the implicit opening of an existential value, one can explicitly write a coercion or forced cast to an existential type directly on the call argument. For example:

```swift
func f1<T: P>(_: T) { } // #1
func f1<T>(_: T) { } // #2

func test(p: any P) {
f1(p) // opens p and calls #1, which is more specific
f1(p as any P) // suppresses opening of 'p', calls #2 which is the only valid candidate
f1(p) // opens p and calls #1, which is more specific
f1(p as any P) // suppresses opening of 'p', calls #2 which is the only valid candidate
f1((p as any P)) // parentheses disable this suppression mechanism, so this opens p and calls #1
}
```

Given that implicit opening of existentials is defined to occur in those cases where a generic function would not otherwise be callable, this suppression mechanism should not be required often in Swift 5. In Swift 6, where implicit opening will be more eagerly performed, it can be used to provide the Swift 5 semantics.

An extra set of parentheses will disable this suppression mechanism, which can be important when `as any P` is required for some other reason. For example, because it acknowledges when information is lost from the result type due to type erasure. This can help break ambiguities when both meanings of `as` could apply:

```swift
protocol P {
associatedtype A
}
protocol Q {
associatedtype B: P where B.A == Int
}

func getP<T: P>(_ p: T)
func getBFromQ<T: Q>(_ q: T) -> T.B { ... }

func eraseQAssoc(q: any Q) {
getP(getBFromQ(q)) // error, must specify "as any P" due to loss of constraint T.B.A == Int
getP(getBFromQ(q) as any P) // suppresses error above, but also suppresses opening, so it produces
// error: now "any P does not conform to P" and op
getP((getBFromQ(q) as any P)) // okay! original error message should suggest this
}

```

## Source compatibility

This proposal is defined specifically to avoid most impacts on source compatibility, especially in Swift 5. Some calls to generic functions that would previously have been ill-formed (e.g., they would fail because `any P` does not conform to `P`) will now become well-formed, and existing code will behavior in the same manner as before. As with any such change, it's possible that overload resolution that would have succeeded before will continue to succeed but will now pick a different function. For example:
Expand Down Expand Up @@ -626,6 +649,10 @@ This approach is much more complex because it introduces value tracking into the

## Revisions

Fifth revision:

* Note that parentheses disable the `as any P` suppression mechanism, avoiding the problem where `as any P` is both required (because type erasure lost information from the return type) and also has semantic effect (suppressing opening).

Fourth revision:

* Add discussion about type erasure losing constraints and the new requirement to introduce an explicit `as` coercion when the upper bound loses information.
Expand Down