From 5b3fcab736ebfe7a6f35440c068ada1b9e91bcd1 Mon Sep 17 00:00:00 2001 From: Christoph Tyralla Date: Sun, 19 Mar 2023 00:33:37 +0100 Subject: [PATCH] Fix narrowing union types that include Self with isinstance (Fixes #14921). The special case of bound type variables was not handled in function `covers_at_runtime` of module `subtypes`. So I added it and defined the test case `testNarrowSelfType`. --- mypy/subtypes.py | 3 +++ test-data/unit/check-selftype.test | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index b322cf7b6cd8..9c6518b9e487 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1802,6 +1802,9 @@ def covers_at_runtime(item: Type, supertype: Type) -> bool: # Special case useful for selecting TypedDicts from unions using isinstance(x, dict). if supertype.type.fullname == "builtins.dict": return True + elif isinstance(item, TypeVarType): + if is_proper_subtype(item.upper_bound, supertype, ignore_promotions=True): + return True elif isinstance(item, Instance) and supertype.type.fullname == "builtins.int": # "int" covers all native int types if item.type.fullname in MYPYC_NATIVE_INT_NAMES: diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test index 752de3741456..8083aaf7cf38 100644 --- a/test-data/unit/check-selftype.test +++ b/test-data/unit/check-selftype.test @@ -1829,3 +1829,21 @@ class C(Generic[T]): reveal_type(self.val) # N: Revealed type is "__main__.A" \ # N: Revealed type is "__main__.B" self.val = x + +[case testNarrowSelfType] +from typing import Self, Union + +class A: ... +class B: + def f1(self, v: Union[Self, A]) -> A: + if isinstance(v, B): + return A() + else: + return v + def f2(self, v: Union[Self, A]) -> A: + if isinstance(v, B): + return A() + else: + return B() # E: Incompatible return value type (got "B", expected "A") + +[builtins fixtures/isinstancelist.pyi]