mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-30 23:27:27 +00:00
[ty] Infer list[T]
when unpacking non-tuple type (#18438)
## Summary Follow-up from #18401, I was looking at whether that would fix the issue at https://github.com/astral-sh/ty/issues/247#issuecomment-2917656676 and it didn't, which made me realize that the PR only inferred `list[T]` when the value type was tuple but it could be other types as well. This PR fixes the actual issue by inferring `list[T]` for the non-tuple type case. ## Test Plan Add test cases for starred expression involved with non-tuple type. I also added a few test cases for list type and list literal. I also verified that the example in the linked issue comment works: ```py def _(line: str): a, b, *c = line.split(maxsplit=2) c.pop() ```
This commit is contained in:
parent
0986edf427
commit
8d98c601d8
2 changed files with 75 additions and 5 deletions
|
@ -1,8 +1,8 @@
|
|||
# Unpacking
|
||||
|
||||
If there are not enough or too many values when unpacking, an error will occur and the types of
|
||||
all variables (if nested tuple unpacking fails, only the variables within the failed tuples) is
|
||||
inferred to be `Unknown`.
|
||||
If there are not enough or too many values when unpacking, an error will occur and the types of all
|
||||
variables (if nested tuple unpacking fails, only the variables within the failed tuples) is inferred
|
||||
to be `Unknown`.
|
||||
|
||||
## Tuple
|
||||
|
||||
|
@ -207,6 +207,57 @@ reveal_type(c) # revealed: int
|
|||
reveal_type(d) # revealed: Literal[2]
|
||||
```
|
||||
|
||||
## List
|
||||
|
||||
### Literal unpacking
|
||||
|
||||
```py
|
||||
a, b = [1, 2]
|
||||
# TODO: should be `int` for both `a` and `b`
|
||||
reveal_type(a) # revealed: Unknown
|
||||
reveal_type(b) # revealed: Unknown
|
||||
```
|
||||
|
||||
### Simple unpacking
|
||||
|
||||
```py
|
||||
def _(value: list[int]):
|
||||
a, b = value
|
||||
reveal_type(a) # revealed: int
|
||||
reveal_type(b) # revealed: int
|
||||
```
|
||||
|
||||
### Nested unpacking
|
||||
|
||||
```py
|
||||
def _(value: list[list[int]]):
|
||||
a, (b, c) = value
|
||||
reveal_type(a) # revealed: list[int]
|
||||
reveal_type(b) # revealed: int
|
||||
reveal_type(c) # revealed: int
|
||||
```
|
||||
|
||||
### Invalid nested unpacking
|
||||
|
||||
```py
|
||||
def _(value: list[int]):
|
||||
# error: [not-iterable] "Object of type `int` is not iterable"
|
||||
a, (b, c) = value
|
||||
reveal_type(a) # revealed: int
|
||||
reveal_type(b) # revealed: Unknown
|
||||
reveal_type(c) # revealed: Unknown
|
||||
```
|
||||
|
||||
### Starred expression
|
||||
|
||||
```py
|
||||
def _(value: list[int]):
|
||||
a, *b, c = value
|
||||
reveal_type(a) # revealed: int
|
||||
reveal_type(b) # revealed: list[int]
|
||||
reveal_type(c) # revealed: int
|
||||
```
|
||||
|
||||
## String
|
||||
|
||||
### Simple unpacking
|
||||
|
@ -293,6 +344,18 @@ reveal_type(b) # revealed: LiteralString
|
|||
reveal_type(c) # revealed: list[LiteralString]
|
||||
```
|
||||
|
||||
### Starred expression (6)
|
||||
|
||||
```py
|
||||
from typing_extensions import LiteralString
|
||||
|
||||
def _(s: LiteralString):
|
||||
a, b, *c = s
|
||||
reveal_type(a) # revealed: LiteralString
|
||||
reveal_type(b) # revealed: LiteralString
|
||||
reveal_type(c) # revealed: list[LiteralString]
|
||||
```
|
||||
|
||||
### Unicode
|
||||
|
||||
```py
|
||||
|
|
|
@ -192,8 +192,15 @@ impl<'db> Unpacker<'db> {
|
|||
err.fallback_element_type(self.db())
|
||||
})
|
||||
};
|
||||
for target_type in &mut target_types {
|
||||
target_type.push(ty);
|
||||
// Both `elts` and `target_types` are guaranteed to have the same length.
|
||||
for (element, target_type) in elts.iter().zip(&mut target_types) {
|
||||
if element.is_starred_expr() {
|
||||
target_type.push(
|
||||
KnownClass::List.to_specialized_instance(self.db(), [ty]),
|
||||
);
|
||||
} else {
|
||||
target_type.push(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue