-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[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
- Loading branch information
Showing
3 changed files
with
192 additions
and
409 deletions.
There are no files selected for viewing
149 changes: 149 additions & 0 deletions
149
crates/red_knot_python_semantic/resources/mdtest/comprehensions/basic.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
# Comprehensions | ||
|
||
## Basic comprehensions | ||
|
||
```py | ||
class IntIterator: | ||
def __next__(self) -> int: | ||
return 42 | ||
|
||
class IntIterable: | ||
def __iter__(self) -> IntIterator: | ||
return IntIterator() | ||
|
||
# revealed: int | ||
[reveal_type(x) for x in IntIterable()] | ||
|
||
class IteratorOfIterables: | ||
def __next__(self) -> IntIterable: | ||
return IntIterable() | ||
|
||
class IterableOfIterables: | ||
def __iter__(self) -> IteratorOfIterables: | ||
return IteratorOfIterables() | ||
|
||
# revealed: tuple[int, IntIterable] | ||
[reveal_type((x, y)) for y in IterableOfIterables() for x in y] | ||
|
||
# revealed: int | ||
{reveal_type(x): 0 for x in IntIterable()} | ||
|
||
# revealed: int | ||
{0: reveal_type(x) for x in IntIterable()} | ||
``` | ||
|
||
## Nested comprehension | ||
|
||
```py | ||
class IntIterator: | ||
def __next__(self) -> int: | ||
return 42 | ||
|
||
class IntIterable: | ||
def __iter__(self) -> IntIterator: | ||
return IntIterator() | ||
|
||
# revealed: tuple[int, int] | ||
[[reveal_type((x, y)) for x in IntIterable()] for y in IntIterable()] | ||
``` | ||
|
||
## Comprehension referencing outer comprehension | ||
|
||
```py | ||
class IntIterator: | ||
def __next__(self) -> int: | ||
return 42 | ||
|
||
class IntIterable: | ||
def __iter__(self) -> IntIterator: | ||
return IntIterator() | ||
|
||
class IteratorOfIterables: | ||
def __next__(self) -> IntIterable: | ||
return IntIterable() | ||
|
||
class IterableOfIterables: | ||
def __iter__(self) -> IteratorOfIterables: | ||
return IteratorOfIterables() | ||
|
||
# revealed: tuple[int, IntIterable] | ||
[[reveal_type((x, y)) for x in y] for y in IterableOfIterables()] | ||
``` | ||
|
||
## Comprehension with unbound iterable | ||
|
||
Iterating over an unbound iterable yields `Unknown`: | ||
|
||
```py | ||
# error: [unresolved-reference] "Name `x` used when not defined" | ||
# revealed: Unknown | ||
[reveal_type(z) for z in x] | ||
|
||
class IntIterator: | ||
def __next__(self) -> int: | ||
return 42 | ||
|
||
class IntIterable: | ||
def __iter__(self) -> IntIterator: | ||
return IntIterator() | ||
|
||
# error: [not-iterable] "Object of type `int` is not iterable" | ||
# revealed: tuple[int, Unknown] | ||
[reveal_type((x, z)) for x in IntIterable() for z in x] | ||
``` | ||
|
||
## Starred expressions | ||
|
||
Starred expressions must be iterable | ||
|
||
```py | ||
class NotIterable: ... | ||
|
||
class Iterator: | ||
def __next__(self) -> int: | ||
return 42 | ||
|
||
class Iterable: | ||
def __iter__(self) -> Iterator: ... | ||
|
||
# This is fine: | ||
x = [*Iterable()] | ||
|
||
# error: [not-iterable] "Object of type `NotIterable` is not iterable" | ||
y = [*NotIterable()] | ||
``` | ||
|
||
## Async comprehensions | ||
|
||
### Basic | ||
|
||
```py | ||
class AsyncIterator: | ||
async def __anext__(self) -> int: | ||
return 42 | ||
|
||
class AsyncIterable: | ||
def __aiter__(self) -> AsyncIterator: | ||
return AsyncIterator() | ||
|
||
# revealed: @Todo(async iterables/iterators) | ||
[reveal_type(x) async for x in AsyncIterable()] | ||
``` | ||
|
||
### Invalid async comprehension | ||
|
||
This tests that we understand that `async` comprehensions do *not* work according to the synchronous | ||
iteration protocol | ||
|
||
```py | ||
class Iterator: | ||
def __next__(self) -> int: | ||
return 42 | ||
|
||
class Iterable: | ||
def __iter__(self) -> Iterator: | ||
return Iterator() | ||
|
||
# revealed: @Todo(async iterables/iterators) | ||
[reveal_type(x) async for x in Iterable()] | ||
``` |
43 changes: 43 additions & 0 deletions
43
crates/red_knot_python_semantic/resources/mdtest/comprehensions/invalid_syntax.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Comprehensions with invalid syntax | ||
|
||
```py | ||
class IntIterator: | ||
def __next__(self) -> int: | ||
return 42 | ||
|
||
class IntIterable: | ||
def __iter__(self) -> IntIterator: | ||
return IntIterator() | ||
|
||
# Missing 'in' keyword. | ||
|
||
# It's reasonably clear here what they *meant* to write, | ||
# so we'll still infer the correct type: | ||
|
||
# error: [invalid-syntax] "Expected 'in', found name" | ||
# revealed: int | ||
[reveal_type(a) for a IntIterable()] | ||
|
||
|
||
# Missing iteration variable | ||
|
||
# error: [invalid-syntax] "Expected an identifier, but found a keyword 'in' that cannot be used here" | ||
# error: [invalid-syntax] "Expected 'in', found name" | ||
# error: [unresolved-reference] | ||
# revealed: Unknown | ||
[reveal_type(b) for in IntIterable()] | ||
|
||
|
||
# Missing iterable | ||
|
||
# error: [invalid-syntax] "Expected an expression" | ||
# revealed: Unknown | ||
[reveal_type(c) for c in] | ||
|
||
|
||
# Missing 'in' keyword and missing iterable | ||
|
||
# error: [invalid-syntax] "Expected 'in', found ']'" | ||
# revealed: Unknown | ||
[reveal_type(d) for d] | ||
``` |
Oops, something went wrong.