Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
69 changes: 66 additions & 3 deletions crates/ty_python_semantic/resources/mdtest/unpacking.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
11 changes: 9 additions & 2 deletions crates/ty_python_semantic/src/types/unpacker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
}
Expand Down
Loading