@@ -19,10 +19,6 @@ FINAL_A: Final[int] = 1
1919FINAL_B : Annotated[Final[int ], " the annotation for FINAL_B" ] = 1
2020FINAL_C : Final[Annotated[int , " the annotation for FINAL_C" ]] = 1
2121FINAL_D : " Final[int]" = 1
22- # Note: Some type checkers do not support a separate declaration and
23- # assignment for `Final` symbols, but it's possible to support this in
24- # ty, and is useful for code that declares symbols `Final` inside
25- # `if TYPE_CHECKING` blocks.
2622FINAL_F : Final[int ]
2723FINAL_F = 1
2824
@@ -52,7 +48,7 @@ reveal_type(FINAL_D) # revealed: int
5248reveal_type(FINAL_F ) # revealed: int
5349```
5450
55- ### ` Final ` without a type
51+ ### Bare ` Final ` without a type
5652
5753When a symbol is qualified with ` Final ` but no type is specified, the type is inferred from the
5854right-hand side of the assignment. We do not union the inferred type with ` Unknown ` , because the
@@ -231,7 +227,86 @@ FINAL_LIST: Final[list[int]] = [1, 2, 3]
231227FINAL_LIST [0 ] = 4
232228```
233229
234- ## Too many arguments
230+ ## Overriding in subclasses
231+
232+ When a symbol is qualified with ` Final ` in a class, it cannot be overridden in subclasses.
233+
234+ ``` py
235+ from typing import Final
236+
237+ class Base :
238+ FINAL_A : Final[int ] = 1
239+ FINAL_B : Final[int ] = 1
240+ FINAL_C : Final = 1
241+
242+ class Derived (Base ):
243+ # TODO : This should be an error
244+ FINAL_A = 2
245+ # TODO : This should be an error
246+ FINAL_B : Final[int ] = 2
247+ # TODO : This should be an error
248+ FINAL_C = 2
249+ ```
250+
251+ ## Syntax and usage
252+
253+ ### Legal syntactical positions
254+
255+ Final may only be used in assignments or variable annotations. Using it in any other position is an
256+ error.
257+
258+ ``` py
259+ from typing import Final, ClassVar, Annotated
260+
261+ LEGAL_A : Final[int ] = 1
262+ LEGAL_B : Final = 1
263+ LEGAL_C : Final[int ]
264+ LEGAL_C = 1
265+ LEGAL_D : Final
266+ LEGAL_D = 1
267+
268+ class C :
269+ LEGAL_E : ClassVar[Final[int ]] = 1
270+ LEGAL_F : Final[ClassVar[int ]] = 1
271+ LEGAL_G : Annotated[Final[ClassVar[int ]], " metadata" ] = 1
272+
273+ def __init__ (self ):
274+ self .LEGAL_H : Final[int ] = 1
275+ self .LEGAL_I : Final[int ]
276+ self .LEGAL_I = 1
277+
278+ # TODO : This should be an error
279+ def f (ILLEGAL : Final[int ]) -> None :
280+ pass
281+ ```
282+
283+ ### Attribute assignment outside ` __init__ `
284+
285+ Qualifying an instance attribute with ` Final ` outside of ` __init__ ` is not allowed. The instance
286+ attribute must be assigned only once, when the instance is created.
287+
288+ ``` py
289+ from typing import Final
290+
291+ class C :
292+ def some_method (self ):
293+ # TODO : This should be an error
294+ self .x: Final[int ] = 1
295+ ```
296+
297+ ### ` Final ` in loops
298+
299+ Using ` Final ` in a loop is not allowed.
300+
301+ ``` py
302+ from typing import Final
303+
304+ for i in range (10 ):
305+ # TODO : This should be an error
306+ i: Final[int ] = 1
307+ ```
308+
309+ ### Too many arguments
235310
236311``` py
237312from typing import Final
@@ -241,39 +316,58 @@ class C:
241316 x: Final[int , str ] = 1
242317```
243318
244- ## Illegal ` Final ` in type expression
319+ ### Illegal ` Final ` in type expression
245320
246321``` py
247322from typing import Final
248323
324+ # error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in type expressions (only in annotation expressions)"
325+ x: list[Final[int ]] = [] # Error!
326+
249327class C :
250- # error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in type expressions (only in annotation expressions)"
328+ # error: [invalid-type-form]
251329 x: Final | int
252330
253- # error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in type expressions (only in annotation expressions)"
331+ # error: [invalid-type-form]
254332 y: int | Final[str ]
255333```
256334
257335## No assignment
258336
337+ Some type checkers do not support a separate declaration and assignment for ` Final ` symbols, but
338+ it's possible to support this in ty, and is useful for code that declares symbols ` Final ` inside
339+ ` if TYPE_CHECKING ` blocks.
340+
341+ ### Basic
342+
259343``` py
260344from typing import Final
261345
262346DECLARED_THEN_BOUND : Final[int ]
263347DECLARED_THEN_BOUND = 1
264348```
265349
266- ## No assignment for bare ` Final `
350+ ### No assignment
267351
268352``` py
269353from typing import Final
270354
271355# TODO : This should be an error
272- NO_RHS : Final
356+ NO_ASSIGNMENT_A : Final
357+ # TODO : This should be an error
358+ NO_ASSIGNMENT_B : Final[int ]
273359
274360class C :
275361 # TODO : This should be an error
276- NO_RHS : Final
362+ NO_ASSIGNMENT_A : Final
363+ # TODO : This should be an error
364+ NO_ASSIGNMENT_B : Final[int ]
365+
366+ # This is okay. `DEFINED_IN_INIT` is defined in `__init__`.
367+ DEFINED_IN_INIT : Final[int ]
368+
369+ def __init__ (self ):
370+ self .DEFINED_IN_INIT = 1
277371```
278372
279373## Full diagnostics
0 commit comments