From 6683ab1bdd89b7e9474467fac550863af3e63acc Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Thu, 7 May 2026 12:10:18 +0100 Subject: [PATCH 1/3] Fix type variable with values as a supertype --- mypy/subtypes.py | 12 ++++++++++++ test-data/unit/check-typevar-values.test | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index b8e8d5e3b79df..b2bc31b181fbc 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -312,6 +312,18 @@ def _is_subtype( # ErasedType as we do for non-proper subtyping. return True + # Cases specific w.r.t. right type are easier to handle before entering the SubtypeVisitor. + # Currently, these include Union types and TypeVarType with values. + if isinstance(right, TypeVarType) and right.values and not isinstance(left, TypeVarType): + if proper_subtype: + if all( + is_proper_subtype(orig_left, v, subtype_context=subtype_context) + for v in right.values + ): + return True + elif all(is_subtype(orig_left, v, subtype_context=subtype_context) for v in right.values): + return True + if isinstance(right, UnionType) and not isinstance(left, UnionType): # Normally, when 'left' is not itself a union, the only way # 'left' can be a subtype of the union 'right' is if it is a diff --git a/test-data/unit/check-typevar-values.test b/test-data/unit/check-typevar-values.test index 72bf9f7f8083a..a1bf1bfec6829 100644 --- a/test-data/unit/check-typevar-values.test +++ b/test-data/unit/check-typevar-values.test @@ -744,3 +744,16 @@ def fn(w: W) -> W: reveal_type(w) # N: Revealed type is "builtins.int" return w [builtins fixtures/isinstance.pyi] + +[case testTypeVarValuesSubtypeOfAll] +from typing import TypeVar + +class B: ... +class C(B): ... + +S = TypeVar("S", B, C) +c = C() +def g(x: S = c): # OK + ... +def h(x: S = 0): # E: Incompatible default for parameter "x" (default has type "int", parameter has type "S") + ... From eb93a2f2ce4fd06134c0d6359344a3c86e9ed4a1 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Thu, 7 May 2026 12:12:40 +0100 Subject: [PATCH 2/3] Better test case --- test-data/unit/check-typevar-values.test | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test-data/unit/check-typevar-values.test b/test-data/unit/check-typevar-values.test index a1bf1bfec6829..e0ebc6ddf13ae 100644 --- a/test-data/unit/check-typevar-values.test +++ b/test-data/unit/check-typevar-values.test @@ -752,8 +752,9 @@ class B: ... class C(B): ... S = TypeVar("S", B, C) +b = B() c = C() def g(x: S = c): # OK ... -def h(x: S = 0): # E: Incompatible default for parameter "x" (default has type "int", parameter has type "S") +def h(x: S = b): # E: Incompatible default for parameter "x" (default has type "B", parameter has type "S") ... From c8a8a2433b04609376b3c6fdeb1069a8d5b8e441 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Thu, 7 May 2026 13:48:25 +0100 Subject: [PATCH 3/3] Address CR --- mypy/subtypes.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index b2bc31b181fbc..5733797326e88 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -314,16 +314,6 @@ def _is_subtype( # Cases specific w.r.t. right type are easier to handle before entering the SubtypeVisitor. # Currently, these include Union types and TypeVarType with values. - if isinstance(right, TypeVarType) and right.values and not isinstance(left, TypeVarType): - if proper_subtype: - if all( - is_proper_subtype(orig_left, v, subtype_context=subtype_context) - for v in right.values - ): - return True - elif all(is_subtype(orig_left, v, subtype_context=subtype_context) for v in right.values): - return True - if isinstance(right, UnionType) and not isinstance(left, UnionType): # Normally, when 'left' is not itself a union, the only way # 'left' can be a subtype of the union 'right' is if it is a @@ -372,6 +362,17 @@ def _is_subtype( elif is_subtype_of_item: return True # otherwise, fall through + + if isinstance(right, TypeVarType) and right.values and not isinstance(left, TypeVarType): + if proper_subtype: + if all( + is_proper_subtype(orig_left, v, subtype_context=subtype_context) + for v in right.values + ): + return True + elif all(is_subtype(orig_left, v, subtype_context=subtype_context) for v in right.values): + return True + return left.accept(SubtypeVisitor(orig_right, subtype_context, proper_subtype))