diff --git a/docs/source/common_issues.rst b/docs/source/common_issues.rst index d3c1761bc994..57ae70dcfe53 100644 --- a/docs/source/common_issues.rst +++ b/docs/source/common_issues.rst @@ -786,6 +786,14 @@ False: If you use the :option:`--warn-unreachable ` flag, mypy will generate an error about each unreachable code block. +There are several cases that we always treat as reachable: + +- ``reveal_type`` and ``reveal_locals`` helper functions, because they are only useful for type checking and can be used for debugging +- ``assert False, 'unreahable'`` and similar constructs, because they can be used to guard places that should not be reached during runtime execution +- functions that return ``NoReturn``, like ``sys.exit`` that can also be used to guard things +- ``raise ...``, with the same reasoning as above +- ``pass`` and ``...``, because they do nothing + Narrowing and inner functions ----------------------------- diff --git a/mypy/checker.py b/mypy/checker.py index d94ab42c8479..ccb9d3550f69 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -26,7 +26,8 @@ ARG_POS, ARG_STAR, LITERAL_TYPE, LDEF, MDEF, GDEF, CONTRAVARIANT, COVARIANT, INVARIANT, TypeVarExpr, AssignmentExpr, is_final_node, - ARG_NAMED) + ARG_NAMED, RevealExpr, +) from mypy import nodes from mypy import operators from mypy.literals import literal, literal_hash, Key @@ -37,7 +38,8 @@ UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType, is_named_instance, union_items, TypeQuery, LiteralType, is_optional, remove_optional, TypeTranslator, StarType, get_proper_type, ProperType, - get_proper_types, is_literal_type, TypeAliasType, TypeGuardedType) + get_proper_types, is_literal_type, TypeAliasType, TypeGuardedType +) from mypy.sametypes import is_same_type from mypy.messages import ( MessageBuilder, make_inferred_type_note, append_invariance_notes, pretty_seq, @@ -306,10 +308,11 @@ def check_first_pass(self) -> None: self.errors.set_file(self.path, self.tree.fullname, scope=self.tscope) with self.tscope.module_scope(self.tree.fullname): with self.enter_partial_types(), self.binder.top_frame_context(): - for d in self.tree.defs: + for index, d in enumerate(self.tree.defs): if (self.binder.is_unreachable() and self.should_report_unreachable_issues() - and not self.is_raising_or_empty(d)): + and self.has_regular_unreachable_statements( + self.tree.defs, index)): self.msg.unreachable_statement(d) break self.accept(d) @@ -2017,9 +2020,10 @@ def visit_block(self, b: Block) -> None: # as unreachable -- so we don't display an error. self.binder.unreachable() return - for s in b.body: + for index, s in enumerate(b.body): if self.binder.is_unreachable(): - if self.should_report_unreachable_issues() and not self.is_raising_or_empty(s): + if (self.should_report_unreachable_issues() + and self.has_regular_unreachable_statements(b.body, index)): self.msg.unreachable_statement(s) break self.accept(s) @@ -2046,6 +2050,9 @@ def is_raising_or_empty(self, s: Statement) -> bool: if isinstance(s.expr, EllipsisExpr): return True elif isinstance(s.expr, CallExpr): + if isinstance(s.expr.analyzed, RevealExpr): + return True # `reveal_type` and `reveal_locals` are no-op + with self.expr_checker.msg.disable_errors(): typ = get_proper_type(self.expr_checker.accept( s.expr, allow_none_return=True, always_allow_any=True)) @@ -2054,6 +2061,18 @@ def is_raising_or_empty(self, s: Statement) -> bool: return True return False + def has_regular_unreachable_statements(self, block: Sequence[Statement], + index: int) -> bool: + """Helps to identify cases when our body has some regular unreachable statements. + + We call statements "regular" when they are not covered by our special rules + defined in `is_raising_or_empty` function. + """ + for ind in range(index, len(block)): + if not self.is_raising_or_empty(block[ind]): + return True + return False + def visit_assignment_stmt(self, s: AssignmentStmt) -> None: """Type check an assignment statement. diff --git a/test-data/unit/check-enum.test b/test-data/unit/check-enum.test index 22d167f3487b..537eddd4d611 100644 --- a/test-data/unit/check-enum.test +++ b/test-data/unit/check-enum.test @@ -1143,14 +1143,14 @@ reveal_type(y) # N: Revealed type is "__main__.Foo" # The standard output when we end up inferring two disjoint facts about the same expr if x is Foo.A and x is Foo.B: - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "__main__.Foo" reveal_type(x) # N: Revealed type is "__main__.Foo" # ..and we get the same result if we have two disjoint groups within the same comp expr if x is Foo.A < x is Foo.B: - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "__main__.Foo" reveal_type(x) # N: Revealed type is "__main__.Foo" @@ -1168,7 +1168,7 @@ class Foo(Enum): x: Foo if x is Foo.A is Foo.B: - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "__main__.Foo" reveal_type(x) # N: Revealed type is "__main__.Foo" @@ -1176,7 +1176,7 @@ reveal_type(x) # N: Revealed type is "__main__.Foo" literal_a: Literal[Foo.A] literal_b: Literal[Foo.B] if x is literal_a is literal_b: - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "__main__.Foo" reveal_type(x) # N: Revealed type is "__main__.Foo" @@ -1184,7 +1184,7 @@ reveal_type(x) # N: Revealed type is "__main__.Foo" final_a: Final = Foo.A final_b: Final = Foo.B if x is final_a is final_b: - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "__main__.Foo" reveal_type(x) # N: Revealed type is "__main__.Foo" diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index f531947d1faf..5e967dc56d9c 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -2336,16 +2336,16 @@ class C: class Example(A, B): pass # E: Definition of "f" in base class "A" is incompatible with definition in base class "B" x: A -if isinstance(x, B): # E: Subclass of "A" and "B" cannot exist: would have incompatible method signatures - reveal_type(x) # E: Statement is unreachable +if isinstance(x, B): # E: Subclass of "A" and "B" cannot exist: would have incompatible method signatures + x # E: Statement is unreachable else: - reveal_type(x) # N: Revealed type is "__main__.A" + reveal_type(x) # N: Revealed type is "__main__.A" y: C if isinstance(y, B): reveal_type(y) # N: Revealed type is "__main__." if isinstance(y, A): # E: Subclass of "C", "B", and "A" cannot exist: would have incompatible method signatures - reveal_type(y) # E: Statement is unreachable + y # E: Statement is unreachable [builtins fixtures/isinstance.pyi] [case testIsInstanceAdHocIntersectionReversed] @@ -2410,7 +2410,7 @@ class B: x: A[int] if isinstance(x, B): # E: Subclass of "A[int]" and "B" cannot exist: would have incompatible method signatures - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "__main__.A[builtins.int]" @@ -2580,7 +2580,7 @@ class B(Y, X): pass foo: A if isinstance(foo, B): # E: Subclass of "A" and "B" cannot exist: would have inconsistent method resolution order - reveal_type(foo) # E: Statement is unreachable + foo # E: Statement is unreachable [builtins fixtures/isinstance.pyi] [case testIsInstanceAdHocIntersectionAmbiguousClass] @@ -2614,7 +2614,7 @@ x: Type[A] if issubclass(x, B): reveal_type(x) # N: Revealed type is "Type[__main__.]" if issubclass(x, C): # E: Subclass of "A", "B", and "C" cannot exist: would have incompatible method signatures - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "Type[__main__.]" else: diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index 37ae12419151..cc3e71e72387 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -3298,7 +3298,7 @@ w: Union[Truth, AlsoTruth] if w: reveal_type(w) # N: Revealed type is "Union[__main__.Truth, __main__.AlsoTruth]" else: - reveal_type(w) # E: Statement is unreachable + w # E: Statement is unreachable [builtins fixtures/bool.pyi] diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index 6b030ae49a86..a45bd3ece602 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -267,7 +267,7 @@ else: reveal_type(x) # N: Revealed type is "Union[__main__.Object1, __main__.Object2]" if x.key is Key.D: - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "Union[__main__.Object1, __main__.Object2]" [builtins fixtures/tuple.pyi] @@ -294,7 +294,7 @@ else: reveal_type(x) # N: Revealed type is "Union[TypedDict('__main__.TypedDict1', {'key': Union[Literal['A'], Literal['C']]}), TypedDict('__main__.TypedDict2', {'key': Union[Literal['B'], Literal['C']]})]" if x['key'] == 'D': - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "Union[TypedDict('__main__.TypedDict1', {'key': Union[Literal['A'], Literal['C']]}), TypedDict('__main__.TypedDict2', {'key': Union[Literal['B'], Literal['C']]})]" [builtins fixtures/primitives.pyi] @@ -321,7 +321,7 @@ else: reveal_type(x) # N: Revealed type is "Union[TypedDict('__main__.TypedDict1', {'key'?: Union[Literal['A'], Literal['C']]}), TypedDict('__main__.TypedDict2', {'key'?: Union[Literal['B'], Literal['C']]})]" if x['key'] == 'D': - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "Union[TypedDict('__main__.TypedDict1', {'key'?: Union[Literal['A'], Literal['C']]}), TypedDict('__main__.TypedDict2', {'key'?: Union[Literal['B'], Literal['C']]})]" [builtins fixtures/primitives.pyi] @@ -612,8 +612,7 @@ else: y: Union[Parent1, Parent2] if y["model"]["key"] is Key.C: - reveal_type(y) # E: Statement is unreachable - reveal_type(y["model"]) + y # E: Statement is unreachable else: reveal_type(y) # N: Revealed type is "Union[TypedDict('__main__.Parent1', {'model': TypedDict('__main__.Model1', {'key': Literal[__main__.Key.A]}), 'foo': builtins.int}), TypedDict('__main__.Parent2', {'model': TypedDict('__main__.Model2', {'key': Literal[__main__.Key.B]}), 'bar': builtins.str})]" reveal_type(y["model"]) # N: Revealed type is "Union[TypedDict('__main__.Model1', {'key': Literal[__main__.Key.A]}), TypedDict('__main__.Model2', {'key': Literal[__main__.Key.B]})]" @@ -648,8 +647,7 @@ else: y: Union[Parent1, Parent2] if y["model"]["key"] == 'C': - reveal_type(y) # E: Statement is unreachable - reveal_type(y["model"]) + y # E: Statement is unreachable else: reveal_type(y) # N: Revealed type is "Union[TypedDict('__main__.Parent1', {'model': TypedDict('__main__.Model1', {'key': Literal['A']}), 'foo': builtins.int}), TypedDict('__main__.Parent2', {'model': TypedDict('__main__.Model2', {'key': Literal['B']}), 'bar': builtins.str})]" reveal_type(y["model"]) # N: Revealed type is "Union[TypedDict('__main__.Model1', {'key': Literal['A']}), TypedDict('__main__.Model2', {'key': Literal['B']})]" @@ -728,7 +726,7 @@ def test2(switch: FlipFlopEnum) -> None: switch.mutate() assert switch.state is State.B # E: Non-overlapping identity check (left operand type: "Literal[State.A]", right operand type: "Literal[State.B]") - reveal_type(switch.state) # E: Statement is unreachable + switch.state # E: Statement is unreachable def test3(switch: FlipFlopStr) -> None: # This is the same thing as 'test1', except we try using str literals. @@ -895,8 +893,7 @@ else: # No contamination here if 1 == x == z: # E: Non-overlapping equality check (left operand type: "Union[Literal[1], Literal[2], None]", right operand type: "Default") - reveal_type(x) # E: Statement is unreachable - reveal_type(z) + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "Union[Literal[1], Literal[2], None]" reveal_type(z) # N: Revealed type is "__main__.Default" @@ -912,7 +909,7 @@ b: Literal[1, 2] c: Literal[2, 3] if a == b == c: - reveal_type(a) # E: Statement is unreachable + a # E: Statement is unreachable reveal_type(b) reveal_type(c) else: @@ -923,7 +920,7 @@ else: if a == a == a: reveal_type(a) # N: Revealed type is "Literal[1]" else: - reveal_type(a) # E: Statement is unreachable + a # E: Statement is unreachable if a == a == b: reveal_type(a) # N: Revealed type is "Literal[1]" @@ -986,8 +983,8 @@ elif a == a == 4: else: # In contrast, this branch must be unreachable: we assume (maybe naively) # that 'a' won't be mutated in the middle of the expression. - reveal_type(a) # E: Statement is unreachable - reveal_type(b) + a # E: Statement is unreachable + b [builtins fixtures/primitives.pyi] [case testNarrowingLiteralTruthiness] diff --git a/test-data/unit/check-python38.test b/test-data/unit/check-python38.test index c7289593e810..c0ef31928e05 100644 --- a/test-data/unit/check-python38.test +++ b/test-data/unit/check-python38.test @@ -455,11 +455,11 @@ def check_partial_list() -> None: # flags: --warn-unreachable if (x := 0): - reveal_type(x) # E: Statement is unreachable + x # E: Statement is unreachable else: reveal_type(x) # N: Revealed type is "builtins.int" -reveal_type(x) # N: Revealed type is "builtins.int" +reveal_type(x) # N: Revealed type is "builtins.int" [case testWalrusAssignmentAndConditionScopeForProperty] # flags: --warn-unreachable @@ -479,14 +479,14 @@ if x := wrapper.f: else: reveal_type(x) # N: Revealed type is "builtins.str" -reveal_type(x) # N: Revealed type is "builtins.str" +reveal_type(x) # N: Revealed type is "builtins.str" if y := wrapper.always_false: - reveal_type(y) # E: Statement is unreachable + y # E: Statement is unreachable else: reveal_type(y) # N: Revealed type is "Literal[False]" -reveal_type(y) # N: Revealed type is "Literal[False]" +reveal_type(y) # N: Revealed type is "Literal[False]" [builtins fixtures/property.pyi] [case testWalrusAssignmentAndConditionScopeForFunction] @@ -501,21 +501,21 @@ if x := f(): else: reveal_type(x) # N: Revealed type is "builtins.str" -reveal_type(x) # N: Revealed type is "builtins.str" +reveal_type(x) # N: Revealed type is "builtins.str" def always_false() -> Literal[False]: ... if y := always_false(): - reveal_type(y) # E: Statement is unreachable + y # E: Statement is unreachable else: reveal_type(y) # N: Revealed type is "Literal[False]" -reveal_type(y) # N: Revealed type is "Literal[False]" +reveal_type(y) # N: Revealed type is "Literal[False]" def always_false_with_parameter(x: int) -> Literal[False]: ... if z := always_false_with_parameter(5): - reveal_type(z) # E: Statement is unreachable + z # E: Statement is unreachable else: reveal_type(z) # N: Revealed type is "Literal[False]" diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index 2a55db1a33c6..ae20e58fd20c 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -760,7 +760,7 @@ a: int if isinstance(a, int): reveal_type(a) # N: Revealed type is "builtins.int" else: - reveal_type(a) # E: Statement is unreachable + a = 1 # E: Statement is unreachable [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagWithBadControlFlow2] @@ -769,7 +769,7 @@ b: int while isinstance(b, int): reveal_type(b) # N: Revealed type is "builtins.int" else: - reveal_type(b) # E: Statement is unreachable + b = 1 # E: Statement is unreachable [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagWithBadControlFlow3] @@ -777,14 +777,14 @@ else: def foo(c: int) -> None: reveal_type(c) # N: Revealed type is "builtins.int" assert not isinstance(c, int) - reveal_type(c) # E: Statement is unreachable + c = 1 # E: Statement is unreachable [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagWithBadControlFlow4] # flags: --warn-unreachable d: int if False: - reveal_type(d) # E: Statement is unreachable + d = 1 # E: Statement is unreachable [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagWithBadControlFlow5] @@ -793,15 +793,14 @@ e: int if True: reveal_type(e) # N: Revealed type is "builtins.int" else: - reveal_type(e) # E: Statement is unreachable + e = 2 # E: Statement is unreachable [builtins fixtures/isinstancelist.pyi] [case testUnreachableFlagStatementAfterReturn] # flags: --warn-unreachable def foo(x: int) -> None: - reveal_type(x) # N: Revealed type is "builtins.int" return - reveal_type(x) # E: Statement is unreachable + x = 1 # E: Statement is unreachable [case testUnreachableFlagTryBlocks] # flags: --warn-unreachable @@ -810,24 +809,24 @@ def foo(x: int) -> int: try: reveal_type(x) # N: Revealed type is "builtins.int" return x - reveal_type(x) # E: Statement is unreachable + x = 1 # E: Statement is unreachable finally: reveal_type(x) # N: Revealed type is "builtins.int" if True: reveal_type(x) # N: Revealed type is "builtins.int" else: - reveal_type(x) # E: Statement is unreachable + x = 1 # E: Statement is unreachable def bar(x: int) -> int: try: if True: raise Exception() - reveal_type(x) # E: Statement is unreachable + x = 1 # E: Statement is unreachable except: reveal_type(x) # N: Revealed type is "builtins.int" return x else: - reveal_type(x) # E: Statement is unreachable + x = 1 # E: Statement is unreachable def baz(x: int) -> int: try: @@ -936,6 +935,116 @@ if False: reveal_type(x) [builtins fixtures/exception.pyi] +[case testUnreachableFlagOkWithDeadStatements2] +# flags: --warn-unreachable +from typing import NoReturn +def assert_never(x: NoReturn) -> NoReturn: + assert False + +def nonthrowing_assert_never(x: NoReturn) -> None: ... + +def expect_str(x: str) -> str: pass + +x: int +if False: + assert False + +if False: + raise Exception() + +if False: + assert_never(x) + +if False: + nonthrowing_assert_never(x) # E: Statement is unreachable + +if False: + # Ignore obvious type errors + assert_never(expect_str(x)) +[builtins fixtures/exception.pyi] + + +[case testUnreachableFlagOkWithDeadStatements3] +# flags: --warn-unreachable +from typing import NoReturn +def assert_never(x: NoReturn) -> NoReturn: + assert False + +def nonthrowing_assert_never(x: NoReturn) -> None: ... + +def expect_str(x: str) -> str: pass + +x: int +if False: + assert False # E: Statement is unreachable + expect_str('a') + +if False: + raise Exception() # E: Statement is unreachable + expect_str('a') + +if False: + assert_never(x) # E: Statement is unreachable + expect_str('a') + +if False: + nonthrowing_assert_never(x) # E: Statement is unreachable + expect_str('a') + +if False: + # Ignore obvious type errors + assert_never(expect_str(x)) # E: Statement is unreachable + expect_str('a') +[builtins fixtures/exception.pyi] + + +[case testSeveralUnreachableStatements] +# flags: --warn-unreachable +from typing import NoReturn +def check() -> None: ... +def never_return() -> NoReturn: ... + +def first() -> NoReturn: + never_return() + never_return() # E: Statement is unreachable + check() + +def second() -> NoReturn: + raise Exception + raise Exception # E: Statement is unreachable + raise Exception() + check() + +def third() -> NoReturn: + assert False + assert False # E: Statement is unreachable + assert False + assert False + check() +[builtins fixtures/exception.pyi] + +[case testSeveralUnreachableStatements2] +# flags: --warn-unreachable +from typing import NoReturn +def assert_never() -> NoReturn: + assert False + +def first() -> NoReturn: + assert_never() + assert_never() + +def second() -> NoReturn: + raise Exception + raise Exception + raise Exception() + +def third() -> NoReturn: + assert False + assert False + assert False + assert False +[builtins fixtures/exception.pyi] + [case testUnreachableFlagExpressions] # flags: --warn-unreachable def foo() -> bool: ... @@ -969,29 +1078,31 @@ class Case1: # flags: --warn-unreachable from typing import TypeVar, Generic +def check(obj: object) -> None: ... + T1 = TypeVar('T1', bound=int) T2 = TypeVar('T2', int, str) T3 = TypeVar('T3', None, str) def test1(x: T1) -> T1: if isinstance(x, int): - reveal_type(x) # N: Revealed type is "T1`-1" + check(x) else: - reveal_type(x) # E: Statement is unreachable + check(x) # E: Statement is unreachable return x def test2(x: T2) -> T2: if isinstance(x, int): - reveal_type(x) # N: Revealed type is "builtins.int*" + check(x) else: - reveal_type(x) # N: Revealed type is "builtins.str*" + check(x) if False: # This is unreachable, but we don't report an error, unfortunately. # The presence of the TypeVar with values unfortunately currently shuts # down type-checking for this entire function. # TODO: Find a way of removing this limitation - reveal_type(x) + check(x) return x @@ -1000,13 +1111,13 @@ class Test3(Generic[T2]): def func(self) -> None: if isinstance(self.x, int): - reveal_type(self.x) # N: Revealed type is "builtins.int*" + check(self.x) else: - reveal_type(self.x) # N: Revealed type is "builtins.str*" + check(self.x) if False: # Same issue as above - reveal_type(self.x) + check(self.x) class Test4(Generic[T3]): @@ -1344,6 +1455,7 @@ async def f_malformed_2() -> int: [case testUnreachableUntypedFunction] # flags: --warn-unreachable +def check(obj: object) -> None: ... def test_untyped_fn(obj): assert obj.prop is True @@ -1352,7 +1464,7 @@ def test_untyped_fn(obj): obj.reload() assert obj.prop is False - reveal_type(obj.prop) + check(obj.prop) def test_typed_fn(obj) -> None: assert obj.prop is True @@ -1361,10 +1473,11 @@ def test_typed_fn(obj) -> None: obj.reload() assert obj.prop is False - reveal_type(obj.prop) # E: Statement is unreachable + check(obj.prop) # E: Statement is unreachable [case testUnreachableCheckedUntypedFunction] # flags: --warn-unreachable --check-untyped-defs +def check(obj: object) -> None: ... def test_untyped_fn(obj): assert obj.prop is True @@ -1373,7 +1486,7 @@ def test_untyped_fn(obj): obj.reload() assert obj.prop is False - reveal_type(obj.prop) # E: Statement is unreachable + check(obj.prop) # E: Statement is unreachable [case testConditionalTypeVarException] # every part of this test case was necessary to trigger the crash @@ -1402,6 +1515,25 @@ def f() -> None: x = 1 # E: Statement is unreachable [builtins fixtures/dict.pyi] +[case testRevealExprAlwaysReachable] +# flags: --warn-unreachable + +# This should always report: + +def f() -> None: + if False: + x = 1 # E: Statement is unreachable + +# But, reveals are special: + +def g() -> None: + if False: + reveal_type(f) + +def h() -> None: + if False: + reveal_locals() + [case testUnreachableModuleBody1] # flags: --warn-unreachable from typing import NoReturn @@ -1416,3 +1548,10 @@ x = 1 # E: Statement is unreachable raise Exception x = 1 # E: Statement is unreachable [builtins fixtures/exception.pyi] + +[case testUnreachableModuleBody3] +# flags: --warn-unreachable +raise Exception +raise Exception # E: Statement is unreachable +x = 1 +[builtins fixtures/exception.pyi] diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 2fdbac433f14..fb0ce1d8d597 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1481,10 +1481,10 @@ _testUnreachableWithStdlibContextManagersNoStrictOptional.py:15: error: Statemen # mypy: warn-unreachable x: str if isinstance(x, bytes): - reveal_type(x) + x y: str if isinstance(x, int): - reveal_type(x) + x [out] _testIsInstanceAdHocIntersectionWithStrAndBytes.py:3: error: Subclass of "str" and "bytes" cannot exist: would have incompatible method signatures _testIsInstanceAdHocIntersectionWithStrAndBytes.py:4: error: Statement is unreachable