from typing import final, assert_never
@final
class FinalCovariant[T]:
def __init__(self, value: T):
self._value = value
def uses_final_covariant(value: FinalCovariant[int]):
match value:
case FinalCovariant():
reveal_type(value) # Should not be `Never`, but is
assert_never() # Should not pass, but does
class Covariant[T]:
def __init__(self, value: T):
self._value = value
def uses_covariant(value: Covariant[int]):
match value:
case Covariant():
reveal_type(value) # Is not `Never`
assert_never() # Correctly does not pass
@final
class FinalBivariant[T]: ...
def uses_final_bivariant(value: FinalBivariant[int]):
match value:
case FinalBivariant():
reveal_type(value) # Is not `Never`
assert_never() # Correctly does not pass
>>> from typing import final, assert_never)
...
... @final
... class FinalCovariant[T]:
... def __init__(self, value: T):
... self._value = value
...
... def uses_final_covariant(value: FinalCovariant[int]):
... match value:
... case FinalCovariant():
... reveal_type(value) # Should not be `Never`, but is
... assert_never() # Should not pass, but does
...
>>> from typing import reveal_type
>>> uses_final_covariant(FinalCovariant(1))
Runtime type is 'FinalCovariant'
Traceback (most recent call last):
File "<python-input-4>", line 1, in <module>
uses_final_covariant(FinalCovariant(1))
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
File "<python-input-2>", line 12, in uses_final_covariant
assert_never() # Should not pass, but does
~~~~~~~~~~~~^^
TypeError: assert_never() missing 1 required positional argument: 'arg'
Summary
If you try to pattern match on a final non-bivariant class using a class pattern, that match arm will be treated as never, despite being taken at runtime and working if any of the conditions are removed.
https://play.ty.dev/b6317b80-39f5-4e45-af1e-977eea84c3ae
Examples showing similar code working, and runtime test
https://play.ty.dev/6e0c778e-50fa-4239-a81e-747ac9351f3a
Version
playground (5139f76d1)