From 55fb9a67800654c7e40f7faffe3b071c9acfff21 Mon Sep 17 00:00:00 2001 From: Christoph Tyralla Date: Fri, 10 Oct 2025 23:36:07 +0200 Subject: [PATCH 1/2] Prevent false unreachable warnings for @final instances that occur when strict optional checking is disabled. --- mypy/typeops.py | 2 +- test-data/unit/check-inference.test | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/mypy/typeops.py b/mypy/typeops.py index d058bb8201d3..fa7081b4a9ad 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -789,7 +789,7 @@ def false_only(t: Type) -> ProperType: if not ret_type.can_be_false: return UninhabitedType(line=t.line) elif isinstance(t, Instance): - if t.type.is_final or t.type.is_enum: + if (t.type.is_final or t.type.is_enum) and state.strict_optional: return UninhabitedType(line=t.line) elif isinstance(t, LiteralType) and t.is_enum_literal(): return UninhabitedType(line=t.line) diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 63278d6c4547..0551ea90add3 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1964,6 +1964,18 @@ if 'x' in d: # E: "None" has no attribute "__iter__" (not iterable) reveal_type(d) # N: Revealed type is "None" [builtins fixtures/dict.pyi] +[case testNoWrongUnreachableWarningWithNoStrictOptionalAndFinalInstance] +# flags: --no-strict-optional --warn-unreachable +from typing import final, Optional + +@final +class C: ... + +x: Optional[C] +if not x: + x = C() +[builtins fixtures/dict.pyi] + [case testInferFromEmptyListWhenUsingInWithStrictEquality] # flags: --strict-equality def f() -> None: From 13af01bc3ca4d34d98fca9b77c9f94976c8700aa Mon Sep 17 00:00:00 2001 From: Christoph Tyralla Date: Sat, 11 Oct 2025 20:45:57 +0200 Subject: [PATCH 2/2] Do the same for enum literals. --- mypy/typeops.py | 2 +- test-data/unit/check-inference.test | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/mypy/typeops.py b/mypy/typeops.py index fa7081b4a9ad..341c96c08931 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -791,7 +791,7 @@ def false_only(t: Type) -> ProperType: elif isinstance(t, Instance): if (t.type.is_final or t.type.is_enum) and state.strict_optional: return UninhabitedType(line=t.line) - elif isinstance(t, LiteralType) and t.is_enum_literal(): + elif isinstance(t, LiteralType) and t.is_enum_literal() and state.strict_optional: return UninhabitedType(line=t.line) new_t = copy_type(t) diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 0551ea90add3..24ea61f2c715 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1976,6 +1976,19 @@ if not x: x = C() [builtins fixtures/dict.pyi] +[case testNoWrongUnreachableWarningWithNoStrictOptionalAndEnumLiteral] +# flags: --no-strict-optional --warn-unreachable +from enum import Enum +from typing import Literal, Optional + +class E(Enum): + a = 1 + +x: Optional[Literal[E.a]] +if not x: + x = E.a +[builtins fixtures/dict.pyi] + [case testInferFromEmptyListWhenUsingInWithStrictEquality] # flags: --strict-equality def f() -> None: