Need better exhaustiveness for record-typed type matching. #4249
Labels
exhaustiveness
patterns
Issues related to pattern matching.
request
Requests to resolve a particular developer problem
Currently record patterns can exhaust a union/sealed type field by exhausting the subtypes.
However, if you use an object or type pattern with the actual type of the record, that does not exhaust:
or
The error given is that it doesn't exhaust the type
({int? Value})
.That error makes sense if the type had been a generic class.
Here a value could have runtime type
C<int?>
. That is not the case for record types. The runtime type of a record type cannot have a field type that is an empty type.We let
s(int? v) => switch (v) { int _ => "a", Null _ => "b" };
exhaustint?
because we know thatint?
itself is an empty type, which is the samesealed
types are abstract. That works for single values, but not for generic type arguments, which can have the empty type. It works for values, not types.We allow record patterns to do the same thing for record values with a matched value type containing exhaustible types, you can exhaust a field by exhausting the non-empty subtypes of its static type.
But we do not do the same thing for record types, and we should.
(Also has the "funny" consequence that this is not exhaustive:
and yet the analyzer complains that the
&& ...
clauses are unnecessary.)Possible fix
Not sure exactly where to poke the algorithm.
Maybe in the "Expanding a space" section where the space for a sealed type is expanded into
the set of its subtypes, union types are split into the spaces of their parts, and enums and
bool
are split into value spaces.
If we add an item saying;
(I probably missed some details, but "all the cross products of all the field spaces" is the general idea.)
Then record types will be treated as as-expandable as the types they're composed of, and in particular
(T,)
is just as exhaustible asT
.@munificent @stereotype441
The text was updated successfully, but these errors were encountered: