young
(rtSwift)
1
In one case ordering, get warning. In a different ordering, no warning. Even though in both certain case will never be reached:
enum Thing {
case one, two
}
func printThing000(_ thing: Thing?) {
// case's in this order, get warnings
switch thing {
case .none:
print("000 .none")
case .some(let me):
print("000 .some of \(me)")
case .one: // Warning: Case is already handled by previous patterns; consider removing it
print("000 .one")
case .two: // Warning: Case is already handled by previous patterns; consider removing it
print("000 .two")
}
}
func printThing111(_ thing: Thing?) {
// case's in this order, no warning even though case .some() will never be reached
switch thing {
case .none:
print("111 .none")
case .one: // no warning
print("111 .one")
case .two: // no warning
print("111 .two")
case .some(let me): // will never be matched to here
print("111 .some of \(me)")
}
}
1 Like
xwu
(Xiaodi Wu)
3
Your enum isn’t frozen to have only two cases forever (which would be the case if it were explicitly declared as such in a separate, ABI-stable library). If you add a new case three to your enum, the last two cases in the first example will still never be reached, but the last case in the second example will become reachable.
2 Likes
young
(rtSwift)
4
After adding @fronzen to the enum doesn't change anything. The second example still no warning. Is this correct behavior?
young
(rtSwift)
6
Declaring the enum this way is not "frozen"?
@frozen
enum Thing {
case one, two
}
xwu
(Xiaodi Wu)
7
@frozen is an opt-out from certain restrictions for libraries compiled in library evolution mode. It was first available for the C overlay, standard library, and libraries shipped by Apple as of SE-0192, and then was extended to user-defined types in libraries compiled in library evolution mode in SE-0260. The attribute has no effect when library evolution mode is off. See the Swift Evolution proposals for more details.
3 Likes
xwu
(Xiaodi Wu)
8
Interesting, though, I think you're onto something in terms of a discrepancy:
var sign: FloatingPointSign? = .plus
switch sign {
case .none: fallthrough
case .minus: fallthrough
case .plus: print("Hi")
default: fatalError() // warning: default will never be executed
}
switch sign {
case .none: fallthrough
case .minus: fallthrough
case .plus: print("Hi")
case .some(_): fatalError() // no warning, hmm...
}
2 Likes
Not sure if this is exactly identical, but here's an earlier similar bug. You'll notice a lot more weirdness in this area, like you're not even allowed explicitly mention the enum name and you have to use implicit member expressions:
var sign: FloatingPointSign? = .plus
switch sign {
case .none: fallthrough
case FloatingPointSign.minus: fallthrough // error: enum case 'minus' is not a member of type 'FloatingPointSign?'
case .plus: print("Hi")
}
I think they're two different issues. One is related to name lookup being weird and the other is about exhaustivity checking not working correctly.
1 Like
young
(rtSwift)
12
This crash:
switch sign {
case _: fallthrough
//case .minus: fallthrough
//case .plus: print("Hi")
// does warning: Case is already handled by previous patterns; consider removing it
case .some(_): fatalError() // !!! crash here: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
}
xwu
(Xiaodi Wu)
13
What do you expect it to do?
GreatApe
(Gustaf Kugelberg)
15
Not really. If you remove the optionality, the compiler will treat your two cases .one and .two as exhaustive, so there is clearly a bug or limitation here, where it can't figure it out correctly when stashed inside an optional.