From cbb3a31c03d661f38a3df1b092d32ea54c41c0b6 Mon Sep 17 00:00:00 2001 From: MUHAMED FAZAL PS Date: Fri, 26 Jun 2026 17:12:09 +0530 Subject: [PATCH 1/2] fix: validate TypeVar upper bound when inferring self-type arguments in bind_self When a method has a self-parameter annotated with a TypeVar (e.g., self: list[SupportsRichComparisonT]), bind_self() infers the type arguments by matching the actual object type against the self-parameter type. Previously, these inferred types were applied without checking whether they satisfy the TypeVar's upper bound. This caused overloaded methods like list.sort() to silently accept invalid type arguments. For example, mypy would not report an error for calling sort() on list[int | None], even though None does not satisfy the SupportsRichComparison bound. The fix adds a validation step after infer_type_arguments() in bind_self() that checks each inferred type against its TypeVar's upper bound. If an inferred type violates the bound, the upper bound is used as a fallback, consistent with the behavior of pre_validate_solutions() in solve.py. --- mypy/typeops.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mypy/typeops.py b/mypy/typeops.py index 78448c60927f9..cdc9f375e76b1 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -505,6 +505,14 @@ class B(A): pass typeargs = infer_type_arguments( self_vars, self_param_type, original_type, is_supertype=True, erase_types=False ) + # Validate that inferred types satisfy TypeVar bounds. + # If not, fall back to the upper bound (same as pre_validate_solutions in solve.py). + from mypy.subtypes import is_subtype as is_subtype_check + + for i, (tv, t) in enumerate(zip(self_vars, typeargs)): + if t is not None and isinstance(tv, TypeVarType) and not tv.values: + if not is_subtype_check(t, tv.upper_bound): + typeargs[i] = tv.upper_bound if ( is_classmethod and any(isinstance(get_proper_type(t), UninhabitedType) for t in typeargs) From 7b03b35a955d5aa09272508dc4cea3cc7b3041ce Mon Sep 17 00:00:00 2001 From: MUHAMED FAZAL PS Date: Fri, 26 Jun 2026 17:45:01 +0530 Subject: [PATCH 2/2] Revert: TypeVar bound check in bind_self causes false positives mypy_primer revealed regressions in spack, psycopg, optuna where the bound-based fallback was too aggressive and caused type narrowing. Reverting until a more precise fix can be designed. --- mypy/typeops.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/mypy/typeops.py b/mypy/typeops.py index cdc9f375e76b1..78448c60927f9 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -505,14 +505,6 @@ class B(A): pass typeargs = infer_type_arguments( self_vars, self_param_type, original_type, is_supertype=True, erase_types=False ) - # Validate that inferred types satisfy TypeVar bounds. - # If not, fall back to the upper bound (same as pre_validate_solutions in solve.py). - from mypy.subtypes import is_subtype as is_subtype_check - - for i, (tv, t) in enumerate(zip(self_vars, typeargs)): - if t is not None and isinstance(tv, TypeVarType) and not tv.values: - if not is_subtype_check(t, tv.upper_bound): - typeargs[i] = tv.upper_bound if ( is_classmethod and any(isinstance(get_proper_type(t), UninhabitedType) for t in typeargs)