Skip to content

Commit 0173738

Browse files
authored
[red-knot] Port comprehension tests to Markdown (#15688)
## Summary Port comprehension tests from Rust to Markdown I don' think the remaining tests in `infer.rs` should be ported to Markdown, maybe except for the incremental-checking tests when (if ever) we have support for that in the MD tests. closes #13696
1 parent 05ea77b commit 0173738

File tree

3 files changed

+192
-409
lines changed

3 files changed

+192
-409
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# Comprehensions
2+
3+
## Basic comprehensions
4+
5+
```py
6+
class IntIterator:
7+
def __next__(self) -> int:
8+
return 42
9+
10+
class IntIterable:
11+
def __iter__(self) -> IntIterator:
12+
return IntIterator()
13+
14+
# revealed: int
15+
[reveal_type(x) for x in IntIterable()]
16+
17+
class IteratorOfIterables:
18+
def __next__(self) -> IntIterable:
19+
return IntIterable()
20+
21+
class IterableOfIterables:
22+
def __iter__(self) -> IteratorOfIterables:
23+
return IteratorOfIterables()
24+
25+
# revealed: tuple[int, IntIterable]
26+
[reveal_type((x, y)) for y in IterableOfIterables() for x in y]
27+
28+
# revealed: int
29+
{reveal_type(x): 0 for x in IntIterable()}
30+
31+
# revealed: int
32+
{0: reveal_type(x) for x in IntIterable()}
33+
```
34+
35+
## Nested comprehension
36+
37+
```py
38+
class IntIterator:
39+
def __next__(self) -> int:
40+
return 42
41+
42+
class IntIterable:
43+
def __iter__(self) -> IntIterator:
44+
return IntIterator()
45+
46+
# revealed: tuple[int, int]
47+
[[reveal_type((x, y)) for x in IntIterable()] for y in IntIterable()]
48+
```
49+
50+
## Comprehension referencing outer comprehension
51+
52+
```py
53+
class IntIterator:
54+
def __next__(self) -> int:
55+
return 42
56+
57+
class IntIterable:
58+
def __iter__(self) -> IntIterator:
59+
return IntIterator()
60+
61+
class IteratorOfIterables:
62+
def __next__(self) -> IntIterable:
63+
return IntIterable()
64+
65+
class IterableOfIterables:
66+
def __iter__(self) -> IteratorOfIterables:
67+
return IteratorOfIterables()
68+
69+
# revealed: tuple[int, IntIterable]
70+
[[reveal_type((x, y)) for x in y] for y in IterableOfIterables()]
71+
```
72+
73+
## Comprehension with unbound iterable
74+
75+
Iterating over an unbound iterable yields `Unknown`:
76+
77+
```py
78+
# error: [unresolved-reference] "Name `x` used when not defined"
79+
# revealed: Unknown
80+
[reveal_type(z) for z in x]
81+
82+
class IntIterator:
83+
def __next__(self) -> int:
84+
return 42
85+
86+
class IntIterable:
87+
def __iter__(self) -> IntIterator:
88+
return IntIterator()
89+
90+
# error: [not-iterable] "Object of type `int` is not iterable"
91+
# revealed: tuple[int, Unknown]
92+
[reveal_type((x, z)) for x in IntIterable() for z in x]
93+
```
94+
95+
## Starred expressions
96+
97+
Starred expressions must be iterable
98+
99+
```py
100+
class NotIterable: ...
101+
102+
class Iterator:
103+
def __next__(self) -> int:
104+
return 42
105+
106+
class Iterable:
107+
def __iter__(self) -> Iterator: ...
108+
109+
# This is fine:
110+
x = [*Iterable()]
111+
112+
# error: [not-iterable] "Object of type `NotIterable` is not iterable"
113+
y = [*NotIterable()]
114+
```
115+
116+
## Async comprehensions
117+
118+
### Basic
119+
120+
```py
121+
class AsyncIterator:
122+
async def __anext__(self) -> int:
123+
return 42
124+
125+
class AsyncIterable:
126+
def __aiter__(self) -> AsyncIterator:
127+
return AsyncIterator()
128+
129+
# revealed: @Todo(async iterables/iterators)
130+
[reveal_type(x) async for x in AsyncIterable()]
131+
```
132+
133+
### Invalid async comprehension
134+
135+
This tests that we understand that `async` comprehensions do *not* work according to the synchronous
136+
iteration protocol
137+
138+
```py
139+
class Iterator:
140+
def __next__(self) -> int:
141+
return 42
142+
143+
class Iterable:
144+
def __iter__(self) -> Iterator:
145+
return Iterator()
146+
147+
# revealed: @Todo(async iterables/iterators)
148+
[reveal_type(x) async for x in Iterable()]
149+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Comprehensions with invalid syntax
2+
3+
```py
4+
class IntIterator:
5+
def __next__(self) -> int:
6+
return 42
7+
8+
class IntIterable:
9+
def __iter__(self) -> IntIterator:
10+
return IntIterator()
11+
12+
# Missing 'in' keyword.
13+
14+
# It's reasonably clear here what they *meant* to write,
15+
# so we'll still infer the correct type:
16+
17+
# error: [invalid-syntax] "Expected 'in', found name"
18+
# revealed: int
19+
[reveal_type(a) for a IntIterable()]
20+
21+
22+
# Missing iteration variable
23+
24+
# error: [invalid-syntax] "Expected an identifier, but found a keyword 'in' that cannot be used here"
25+
# error: [invalid-syntax] "Expected 'in', found name"
26+
# error: [unresolved-reference]
27+
# revealed: Unknown
28+
[reveal_type(b) for in IntIterable()]
29+
30+
31+
# Missing iterable
32+
33+
# error: [invalid-syntax] "Expected an expression"
34+
# revealed: Unknown
35+
[reveal_type(c) for c in]
36+
37+
38+
# Missing 'in' keyword and missing iterable
39+
40+
# error: [invalid-syntax] "Expected 'in', found ']'"
41+
# revealed: Unknown
42+
[reveal_type(d) for d]
43+
```

0 commit comments

Comments
 (0)