From cda7cb1c7722b37dd2f727a4b107c6aafb637f20 Mon Sep 17 00:00:00 2001 From: Piyush Bhakuni Date: Fri, 26 Jun 2026 16:43:48 +0530 Subject: [PATCH 1/2] Suppress redundant-expr for validation guards that always terminate --- mypy/checker.py | 9 +++++++++ mypy/checkexpr.py | 1 + mypy/nodes.py | 4 ++++ test-data/unit/check-errorcodes.test | 23 +++++++++++++++++++++++ 4 files changed, 37 insertions(+) diff --git a/mypy/checker.py b/mypy/checker.py index 33705c98e10c3..1fff2e2a0e369 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5345,6 +5345,15 @@ def visit_if_stmt(self, s: IfStmt) -> None: # Fall-through to the original frame is handled explicitly in each block. with self.binder.frame_context(can_skip=False, conditional_frame=True, fall_through=0): for e, b in zip(s.expr, s.body): + # Suppress redundant-expr warnings for validation code + # that only terminates execution (raise,assert false, no return ,etc) + if ( + isinstance(e, OpExpr) + and e.op == "and" + and b.body + and all(self.is_noop_for_reachability(stmt) for stmt in b.body) + ): + e.suppress_redundant_expr = True t = get_proper_type(self.expr_checker.accept(e)) if isinstance(t, DeletedType): diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 44855f49afaf9..2af0c9027510e 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4446,6 +4446,7 @@ def check_boolean_op(self, e: OpExpr) -> Type: codes.REDUNDANT_EXPR in self.chk.options.enabled_error_codes and left_unreachable # don't report an error if it's intentional + and not e.suppress_redundant_expr and not e.right_always ): self.msg.redundant_left_operand(e.op, e.left) diff --git a/mypy/nodes.py b/mypy/nodes.py index e2ea348d2df11..a3ae182dc5cd1 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2662,6 +2662,7 @@ class OpExpr(Expression): "right_unreachable", "analyzed", "as_type", + "suppress_redundant_expr", ) __match_args__ = ("left", "op", "right") @@ -2675,6 +2676,8 @@ class OpExpr(Expression): right_always: bool # Per static analysis only: Is the right side unreachable? right_unreachable: bool + # Suppress redundant-expr warnings for this expression. + suppress_redundant_expr: bool # Used for expressions that represent a type "X | Y" in some contexts analyzed: TypeAliasExpr | None # If this value expression can also be parsed as a valid type expression, @@ -2693,6 +2696,7 @@ def __init__( self.right_always = False self.right_unreachable = False self.analyzed = analyzed + self.suppress_redundant_expr = False self.as_type = NotParsed.VALUE def accept(self, visitor: ExpressionVisitor[T]) -> T: diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 5296d813334e4..10e7194d6ccf2 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -964,6 +964,29 @@ for y in bad_list: [builtins fixtures/isinstancelist.pyi] [typing fixtures/typing-full.pyi] +[case testNoRedundantExprForTypeIsAndRaise] +# flags: --enable-error-code redundant-expr +from typing import TypeVar, Sequence, Any +from typing_extensions import TypeIs, Self + +class Cat: + def foo(self) -> Self: # type: ignore[empty-body] + ... + +MyType = TypeVar('MyType', int, str, Cat) +T = TypeVar('T') + +def _is_seq_of(seq: Sequence[Any], tp: type[T]) -> TypeIs[Sequence[T]]: # type: ignore[empty-body] + ... + +def main(a: Sequence[MyType]) -> MyType: + if not _is_seq_of(a, Cat) and not _is_seq_of(a, int): + assert False + return a[0] + +[typing fixtures/typing-full.pyi] +[builtins fixtures/tuple.pyi] + [case testNamedTupleNameMismatch] from typing import NamedTuple From 8310f1d54dd67cb144465561ac965f808f0571a1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 11:22:30 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/checker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index 1fff2e2a0e369..98bce9d504ad7 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5351,7 +5351,7 @@ def visit_if_stmt(self, s: IfStmt) -> None: isinstance(e, OpExpr) and e.op == "and" and b.body - and all(self.is_noop_for_reachability(stmt) for stmt in b.body) + and all(self.is_noop_for_reachability(stmt) for stmt in b.body) ): e.suppress_redundant_expr = True t = get_proper_type(self.expr_checker.accept(e))