fix False positive with overloaded async iterators #2873#2939
fix False positive with overloaded async iterators #2873#2939asukaminato0721 wants to merge 2 commits intofacebook:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes a false-positive overload/yield error involving async generator implementations with overload stubs returning AsyncIterator[...], and unions of async-iterator return types.
Changes:
- Normalize overload return signatures when the implementation is an async generator (so overloads don’t remain wrapped as
Coroutine[..., AsyncIterator[...]]). - Update generator/async-generator decomposition to handle
Uniontypes member-by-member and union the decomposed components. - Add a regression test covering overloaded async iterator returns and yield behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| pyrefly/lib/test/overload.rs | Adds a regression test reproducing issue #2873 with overloaded async generator returning AsyncIterator[...]. |
| pyrefly/lib/alt/unwrap.rs | Decomposes generator / async generator types across union members and unions their yield/send/return components. |
| pyrefly/lib/alt/function.rs | Normalizes overload signatures for async generator implementations before overload consistency checking. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Diff from mypy_primer, showing the effect of this PR on open source code: freqtrade (https://github.com/freqtrade/freqtrade)
+ ERROR freqtrade/rpc/api_server/deps.py:23:24-49: Async generator function should return `AsyncGenerator` [bad-return]
starlette (https://github.com/encode/starlette)
+ ERROR tests/middleware/test_gzip.py:75:58-71: Async generator function should return `AsyncGenerator` [bad-return]
+ ERROR tests/middleware/test_gzip.py:98:58-71: Async generator function should return `AsyncGenerator` [bad-return]
+ ERROR tests/middleware/test_gzip.py:123:58-71: Async generator function should return `AsyncGenerator` [bad-return]
+ ERROR tests/middleware/test_gzip.py:146:58-71: Async generator function should return `AsyncGenerator` [bad-return]
steam.py (https://github.com/Gobot1234/steam.py)
- ERROR steam/leaderboard.py:101:15-22: Overload return type `Coroutine[Unknown, Unknown, AsyncGenerator[LeaderboardUser]]` is not assignable to implementation return type `AsyncGenerator[LeaderboardUser]` [inconsistent-overload]
- ERROR steam/leaderboard.py:110:15-22: Overload return type `Coroutine[Unknown, Unknown, AsyncGenerator[LeaderboardUser]]` is not assignable to implementation return type `AsyncGenerator[LeaderboardUser]` [inconsistent-overload]
strawberry (https://github.com/strawberry-graphql/strawberry)
+ ERROR strawberry/channels/testing.py:116:10-58: Async generator function should return `AsyncGenerator` [bad-return]
optuna (https://github.com/optuna/optuna)
- ERROR optuna/storages/_rdb/alembic/versions/v2.4.0.a.py:181:42-51: Argument `str | None` is not assignable to parameter `constraint_name` with type `str` in function `alembic.operations.base.BatchOperations.drop_constraint` [bad-argument-type]
prefect (https://github.com/PrefectHQ/prefect)
+ ERROR src/prefect/server/models/task_runs.py:138:8-21: Object of class `NoneType` has no attribute `created` [missing-attribute]
+ ERROR src/prefect/server/models/task_runs.py:141:25-33: Object of class `NoneType` has no attribute `id` [missing-attribute]
+ ERROR src/prefect/server/models/task_runs.py:147:12-17: Returned type `TaskRun | None` is not assignable to declared return type `TaskRun` [bad-return]
|
Primer Diff Classification❌ 3 regression(s) | ✅ 3 improvement(s) | 6 project(s) total | +9, -3 errors 3 regression(s) across freqtrade, optuna, prefect. error kinds:
Detailed analysis❌ Regression (3)freqtrade (+1)
The core issue is that the return type annotation Looking at the code: the However, this is likely a true positive that is low-severity in practice. The annotation That said, since mypy and pyright both accept this pattern without error, and it appears in real-world codebases like freqtrade, this represents a compatibility difference where pyrefly is stricter than other type checkers. Whether this is a "false positive" depends on perspective - the annotation is technically wrong, but the intent is clear and other tools accept it. This is best categorized as a pyrefly-specific strictness issue where pyrefly does not handle union return types containing a valid async generator type (like
optuna (-1)
prefect (+3)
✅ Improvement (3)starlette (+4)
steam.py (-2)
strawberry (+1)
Suggested fixesSummary: The refactored **1. In rust This allows
2. In
3. For the prefect regression specifically: investigate whether the union handling changes in
Was this helpful? React with 👍 or 👎 Classification by primer-classifier (6 LLM) |
Summary
Fixes #2873
The change has two parts.
overload signatures are normalized when the implementation is an async generator, so async def overload stubs returning
AsyncIterator[...]no longer stay wrapped asCoroutine[..., AsyncIterator[...]].generator decomposition now handles unions member-by-member, which fixes the bogus yield Patch() vs FullState error from
AsyncIterator[Patch] | AsyncIterator[FullState].Test Plan
add test