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
[SR-11828] case nil
compiles for any type even if it will never match, due to optional hoisting
#54240
Comments
Reproduction code: func foo(_ x: Int) {
switch x {
case nil: fatalError("unreachable")
default: break
}
} |
@swift-ci create |
Interesting! For the following code, we do emit a warning: func foo(_ x: Int) {
switch Optional.some(x) {
case .none: print("Unreachable")
default: ()
}
} but we suppress the warning if Right now, the constant evaluation machinery is relying on |
The warning in that case is different than in the original. Replacing I think the problem is in your sample code, you're stuffing a constant value into the |
> Replacing fatalError("unreachable") with print in my original sample still doesn't print a warning. Agreed. All I was saying was I would not expect your > I think the problem is in your sample code, you're stuffing a constant value into the I don't quite get what you mean by "optional hoisting" but I realize I was mistaken in understanding what it was "desugaring" to. func foo(_ x: Int) {
switch x {
case nil: print("unreachable")
default: break
}
}
// I initially thought it got translated to this [incorrect]
func foo(_ x: Int) {
switch Optional.some(x) {
case nil: print("unreachable")
default: break
}
}
// actually it seems to be getting treated like this [also incorrect?]
func foo(_ x: Int) {
switch x {
case (let y) where (nil ~= Optional.some(y)): print("unreachable")
default: break
}
} If it were getting treated as the second case, because that overload is marked @_transparent
func nope() -> Bool { return false }
func foo(_ x: Int) {
switch x {
case (let y) where nope(): print("unreachable")
default: print(x)
}
} So my second interpretation is also wrong. I wonder what it is actually doing. |
I do in fact expect it to print a warning. The warning in your case is "this code isn't reachable", and it makes sense to suppress that with a But in my case, I expect a warning even with
When you use a non-optional value in a place where the type system expects an optional, so the non-optional value is implicitly wrapped up in
I believe it's being treated as func foo(_ x: Int) {
switch x {
case (let y) where (nil ~= y): print("unreachable")
default: break
}
} This does not produce a warning. |
Makes sense. Thanks for clarifying. I think I realized the issue: |
Environment
Apple Swift version 5.1.2 (swiftlang-1100.0.278 clang-1100.0.33.9)
Target: x86_64-apple-darwin19.0.0
Additional Detail from JIRA
md5: 1b964c512d445f610c1522c297d47045
Issue Description:
It appears that in any
switch
you can writecase nil
(or usenil
as any sub-field of the case) and it will compile. It seems thenil
here is becoming an_OptionalNilComparisonType
, using~=
to compare, and the value it's comparing against is hoisted up to an optional.This can also be seen with the simple expression
nil ~= 3
.The net result here is I just wrote a case that can't possibly ever match and I got no warnings.
I believe we need to take the
~=(lhs: _OptionalNilComparisonType, rhs: Wrapped?)
operator and do whatever magic you've done in other cases to produce a warning if this optionally-hoists the right-hand side.The text was updated successfully, but these errors were encountered: