Skip to content

Commit e666217

Browse files
Preserve block unreachablility when checking function definitions with constrained TypeVars (#18217)
Fixes #18210 When checking function definitions with constrained type variables (i.e. type variables with value restrictions), mypy expands the function definition for each possible type variable value. However, blocks in the expanded function definitions have their `is_unreachable` reset to `False`, which leads to spurious errors in blocks that were marked as unreachable during semantic analysis. This PR preserves the value of `is_unreachable` on blocks in the expanded function definitions.
1 parent 9dad464 commit e666217

File tree

3 files changed

+13
-3
lines changed

3 files changed

+13
-3
lines changed

mypy/nodes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,15 +1263,15 @@ class Block(Statement):
12631263

12641264
__match_args__ = ("body", "is_unreachable")
12651265

1266-
def __init__(self, body: list[Statement]) -> None:
1266+
def __init__(self, body: list[Statement], *, is_unreachable: bool = False) -> None:
12671267
super().__init__()
12681268
self.body = body
12691269
# True if we can determine that this block is not executed during semantic
12701270
# analysis. For example, this applies to blocks that are protected by
12711271
# something like "if PY3:" when using Python 2. However, some code is
12721272
# only considered unreachable during type checking and this is not true
12731273
# in those cases.
1274-
self.is_unreachable = False
1274+
self.is_unreachable = is_unreachable
12751275

12761276
def accept(self, visitor: StatementVisitor[T]) -> T:
12771277
return visitor.visit_block(self)

mypy/treetransform.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ def visit_nonlocal_decl(self, node: NonlocalDecl) -> NonlocalDecl:
276276
return NonlocalDecl(node.names.copy())
277277

278278
def visit_block(self, node: Block) -> Block:
279-
return Block(self.statements(node.body))
279+
return Block(self.statements(node.body), is_unreachable=node.is_unreachable)
280280

281281
def visit_decorator(self, node: Decorator) -> Decorator:
282282
# Note that a Decorator must be transformed to a Decorator.

test-data/unit/check-unreachable-code.test

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,16 @@ class Test4(Generic[T3]):
10001000

10011001
[builtins fixtures/isinstancelist.pyi]
10021002

1003+
[case testUnreachableBlockStaysUnreachableWithTypeVarConstraints]
1004+
# flags: --always-false COMPILE_TIME_FALSE
1005+
from typing import TypeVar
1006+
COMPILE_TIME_FALSE = False
1007+
T = TypeVar("T", int, str)
1008+
def foo(x: T) -> T:
1009+
if COMPILE_TIME_FALSE:
1010+
return "bad"
1011+
return x
1012+
10031013
[case testUnreachableFlagContextManagersNoSuppress]
10041014
# flags: --warn-unreachable
10051015
from contextlib import contextmanager

0 commit comments

Comments
 (0)