Skip to content
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
ac1cbe6
Create TypeVarInstance type for legacy typevars
dcreager Mar 6, 2025
d095520
TypeVars have ambiguous truthiness as long as they're dynamic
dcreager Mar 6, 2025
e41ff39
Fix test failures
dcreager Mar 20, 2025
29852ac
Expose __constraints__
dcreager Mar 20, 2025
090b183
Test empty constraints too
dcreager Mar 20, 2025
363fce6
Expose __bound__
dcreager Mar 20, 2025
157fb7e
Use NoDefault for default default
dcreager Mar 20, 2025
87f56ff
Expose __default__
dcreager Mar 20, 2025
40d392e
Fewer salsa queries
dcreager Mar 20, 2025
f8d0350
Treat TypeVar as Any for descriptor protocol
dcreager Mar 21, 2025
6284357
Merge branch 'main' into dcreager/legacy-typevar-instance
dcreager Apr 8, 2025
6338868
Fix most merge conflicts
dcreager Apr 8, 2025
1073f86
Thread containing assignment down through type inference
dcreager Apr 8, 2025
c5978a7
Remove some moot TypeVar → Any translations
dcreager Apr 8, 2025
57c1adf
Add back extra TypeVar properties
dcreager Apr 8, 2025
fd91822
Merge branch 'main' into dcreager/legacy-typevar-instance
dcreager Apr 18, 2025
d735666
Fix merge conflicts
dcreager Apr 18, 2025
92fe5d6
Skip call constructor logic for TypeVar
dcreager Apr 18, 2025
dc78234
TODO: detect legacy typevars in function parameter list
dcreager Apr 18, 2025
c94cee9
Track whether typevar is legacy or PEP 695
dcreager Apr 18, 2025
f7e5a18
Merge branch 'main' into dcreager/legacy-typevar-instance
dcreager Apr 22, 2025
f2ed471
Handle generic constructors of generic classes
dcreager Apr 22, 2025
5631243
Merge branch 'dcreager/generic-constructor' into dcreager/legacy-type…
dcreager Apr 22, 2025
8cdde43
Find legacy typevars in function parameter lists
dcreager Apr 22, 2025
269a487
clippy
dcreager Apr 22, 2025
0bcbc1c
remove no longer accurate comment
dcreager Apr 22, 2025
2e87308
remove fwomp
dcreager Apr 22, 2025
70e3a84
Reveal the return type
dcreager Apr 22, 2025
71b1677
Add explanatory comment
dcreager Apr 22, 2025
8f0cabb
Fix custom `reveal_type` signatures
dcreager Apr 22, 2025
fbb6369
Revert custom `reveal_type` signatures
dcreager Apr 23, 2025
93feb23
Reveal argument type again
dcreager Apr 23, 2025
6976c81
We don't need this
dcreager Apr 23, 2025
d4b8c6f
Merge branch 'main' into dcreager/generic-constructor
dcreager Apr 23, 2025
8a34b11
Merge branch 'dcreager/generic-constructor' into dcreager/legacy-type…
dcreager Apr 23, 2025
bcea973
fix snapshot tests
dcreager Apr 23, 2025
bfac80b
Pull FunctionLiteral out into separate type
dcreager Apr 23, 2025
0a09a28
Merge branch 'dcreager/generic-constructor' into dcreager/legacy-type…
dcreager Apr 23, 2025
9e72367
clippy
dcreager Apr 23, 2025
345fff3
Clean this up a bit
dcreager Apr 23, 2025
43ce8d5
Revert FunctionLiteral type
dcreager Apr 23, 2025
7cce514
Merge remote-tracking branch 'origin/main' into dcreager/generic-cons…
dcreager Apr 23, 2025
899bc19
Merge branch 'dcreager/generic-constructor' into dcreager/legacy-type…
dcreager Apr 23, 2025
c9f2fc2
Merge branch 'main' into dcreager/legacy-typevar-instance
dcreager Apr 23, 2025
7218d0c
Fix tests
dcreager Apr 23, 2025
0f62237
Fix benchmarks
dcreager Apr 23, 2025
945b067
Clarify comment
dcreager Apr 23, 2025
7a1f1b6
Diagnostics for invalid legacy typevars
dcreager Apr 24, 2025
0d09595
Merge branch 'main' into dcreager/legacy-typevar-instance
dcreager Apr 24, 2025
8fd75e3
Update lints
dcreager Apr 24, 2025
2d07b0a
Track containing assignment in semantic index
dcreager Apr 25, 2025
a8132a3
Move legacy typevar stuff up to infer.rs
dcreager Apr 26, 2025
dae95a7
Revert "Thread containing assignment down through type inference"
dcreager Apr 26, 2025
230c69d
clippy
dcreager Apr 26, 2025
fb51439
Merge branch 'main' into dcreager/legacy-typevar-instance
dcreager Apr 26, 2025
a507a35
Add false positive test for annotated assignment
dcreager Apr 26, 2025
fdaa4c9
Merge branch 'main' into dcreager/legacy-typevar-instance
dcreager Apr 28, 2025
837489d
Update mdtest snapshots
dcreager Apr 28, 2025
8e78adc
Detect inferred args that don't satisfy bound/constraints
dcreager Apr 29, 2025
30f116f
Merge branch 'main' into dcreager/legacy-typevar-instance
dcreager Apr 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ from typing import TypeVar

T = TypeVar("T")

# TODO: `invalid-return-type` error should be emitted
# error: [invalid-return-type]
def m(x: T) -> T: ...
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ in newer Python releases.
from typing import TypeVar

T = TypeVar("T")
reveal_type(type(T)) # revealed: Literal[TypeVar]
reveal_type(T) # revealed: typing.TypeVar
reveal_type(T.__name__) # revealed: Literal["T"]
```

### Directly assigned to a variable
Expand All @@ -29,7 +32,7 @@ T = TypeVar("T")
```py
from typing import TypeVar

# TODO: error
# error: [invalid-legacy-type-variable] "A legacy `typing.TypeVar` must be immediately assigned to a variable"
TestList = list[TypeVar("W")]
```

Expand All @@ -40,7 +43,7 @@ TestList = list[TypeVar("W")]
```py
from typing import TypeVar

# TODO: error
# error: [invalid-legacy-type-variable] "The name of a legacy `typing.TypeVar` must match the name of the variable it is assigned to"
T = TypeVar("Q")
```

Expand All @@ -57,6 +60,52 @@ T = TypeVar("T")
T = TypeVar("T")
```

### Type variables with a default

Note that the `__default__` property is only available in Python ≥3.13.

```toml
[environment]
python-version = "3.13"
```

```py
from typing import TypeVar

T = TypeVar("T", default=int)
reveal_type(T.__default__) # revealed: int
reveal_type(T.__bound__) # revealed: None
reveal_type(T.__constraints__) # revealed: tuple[()]

S = TypeVar("S")
reveal_type(S.__default__) # revealed: NoDefault
```

### Type variables with an upper bound

```py
from typing import TypeVar

T = TypeVar("T", bound=int)
reveal_type(T.__bound__) # revealed: int
reveal_type(T.__constraints__) # revealed: tuple[()]

S = TypeVar("S")
reveal_type(S.__bound__) # revealed: None
```

### Type variables with constraints

```py
from typing import TypeVar

T = TypeVar("T", int, str)
reveal_type(T.__constraints__) # revealed: tuple[int, str]

S = TypeVar("S")
reveal_type(S.__constraints__) # revealed: tuple[()]
```

### Cannot have only one constraint

> `TypeVar` supports constraining parametric types to a fixed set of possible types...There should
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,51 @@ instances of `typing.TypeVar`, just like legacy type variables.
```py
def f[T]():
reveal_type(type(T)) # revealed: Literal[TypeVar]
reveal_type(T) # revealed: T
reveal_type(T) # revealed: typing.TypeVar
reveal_type(T.__name__) # revealed: Literal["T"]
```

### Type variables with a default

Note that the `__default__` property is only available in Python ≥3.13.

```toml
[environment]
python-version = "3.13"
```

```py
def f[T = int]():
reveal_type(T.__default__) # revealed: int
reveal_type(T.__bound__) # revealed: None
reveal_type(T.__constraints__) # revealed: tuple[()]

def g[S]():
reveal_type(S.__default__) # revealed: NoDefault
```

### Type variables with an upper bound

```py
def f[T: int]():
reveal_type(T.__bound__) # revealed: int
reveal_type(T.__constraints__) # revealed: tuple[()]

def g[S]():
reveal_type(S.__bound__) # revealed: None
```

### Type variables with constraints

```py
def f[T: (int, str)]():
reveal_type(T.__constraints__) # revealed: tuple[int, str]
reveal_type(T.__bound__) # revealed: None

def g[S]():
reveal_type(S.__constraints__) # revealed: tuple[()]
```

### Cannot have only one constraint

> `TypeVar` supports constraining parametric types to a fixed set of possible types...There should
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,7 @@ class Legacy(Generic[T]):
return y

legacy: Legacy[int] = Legacy()
# TODO: revealed: str
reveal_type(legacy.m(1, "string")) # revealed: @Todo(Support for `typing.TypeVar` instances in type expressions)
reveal_type(legacy.m(1, "string")) # revealed: Literal["string"]
```

With PEP 695 syntax, it is clearer that the method uses a separate typevar:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/function/return_ty
14 |
15 | T = TypeVar("T")
16 |
17 | # TODO: `invalid-return-type` error should be emitted
17 | # error: [invalid-return-type]
18 | def m(x: T) -> T: ...
```

Expand Down Expand Up @@ -79,3 +79,14 @@ error: lint:invalid-return-type: Return type does not match returned value
|

```

```
error: lint:invalid-return-type: Function can implicitly return `None`, which is not assignable to return type `T`
--> /src/mdtest_snippet.py:18:16
|
17 | # error: [invalid-return-type]
18 | def m(x: T) -> T: ...
| ^
|

```
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ x = [1, 2, 3]
reveal_type(x) # revealed: list

# TODO reveal int
reveal_type(x[0]) # revealed: @Todo(Support for `typing.TypeVar` instances in type expressions)
reveal_type(x[0]) # revealed: Unknown

# TODO reveal list
reveal_type(x[0:1]) # revealed: @Todo(specialized non-generic class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,8 @@ from functools import partial

def f(x: int, y: str) -> None: ...

# TODO: no error
# error: [invalid-assignment] "Object of type `partial` is not assignable to `(int, /) -> None`"
c1: Callable[[int], None] = partial(f, y="a")
```

Expand Down
Loading
Loading