Contextually type comprehension arguments during overload resolution#4224
Open
markselby9 wants to merge 1 commit into
Open
Contextually type comprehension arguments during overload resolution#4224markselby9 wants to merge 1 commit into
markselby9 wants to merge 1 commit into
Conversation
When resolving an overloaded call, container literals (list/set/dict) are kept as expressions rather than eagerly inferred, so each candidate overload can contextually type them against its parameter and narrow element literals. Comprehensions and generator expressions were not: they fell through to a context-free `expr_infer`, so `[(name, "ascending") for name in names]` was inferred as `list[tuple[str, str]]` and failed to match a `Sequence[tuple[str, Literal["ascending", "descending"]]]` overload, even though mypy, pyright, and ty all accept it. Include comprehension and generator expressions in the un-flattened arm of `CallWithTypes::type_or_expr`. They already support hint-directed inference via `infer_with_decomposed_hint` / `decompose_list`, so deferring their inference lets the existing per-overload contextual-typing path narrow their element/key/value types exactly as it does for container literals. Closes facebook#4167
|
Diff from mypy_primer, showing the effect of this PR on open source code: rotki (https://github.com/rotki/rotki)
- ERROR rotkehlchen/api/services/assets.py:532:32-535:15: No matching overload found for function `typing.MutableMapping.update` called with arguments: (dict[Asset, list[Price | int]]) [no-matching-overload]
scikit-learn (https://github.com/scikit-learn/scikit-learn)
- ERROR sklearn/utils/_metadata_requests.py:1668:29-1677:10: No matching overload found for function `collections.defaultdict.__init__` called with arguments: (type[str], dict[str, None]) [no-matching-overload]
zulip (https://github.com/zulip/zulip)
+ ERROR zerver/actions/message_send.py:1411:12-67: Returned type `list[object]` is not assignable to declared return type `list[str]` [bad-return]
optuna (https://github.com/optuna/optuna)
- ERROR optuna/visualization/_hypervolume_history.py:114:30-50: `*` is not supported between `ndarray[tuple[int], dtype[signedinteger[_NBitIntP]]]` and `None` [unsupported-operation]
+ ERROR optuna/visualization/_hypervolume_history.py:114:30-50: `*` is not supported between `ndarray[tuple[int], dtype[float64]]` and `None` [unsupported-operation]
|
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes overload resolution failing to contextually type comprehension and generator arguments, so a literal element is not narrowed to the expected type.
When resolving an overloaded call, container literals (
list/set/dict) are kept as expressions rather than eagerly inferred, so each candidate overload can contextually type them against its parameter (and narrow element literals). Comprehensions and generator expressions were not — they fell through to a context-freeexpr_inferinCallWithTypes::type_or_expr, so:was inferred as
list[tuple[str, str]]and reportedno-matching-overload, even though mypy, pyright, and ty all accept it (reported against Narwhals).The fix adds
Expr::ListComp | Expr::SetComp | Expr::DictComp | Expr::Generatorto the same un-flattened arm. These variants already support hint-directed inference viainfer_with_decomposed_hint/decompose_list, so deferring their inference lets the existing per-overload contextual-typing path narrow their element/key/value types exactly as it does for container literals. When a hint doesn't decompose (e.g. a generator against a non-Sequenceparam), inference falls back to the previous context-free behaviour, so no path is worse than before.Closes #4167
Test plan
Added
test_overload_literal_narrowing_through_comprehension(the reported repro) andtest_overload_literal_narrowing_through_set_dict_generator(covering the set/dict-comprehension and generator variants) topyrefly/lib/test/overload.rs. Both fail before the change (no-matching-overload,reveal_type=Unknown) and pass after (reveal_type=str).Full
cargo test -p pyrefly --libsuite passes (0 failures);test.pyformatting + linting clean.