From 043963ad3da578414787eb8b62d888f39c8eb3d2 Mon Sep 17 00:00:00 2001 From: Dendroculus Date: Sun, 2 Aug 2026 21:31:40 +0700 Subject: [PATCH 1/3] Fix redundant cast detection for generic calls --- mypy/checkexpr.py | 5 +---- test-data/unit/check-warnings.test | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 172d44555b946..bd6127fd372a7 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4850,10 +4850,7 @@ def visit_enum_index_expr( def visit_cast_expr(self, expr: CastExpr) -> Type: """Type check a cast expression.""" source_type = self.accept( - expr.expr, - type_context=AnyType(TypeOfAny.special_form), - allow_none_return=True, - always_allow_any=True, + expr.expr, type_context=None, allow_none_return=True, always_allow_any=True ) target_type = expr.type options = self.chk.options diff --git a/test-data/unit/check-warnings.test b/test-data/unit/check-warnings.test index a2d201fa301d9..641072c6c5311 100644 --- a/test-data/unit/check-warnings.test +++ b/test-data/unit/check-warnings.test @@ -12,6 +12,20 @@ c = cast(int, a) [out] main:5: error: Redundant cast to "int" +[case testRedundantCastGenericReturn] +# flags: --warn-redundant-casts +from typing import TypeVar, cast + +T = TypeVar("T") + +def identity(xs: list[T]) -> list[T]: + return xs + +xs: list[int] = [] +cast(list[int], identity(xs)) +[out] +main:10: error: Redundant cast to "list[int]" + [case testRedundantCastWithIsinstance] # flags: --warn-redundant-casts from typing import cast, Union From c939dbdf0c207f333a582db220dd578fb682a57a Mon Sep 17 00:00:00 2001 From: Dendroculus Date: Sun, 2 Aug 2026 22:39:45 +0700 Subject: [PATCH 2/3] Fix redundant cast inference without changing cast diagnostics --- mypy/checkexpr.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index bd6127fd372a7..6b562ca001878 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4850,18 +4850,39 @@ def visit_enum_index_expr( def visit_cast_expr(self, expr: CastExpr) -> Type: """Type check a cast expression.""" source_type = self.accept( - expr.expr, type_context=None, allow_none_return=True, always_allow_any=True + expr.expr, + type_context=AnyType(TypeOfAny.special_form), + allow_none_return=True, + always_allow_any=True, ) target_type = expr.type options = self.chk.options + + redundant_source_type = source_type + + if options.warn_redundant_casts: + with self.msg.filter_errors() as local_errors: + with ( + self.chk.local_type_map, + self.chk.binder.frame_context(can_skip=False, discard=True), + ): + inferred_source_type = self.accept( + expr.expr, type_context=None, allow_none_return=True, always_allow_any=True + ) + + if not local_errors.has_new_errors(): + redundant_source_type = inferred_source_type + if ( options.warn_redundant_casts and not is_same_type(target_type, AnyType(TypeOfAny.special_form)) - and is_same_type(source_type, target_type) + and is_same_type(redundant_source_type, target_type) ): self.msg.redundant_cast(target_type, expr) + if options.disallow_any_unimported and has_any_from_unimported_type(target_type): self.msg.unimported_type_becomes_any("Target type of cast", target_type, expr) + check_for_explicit_any( target_type, self.chk.options, self.chk.is_typeshed_stub, self.msg, context=expr ) From e138c14930b28c89c7a934080672a0ce9daa1dd5 Mon Sep 17 00:00:00 2001 From: Dendroculus Date: Mon, 3 Aug 2026 09:03:09 +0700 Subject: [PATCH 3/3] Preserve type context for redundant cast checks --- mypy/checkexpr.py | 7 ++++++- test-data/unit/check-warnings.test | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 6b562ca001878..70f9943ec3ea8 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4861,13 +4861,18 @@ def visit_cast_expr(self, expr: CastExpr) -> Type: redundant_source_type = source_type if options.warn_redundant_casts: + cast_context = self.type_context[-1] + with self.msg.filter_errors() as local_errors: with ( self.chk.local_type_map, self.chk.binder.frame_context(can_skip=False, discard=True), ): inferred_source_type = self.accept( - expr.expr, type_context=None, allow_none_return=True, always_allow_any=True + expr.expr, + type_context=cast_context, + allow_none_return=True, + always_allow_any=True, ) if not local_errors.has_new_errors(): diff --git a/test-data/unit/check-warnings.test b/test-data/unit/check-warnings.test index 641072c6c5311..bb0e966d8dbaa 100644 --- a/test-data/unit/check-warnings.test +++ b/test-data/unit/check-warnings.test @@ -21,8 +21,8 @@ T = TypeVar("T") def identity(xs: list[T]) -> list[T]: return xs -xs: list[int] = [] -cast(list[int], identity(xs)) +def f(xs: list[int]) -> list[int]: + return cast(list[int], identity(xs)) [out] main:10: error: Redundant cast to "list[int]"