From f545d5a7ee153bb47f2e9b857ddc2e8e3c888f17 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 647116706d324..e6185e54a8d52 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4866,10 +4866,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 2e87ec70bb4fdb8e71857f169ca2fc0f15c1b00e 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 e6185e54a8d52..2623d50925406 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4866,18 +4866,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 ed8dc4e9407a1f19d10ad901e7f955d76b07c507 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 2623d50925406..b54c38150c83e 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4877,13 +4877,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]"