-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Swift 6 typed-throws unable to detect exhaustive catch statements #74555
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
Comments
Just an additional data point. Consider: enum MyError: Error {
case one
case two
}
func funcWithTypedThrow() async throws(MyError) {…} As NachoSoto pointed out, if you use separate // An example where typed-throw correctly infers the type of the thrown error, but
// incorrectly concludes catch is not exhaustive.
func foo() async {
do {
try await funcWithTypedThrow() // Swift 6.0 compiler incorrectly produces error: “Errors thrown from here are not handled because the enclosing catch is not exhaustive”
} catch .one {
print("one")
} catch .two {
print("two")
}
} Interestingly, if we add an extra // In this example, I added extra `catch` to silence the above error, but now
// the compiler now warns us that that this extra `catch` is unnecessary.
func bar() async {
do {
try await funcWithTypedThrow()
} catch .one {
print("one")
} catch .two {
print("two")
} catch { // Swift 6.0 compiler correctly produces warning: “Case will never be executed”
print("this is required to silence 'non-exhaustive' error, but generates a 'will never be executed' warning")
}
} So, it is not the case that it is entirely unaware of the exhaustive |
Another example (repro-ing on enum E: Error {
case e1
}
func f() throws(E) {
throw .e1
}
func g() {
do {
// Errors thrown from here are not handled because the enclosing catch is not exhaustive
try f()
} catch E.e1 {}
} |
FWIW, the issue persists in Swift version 6.1 (swiftlang-6.1.0.109.103 clang-1700.0.13.2), from Xcode 16.3 beta 2, too. For what it is worth, in the interim, one can use a enum MyError: Error {
case one
case two
}
func funcWithTypedThrow() async throws(MyError) {…}
func baz() async {
do {
try await funcWithTypedThrow()
} catch {
switch error {
case .one: print("one")
case .two: print("two")
}
}
} Again, it illustrates that it clearly understands that |
This just caught me by surprise. Especially as the compiler gives you an error to say you need an unconditional catch block, which if you add it then produces a warning that it's unexecutable. No sane language should tell you do something and then immediately tell you, you don't need it. This should be basically syntax sugar
For this:
|
@xwu said:
I would not say it is “by design”, but rather more of an acknowledged limitation. As they say a few lines later:
So, its not that it was designed with the intent of adding the unnecessary unconditional My point is that it’s not reasonable for the compiler to complain that the “Case will never be executed” when it was the compiler that insisted in the unnecessary unconditional |
Description
Consider the example below. Both
Error.a
andError.b
are caught, but the compiler is unable to infer that.Reproduction
Expected behavior
Code compiles
Environment
swift-driver version: 1.109.2 Apple Swift version 6.0 (swiftlang-6.0.0.3.300 clang-1600.0.20.10)
Target: arm64-apple-macosx14.0
Additional information
No response
The text was updated successfully, but these errors were encountered: