Skip to content

Commit 7d591b2

Browse files
committed
[ty] Use inferred type for Final symbols
1 parent 3be83d3 commit 7d591b2

File tree

2 files changed

+49
-16
lines changed

2 files changed

+49
-16
lines changed

crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,68 @@
33
[`typing.Final`] is a type qualifier that is used to indicate that a symbol may not be reassigned in
44
any scope. Final names declared in class scopes cannot be overridden in subclasses.
55

6-
## Basic
6+
## Basic type inference
77

88
`mod.py`:
99

1010
```py
1111
from typing import Final, Annotated
1212

13-
FINAL_A: int = 1
13+
FINAL_A: Final[int] = 1
1414
FINAL_B: Annotated[Final[int], "the annotation for FINAL_B"] = 1
1515
FINAL_C: Final[Annotated[int, "the annotation for FINAL_C"]] = 1
1616
FINAL_D: Final = 1
1717
FINAL_E: "Final[int]" = 1
18+
FINAL_F: Final[int]
19+
FINAL_F = 1
1820

1921
reveal_type(FINAL_A) # revealed: Literal[1]
2022
reveal_type(FINAL_B) # revealed: Literal[1]
2123
reveal_type(FINAL_C) # revealed: Literal[1]
2224
reveal_type(FINAL_D) # revealed: Literal[1]
2325
reveal_type(FINAL_E) # revealed: Literal[1]
2426

25-
# TODO: All of these should be errors:
27+
def nonlocal_uses():
28+
reveal_type(FINAL_A) # revealed: Literal[1]
29+
reveal_type(FINAL_B) # revealed: Literal[1]
30+
reveal_type(FINAL_C) # revealed: Literal[1]
31+
reveal_type(FINAL_D) # revealed: Literal[1]
32+
reveal_type(FINAL_E) # revealed: Literal[1]
33+
```
34+
35+
Imported types:
36+
37+
```py
38+
from mod import FINAL_A, FINAL_B, FINAL_C, FINAL_D, FINAL_E, FINAL_F
39+
40+
reveal_type(FINAL_A) # revealed: Literal[1]
41+
reveal_type(FINAL_B) # revealed: Literal[1]
42+
reveal_type(FINAL_C) # revealed: Literal[1]
43+
reveal_type(FINAL_D) # revealed: Literal[1]
44+
reveal_type(FINAL_E) # revealed: Literal[1]
45+
reveal_type(FINAL_F) # revealed: Literal[1]
46+
```
47+
48+
## Not modifiable
49+
50+
```py
51+
from typing import Final, Annotated
52+
53+
FINAL_A: Final[int] = 1
54+
FINAL_B: Annotated[Final[int], "the annotation for FINAL_B"] = 1
55+
FINAL_C: Final[Annotated[int, "the annotation for FINAL_C"]] = 1
56+
FINAL_D: Final = 1
57+
FINAL_E: "Final[int]" = 1
58+
FINAL_F: Final[int]
59+
FINAL_F = 1
60+
61+
# TODO: all of these should be errors
2662
FINAL_A = 2
2763
FINAL_B = 2
2864
FINAL_C = 2
2965
FINAL_D = 2
3066
FINAL_E = 2
31-
```
32-
33-
Public types:
34-
35-
```py
36-
from mod import FINAL_A, FINAL_B, FINAL_C, FINAL_D, FINAL_E
37-
38-
# TODO: All of these should be Literal[1]
39-
reveal_type(FINAL_A) # revealed: int
40-
reveal_type(FINAL_B) # revealed: int
41-
reveal_type(FINAL_C) # revealed: int
42-
reveal_type(FINAL_D) # revealed: Unknown
43-
reveal_type(FINAL_E) # revealed: int
67+
FINAL_F = 2
4468
```
4569

4670
## Too many arguments

crates/ty_python_semantic/src/place.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,15 @@ fn place_by_id<'db>(
645645
ConsideredDefinitions::AllReachable => use_def.all_reachable_bindings(place_id),
646646
};
647647

648+
match declared {
649+
Ok(declared) if declared.qualifiers.contains(TypeQualifiers::FINAL) => {
650+
let bindings = all_considered_bindings();
651+
return place_from_bindings_impl(db, bindings, requires_explicit_reexport)
652+
.with_qualifiers(declared.qualifiers);
653+
}
654+
_ => {}
655+
}
656+
648657
match declared {
649658
// Place is declared, trust the declared type
650659
Ok(

0 commit comments

Comments
 (0)