From 9a3f5c6e74e3e7e6b7c7ec174d79909f2b2d4242 Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Fri, 6 Mar 2026 18:46:45 +0500 Subject: [PATCH 1/4] Enhance subtype checking for TypeVarType and UnionType --- mypy/subtypes.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 66d7a95eb425..bcd794dcf90e 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -311,8 +311,23 @@ def _is_subtype( # TODO: should we consider all types proper subtypes of UnboundType and/or # ErasedType as we do for non-proper subtyping. return True - - if isinstance(right, UnionType) and not isinstance(left, UnionType): + + if isinstance(right, TypeVarType) and right.values: + if isinstance(left, TypeVarType) and left.id == right.id: + return True + if proper_subtype: + return all( + is_proper_subtype(orig_left, v, subtype_context=subtype_context) + for v in right.values + ) + else: + return all( + is_subtype(orig_left, v, subtype_context=subtype_context) for v in right.values + ) + # 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 + # subtype of one of the items making up the union. + 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 # subtype of one of the items making up the union. From c4faa018eefbad12be6e41570aa1ccea5ee75d1a Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Fri, 6 Mar 2026 18:51:39 +0500 Subject: [PATCH 2/4] Add subtype check in visit_type_var method --- mypy/join.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/join.py b/mypy/join.py index a8c9910e60bb..b8b1fe5071cb 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -295,8 +295,9 @@ def visit_deleted_type(self, t: DeletedType) -> ProperType: def visit_erased_type(self, t: ErasedType) -> ProperType: return self.s - def visit_type_var(self, t: TypeVarType) -> ProperType: + if is_subtype(self.s, t): + return t if isinstance(self.s, TypeVarType): if self.s.id == t.id: if self.s.upper_bound == t.upper_bound: @@ -308,7 +309,6 @@ def visit_type_var(self, t: TypeVarType) -> ProperType: return get_proper_type(join_types(self.s.upper_bound, t.upper_bound)) else: return self.default(self.s) - def visit_param_spec(self, t: ParamSpecType) -> ProperType: if self.s == t: return t From 30f6c49cbe2dce11e190c4358cf0051bdce5ff9d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 14:12:40 +0000 Subject: [PATCH 3/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/join.py | 2 ++ mypy/subtypes.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mypy/join.py b/mypy/join.py index b8b1fe5071cb..6e21171378ab 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -295,6 +295,7 @@ def visit_deleted_type(self, t: DeletedType) -> ProperType: def visit_erased_type(self, t: ErasedType) -> ProperType: return self.s + def visit_type_var(self, t: TypeVarType) -> ProperType: if is_subtype(self.s, t): return t @@ -309,6 +310,7 @@ def visit_type_var(self, t: TypeVarType) -> ProperType: return get_proper_type(join_types(self.s.upper_bound, t.upper_bound)) else: return self.default(self.s) + def visit_param_spec(self, t: ParamSpecType) -> ProperType: if self.s == t: return t diff --git a/mypy/subtypes.py b/mypy/subtypes.py index bcd794dcf90e..8a8037014b26 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -311,7 +311,7 @@ def _is_subtype( # TODO: should we consider all types proper subtypes of UnboundType and/or # ErasedType as we do for non-proper subtyping. return True - + if isinstance(right, TypeVarType) and right.values: if isinstance(left, TypeVarType) and left.id == right.id: return True From 0fc1b7bdf85c48d8a7bc1016c8da8dd3fcc6b0d4 Mon Sep 17 00:00:00 2001 From: Shrey Naithani Date: Fri, 6 Mar 2026 19:18:07 +0500 Subject: [PATCH 4/4] Update subtypes.py --- mypy/subtypes.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 8a8037014b26..8f2287e4ce3d 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -324,10 +324,8 @@ def _is_subtype( return all( is_subtype(orig_left, v, subtype_context=subtype_context) for v in right.values ) - # 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 - # subtype of one of the items making up the union. - if isinstance(right, UnionType) and not isinstance(left, UnionType): + + 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 # subtype of one of the items making up the union.