-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[red-knot] function parameter types (#14802)
## Summary Inferred and declared types for function parameters, in the function body scope. Fixes #13693. ## Test Plan Added mdtests. --------- Co-authored-by: Micha Reiser <[email protected]> Co-authored-by: Alex Waygood <[email protected]>
- Loading branch information
1 parent
2119dca
commit 3017b3b
Showing
7 changed files
with
340 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
crates/red_knot_python_semantic/resources/mdtest/function/parameters.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# Function parameter types | ||
|
||
Within a function scope, the declared type of each parameter is its annotated type (or Unknown if | ||
not annotated). The initial inferred type is the union of the declared type with the type of the | ||
default value expression (if any). If both are fully static types, this union should simplify to the | ||
annotated type (since the default value type must be assignable to the annotated type, and for fully | ||
static types this means subtype-of, which simplifies in unions). But if the annotated type is | ||
Unknown or another non-fully-static type, the default value type may still be relevant as lower | ||
bound. | ||
|
||
The variadic parameter is a variadic tuple of its annotated type; the variadic-keywords parameter is | ||
a dictionary from strings to its annotated type. | ||
|
||
## Parameter kinds | ||
|
||
```py | ||
from typing import Literal | ||
|
||
def f(a, b: int, c=1, d: int = 2, /, e=3, f: Literal[4] = 4, *args: object, g=5, h: Literal[6] = 6, **kwargs: str): | ||
reveal_type(a) # revealed: Unknown | ||
reveal_type(b) # revealed: int | ||
reveal_type(c) # revealed: Unknown | Literal[1] | ||
reveal_type(d) # revealed: int | ||
reveal_type(e) # revealed: Unknown | Literal[3] | ||
reveal_type(f) # revealed: Literal[4] | ||
reveal_type(g) # revealed: Unknown | Literal[5] | ||
reveal_type(h) # revealed: Literal[6] | ||
|
||
# TODO: should be `tuple[object, ...]` (needs generics) | ||
reveal_type(args) # revealed: tuple | ||
|
||
# TODO: should be `dict[str, str]` (needs generics) | ||
reveal_type(kwargs) # revealed: dict | ||
``` | ||
|
||
## Unannotated variadic parameters | ||
|
||
...are inferred as tuple of Unknown or dict from string to Unknown. | ||
|
||
```py | ||
def g(*args, **kwargs): | ||
# TODO: should be `tuple[Unknown, ...]` (needs generics) | ||
reveal_type(args) # revealed: tuple | ||
|
||
# TODO: should be `dict[str, Unknown]` (needs generics) | ||
reveal_type(kwargs) # revealed: dict | ||
``` | ||
|
||
## Annotation is present but not a fully static type | ||
|
||
The default value type should be a lower bound on the inferred type. | ||
|
||
```py | ||
from typing import Any | ||
|
||
def f(x: Any = 1): | ||
reveal_type(x) # revealed: Any | Literal[1] | ||
``` | ||
|
||
## Default value type must be assignable to annotated type | ||
|
||
The default value type must be assignable to the annotated type. If not, we emit a diagnostic, and | ||
fall back to inferring the annotated type, ignoring the default value type. | ||
|
||
```py | ||
# error: [invalid-parameter-default] | ||
def f(x: int = "foo"): | ||
reveal_type(x) # revealed: int | ||
|
||
# The check is assignable-to, not subtype-of, so this is fine: | ||
from typing import Any | ||
|
||
def g(x: Any = "foo"): | ||
reveal_type(x) # revealed: Any | Literal["foo"] | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.