Skip to content

Commit bdf83fd

Browse files
committed
[ty] Infer list[T] when unpacking non-literal list
1 parent 2289187 commit bdf83fd

File tree

2 files changed

+75
-5
lines changed

2 files changed

+75
-5
lines changed

crates/ty_python_semantic/resources/mdtest/unpacking.md

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Unpacking
22

3-
If there are not enough or too many values ​​when unpacking, an error will occur and the types of
4-
all variables (if nested tuple unpacking fails, only the variables within the failed tuples) is
5-
inferred to be `Unknown`.
3+
If there are not enough or too many values when unpacking, an error will occur and the types of all
4+
variables (if nested tuple unpacking fails, only the variables within the failed tuples) is inferred
5+
to be `Unknown`.
66

77
## Tuple
88

@@ -207,6 +207,57 @@ reveal_type(c) # revealed: int
207207
reveal_type(d) # revealed: Literal[2]
208208
```
209209

210+
## List
211+
212+
### Literal unpacking
213+
214+
```py
215+
a, b = [1, 2]
216+
# TODO: should be `int` for both `a` and `b`
217+
reveal_type(a) # revealed: Unknown
218+
reveal_type(b) # revealed: Unknown
219+
```
220+
221+
### Simple unpacking
222+
223+
```py
224+
def _(value: list[int]):
225+
a, b = value
226+
reveal_type(a) # revealed: int
227+
reveal_type(b) # revealed: int
228+
```
229+
230+
### Nested unpacking
231+
232+
```py
233+
def _(value: list[list[int]]):
234+
a, (b, c) = value
235+
reveal_type(a) # revealed: list[int]
236+
reveal_type(b) # revealed: int
237+
reveal_type(c) # revealed: int
238+
```
239+
240+
### Invalid nested unpacking
241+
242+
```py
243+
def _(value: list[int]):
244+
# error: [not-iterable] "Object of type `int` is not iterable"
245+
a, (b, c) = value
246+
reveal_type(a) # revealed: int
247+
reveal_type(b) # revealed: Unknown
248+
reveal_type(c) # revealed: Unknown
249+
```
250+
251+
### Starred expression
252+
253+
```py
254+
def _(value: list[int]):
255+
a, *b, c = value
256+
reveal_type(a) # revealed: int
257+
reveal_type(b) # revealed: list[int]
258+
reveal_type(c) # revealed: int
259+
```
260+
210261
## String
211262

212263
### Simple unpacking
@@ -293,6 +344,18 @@ reveal_type(b) # revealed: LiteralString
293344
reveal_type(c) # revealed: list[LiteralString]
294345
```
295346

347+
### Starred expression (6)
348+
349+
```py
350+
from typing_extensions import LiteralString
351+
352+
def _(s: LiteralString):
353+
a, b, *c = s
354+
reveal_type(a) # revealed: LiteralString
355+
reveal_type(b) # revealed: LiteralString
356+
reveal_type(c) # revealed: list[LiteralString]
357+
```
358+
296359
### Unicode
297360

298361
```py

crates/ty_python_semantic/src/types/unpacker.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,15 @@ impl<'db> Unpacker<'db> {
192192
err.fallback_element_type(self.db())
193193
})
194194
};
195-
for target_type in &mut target_types {
196-
target_type.push(ty);
195+
// Both `elts` and `target_types` are guaranteed to have the same length.
196+
for (element, target_type) in elts.iter().zip(&mut target_types) {
197+
if element.is_starred_expr() {
198+
target_type.push(
199+
KnownClass::List.to_specialized_instance(self.db(), [ty]),
200+
);
201+
} else {
202+
target_type.push(ty);
203+
}
197204
}
198205
}
199206
}

0 commit comments

Comments
 (0)