Should switch on UInt type be exhaustive for negative numbers?

I recently switched over a UInt type, and Swift displayed an error that my switch statement was not exhaustive, even though all possible UInt values were accounted for (zero to infinity). Is this a candidate for a change to the compiler, or am I missing something?

let nonNegativeNumber: UInt = 42
switch nonNegativeNumber {
case 0:
   break
case 1...:
   break
}

I am working at some changes to exhaustivity checking… so I've thought about this a little.

It's a Difficult Problem™️

The simplest implementation that I can think of, which is not to say that it is the simplest that anyone could think of, involves making ad hoc ranges that can only stride by 1., sorting those ranges, and then checking for exhaustivity while considering overlapping.

This limited support only gains you the ability to switch over a number, however. now consider that you can switch over a tuple where the number is just an element. The space gets big * a space that is getting big.

I do hope that, in the fullness of time, we get this, though.

1 Like

More technically, right now a switch statement doesn't know about anything except enums (and booleans, and tuples I guess). Any other checking just calls out to ~= for the given types. In order to support this kind of matching, the compiler would have to start tracking the stuff TJ is talking about, and it would have to assume that ranges of integers work that way. That's probably an okay assumption to hardcode in the compiler (both Range/ClosedRange and the standard integer types are part of the standard library), but that's why it's not there now. (Well, that and that the workaround of using a default with an assert is pretty easy, albeit ugly.)

1 Like

In theory, as the constexpr feature develops it will acquire these kinds of smarts over time. You can imagine us emitting a boolean expression that is false if all the case expressions are false (nonNegativeNumber ~= 0 || nonNegativeNumber ~= 1...). After enough mandatory inlining and constant folding, this might simplify down to true, in which case we could decide that the switch is exhaustive. If it does not simplify to a constant boolean, the switch is non-exhaustive.

Of course this just shifts the problem to the constant evaluator and there are theoretical limitations standing in the way of solving this in all cases, but I can imagine us implementing things well enough that it all works at least for common examples like exhaustive ranges over the integers.

I'd be a little worried of how that composes with enum cases and destructuring, though…

1 Like

Yeah, I didn't think it through. Just pointing out that we might one day have similar analysis built into mandatory passes, and it might make sense to leverage them instead of inventing a whole new thing specific to integers for exhaustivity checking :)