python / python/mypy

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

Đang mở
#12,802 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

bug topic-protocols topic-reachability topic-type-narrowing
Ngôn ngữ chính
Python
Star
20.6k
Fork
3.3k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

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

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu bằng cách lưu reproducer được cung cấp dưới dạng foo.py và chạy mypy --warn-unreachable, so sánh f và g. Sau đó, theo dõi hành vi thu hẹp kiểu và chẩn đoán mã không thể đạt tới đối với Optional[X] so với X. Hoàn thành khi trường hợp optional được thu hẹp thành một X/Y subclass có thể xảy ra và khớp với đầu ra mong đợi mà không có lỗi mã không thể đạt tới.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python
Lĩnh vực
devtools
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
45/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.