Skip to content

Commit ef75f0a

Browse files
committed
prevent incorrect specializations in SpecializationBuilder::infer
1 parent 9622841 commit ef75f0a

File tree

4 files changed

+27
-1
lines changed

4 files changed

+27
-1
lines changed

crates/ty_python_semantic/resources/mdtest/bidirectional.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Bidirectional Type Inference
1+
# Bidirectional type inference
22

33
ty partially supports bidirectional type inference. This is a mechanism for inferring the type of an
44
expression "from the outside in". Normally, type inference proceeds "from the inside out". That is,
@@ -46,6 +46,13 @@ def _(l: list[int] | None = None):
4646
l2: list[int] = l or list()
4747
# TODO: should be `list[int]`
4848
reveal_type(l2) # revealed: (list[int] & ~AlwaysFalsy) | list[Unknown]
49+
50+
def f[T](x: T, cond: bool) -> T | list[T]:
51+
return x if cond else [x]
52+
53+
# TODO: no error
54+
# error: [invalid-assignment] "Object of type `Literal[1] | list[Literal[1]]` is not assignable to `int | list[int]`"
55+
l5: int | list[int] = f(1, True)
4956
```
5057

5158
```py
@@ -123,4 +130,10 @@ reveal_type(f("a")) # revealed: list[str]
123130

124131
async def g() -> list[int]:
125132
return list1(1)
133+
134+
def h[T](x: T, cond: bool) -> T | list[T]:
135+
return i(x, cond)
136+
137+
def i[T](x: T, cond: bool) -> T | list[T]:
138+
return x if cond else [x]
126139
```

crates/ty_python_semantic/resources/mdtest/generics/legacy/functions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,10 @@ def union_param(x: T | None) -> T:
323323
reveal_type(union_param("a")) # revealed: Literal["a"]
324324
reveal_type(union_param(1)) # revealed: Literal[1]
325325
reveal_type(union_param(None)) # revealed: Unknown
326+
327+
def _(x: int | None):
328+
# TODO: should be `int`
329+
reveal_type(union_param(x)) # revealed: Unknown
326330
```
327331

328332
```py

crates/ty_python_semantic/resources/mdtest/generics/pep695/functions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ def union_param[T](x: T | None) -> T:
286286
reveal_type(union_param("a")) # revealed: Literal["a"]
287287
reveal_type(union_param(1)) # revealed: Literal[1]
288288
reveal_type(union_param(None)) # revealed: Unknown
289+
290+
def _(x: int | None):
291+
# TODO: should be `int`
292+
reveal_type(union_param(x)) # revealed: Unknown
289293
```
290294

291295
```py

crates/ty_python_semantic/src/types/generics.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,11 @@ impl<'db> SpecializationBuilder<'db> {
10881088
}
10891089

10901090
match (formal, actual) {
1091+
(Type::Union(_), Type::Union(_)) => {
1092+
// TODO: We need to infer specializations appropriately.
1093+
// e.g.
1094+
// `formal: list[T] | T | U, actual: V | int | list[V]` => `T = V, U = int`
1095+
}
10911096
(Type::Union(formal), _) => {
10921097
// TODO: We haven't implemented a full unification solver yet. If typevars appear
10931098
// in multiple union elements, we ideally want to express that _only one_ of them

0 commit comments

Comments
 (0)