python / python/mypy

Narrowing an optional class type to an unrelated Protocol causes a false unreachable error

Abierto
#12,802 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

bug topic-protocols topic-reachability topic-type-narrowing
Lenguaje dominante
Python
Estrellas
20.6k
Forks
3.3k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

Bug Report

If Y is a runtime-checkable protocol which is not implemented by the class X, then mypy will erroneously consider the print statement in the following to be unreachable:

def f(x: Optional[X]) -> None:
    if isinstance(x, Y):
        print(x.bar())

This is incorrect, because x may be an object created from a subclass of X which does implement Y.

If x is annotated as X (not Optional[X]), then mypy behaves correctly.

To Reproduce

Save the following source code to a file (called foo.py below).

from typing import Optional, Protocol, runtime_checkable
from typing_extensions import reveal_type


class X:
    def foo(self) -> int:
        ...


@runtime_checkable
class Y(Protocol):
    def bar(self) -> int:
        ...


class Z(X):
    def foo(self) -> int:
        return 5

    def bar(self) -> int:
        return 6


def f(x: Optional[X]) -> None:
    reveal_type(x)
    if isinstance(x, Y):
        reveal_type(x)
        print(x.bar())


def g(x: X) -> None:
    reveal_type(x)
    if isinstance(x, Y):
        reveal_type(x)
        print(x.bar())


f(Z())
g(Z())

Run mypy on it with --warn-unreachable

Expected Behavior

> mypy --warn-unreachable foo.py
foo.py:25: note: Revealed type is "Union[foo.X, None]"
foo.py:27: note: Revealed type is "foo.<subclass of "X" and "Y">1"
foo.py:32: note: Revealed type is "foo.X"
foo.py:34: note: Revealed type is "foo.<subclass of "X" and "Y">1"
Success: no issues found in 1 source file

Actual Behavior

> mypy --warn-unreachable foo.py
foo.py:25: note: Revealed type is "Union[foo.X, None]"
foo.py:27: error: Statement is unreachable
foo.py:32: note: Revealed type is "foo.X"
foo.py:34: note: Revealed type is "foo.<subclass of "X" and "Y">1"
Found 1 error in 1 file (checked 1 source file)

(Running the script demonstrates that there is no actual unreachable code at runtime.)

Your Environment

  • Mypy version used: mypy 0.950 (compiled: yes)
  • Mypy command-line flags: --warn-unreachable
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: Python 3.10.4
  • Operating system and version:
Edition	Windows 10 Business
Version	21H1
Installed on	‎2.‎8.‎2021
OS build	19043.1706
Experience	Windows Feature Experience Pack 120.2212.4170.0

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Empieza guardando el reproductor proporcionado como foo.py y ejecutando mypy --warn-unreachable, comparando f y g. Después, rastrea el comportamiento del estrechamiento de tipos y del diagnóstico de código inalcanzable para Optional[X] frente a X. La tarea estará terminada cuando el caso opcional se estreche a una posible subclase de X/Y y coincida con la salida esperada sin un error de código inalcanzable.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
devtools
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Estancado
Claridad
Bien especificado
Aptitud para principiantes
45/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.