Skip to content

Commit 59696d1

Browse files
committed
Admit that Final variables are never redefined
1 parent addcff2 commit 59696d1

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

mypy/checker.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,10 @@ def is_var_redefined_in_outer_context(self, v: Var, after_line: int) -> bool:
15571557
Note that this doesn't do a full CFG analysis but uses a line number based
15581558
heuristic that isn't correct in some (rare) cases.
15591559
"""
1560+
if v.is_final:
1561+
# Final vars are definitely never reassigned.
1562+
return False
1563+
15601564
outers = self.tscope.outer_functions()
15611565
if not outers:
15621566
# Top-level function -- outer context is top level, and we can't reason about

test-data/unit/check-final.test

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,3 +1250,30 @@ def check_final_init() -> None:
12501250
new_instance = FinalInit()
12511251
new_instance.__init__()
12521252
[builtins fixtures/tuple.pyi]
1253+
1254+
[case testNarrowingOfFinalPersistsInFunctions]
1255+
from typing import Final, Union
1256+
1257+
def _init() -> Union[int, None]:
1258+
return 0
1259+
1260+
FOO: Final = _init()
1261+
# For some reason the following isn't narrowed at all
1262+
# (always stays int | None):
1263+
# FOO: Final[Union[int, None]] = 0
1264+
1265+
class Example:
1266+
1267+
if FOO is not None:
1268+
reveal_type(FOO) # N: Revealed type is "builtins.int"
1269+
1270+
def fn(self) -> int:
1271+
return FOO
1272+
1273+
if FOO is not None:
1274+
reveal_type(FOO) # N: Revealed type is "builtins.int"
1275+
1276+
def func() -> int:
1277+
return FOO
1278+
1279+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)