Skip to content

Commit

Permalink
[red-knot] Port comprehension tests to Markdown (#15688)
Browse files Browse the repository at this point in the history
## 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
sharkdp authored Jan 23, 2025
1 parent 05ea77b commit 0173738
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 409 deletions.
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()]
```
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]
```
Loading

0 comments on commit 0173738

Please sign in to comment.