Skip to content

Class pattern matching fails for final non-bivariant classes #1458

@MeGaGiGaGon

Description

@MeGaGiGaGon

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

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
Examples showing similar code working, and runtime test

https://play.ty.dev/6e0c778e-50fa-4239-a81e-747ac9351f3a

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'

Version

playground (5139f76d1)

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingnarrowingrelated to flow-sensitive type narrowing

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions