mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 05:15:12 +00:00

## Summary This PR closes #16248. If the return type of the function isn't assignable to the one specified, an `invalid-return-type` error occurs. I thought it would be better to report this as a different kind of error than the `invalid-assignment` error, so I defined this as a new error. ## Test Plan All type inconsistencies in the test cases have been replaced with appropriate ones. --------- Co-authored-by: Carl Meyer <carl@astral.sh>
3 KiB
3 KiB
Comprehensions
Basic comprehensions
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
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
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
:
# 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
class NotIterable: ...
class Iterator:
def __next__(self) -> int:
return 42
class Iterable:
def __iter__(self) -> Iterator:
return Iterator()
# This is fine:
x = [*Iterable()]
# error: [not-iterable] "Object of type `NotIterable` is not iterable"
y = [*NotIterable()]
Async comprehensions
Basic
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
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()]