[ty] pass type context to sequence literals in binary operations#24197
[ty] pass type context to sequence literals in binary operations#24197oconnor663 merged 3 commits intomainfrom
Conversation
Typing conformance resultsNo changes detected ✅Current numbersThe percentage of diagnostics emitted that were expected errors held steady at 86.79%. The percentage of expected errors that received a diagnostic held steady at 81.72%. The number of fully passing files held steady at 70/132. |
Memory usage reportSummary
Significant changesClick to expand detailed breakdownprefect
sphinx
trio
flake8
|
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
invalid-assignment |
0 | 27 | 3 |
unsupported-operator |
0 | 10 | 0 |
invalid-argument-type |
0 | 8 | 0 |
invalid-return-type |
0 | 3 | 1 |
no-matching-overload |
0 | 1 | 0 |
not-iterable |
0 | 1 | 0 |
| Total | 0 | 50 | 4 |
Raw diff (54 changes)
core (https://github.com/home-assistant/core)
- homeassistant/components/osoenergy/water_heater.py:163:36 error[invalid-assignment] Object of type `list[int | float]` is not assignable to `list[JsonValueType]`
dedupe (https://github.com/dedupeio/dedupe)
- dedupe/labeler.py:451:26 error[invalid-assignment] Object of type `list[int]` is not assignable to `list[Literal[0, 1]]`
- dedupe/labeler.py:487:26 error[invalid-assignment] Object of type `list[int]` is not assignable to `list[Literal[0, 1]]`
egglog-python (https://github.com/egraphs-good/egglog-python)
- python/egglog/pretty.py:136:28 error[invalid-assignment] Object of type `list[UnboundVarDecl]` is not assignable to `list[DummyDecl | UnboundVarDecl | LetRefDecl | ... omitted 6 union elements]`
- python/egglog/pretty.py:149:44 error[invalid-assignment] Object of type `list[UnboundVarDecl]` is not assignable to `list[DummyDecl | UnboundVarDecl | LetRefDecl | ... omitted 6 union elements]`
ignite (https://github.com/pytorch/ignite)
- ignite/handlers/param_scheduler.py:1674:22 error[invalid-assignment] Object of type `list[int]` is not assignable to `int | float | list[int | float]`
- ignite/handlers/param_scheduler.py:1675:13 error[invalid-assignment] Cannot assign to a subscript on an object of type `float`
- ignite/handlers/param_scheduler.py:1675:13 error[invalid-assignment] Cannot assign to a subscript on an object of type `int`
jax (https://github.com/google/jax)
- jax/experimental/jet.py:459:35 error[invalid-argument-type] Argument to function `square` is incorrect: Expected `Array | ndarray[tuple[Any, ...], dtype[Any]] | numpy.bool[builtins.bool] | ... omitted 4 union elements`, found `None | Unknown | Array`
- jax/experimental/jet.py:460:33 error[invalid-argument-type] Argument to function `exp` is incorrect: Expected `Array | ndarray[tuple[Any, ...], dtype[Any]] | numpy.bool[builtins.bool] | ... omitted 4 union elements`, found `None | Unknown | Array`
- jax/experimental/jet.py:465:16 error[unsupported-operator] Operator `*` is not supported between objects of type `int` and `None | Unknown | Array`
- jax/experimental/jet.py:470:22 error[unsupported-operator] Operator `*` is not supported between two objects of type `None | Unknown | Array`
- jax/experimental/jet.py:473:22 error[unsupported-operator] Operator `*` is not supported between objects of type `int` and `None | Unknown | Array`
- jax/experimental/jet.py:480:14 error[unsupported-operator] Operator `*` is not supported between objects of type `int` and `None | Unknown | Array`
- jax/experimental/jet.py:494:16 error[unsupported-operator] Operator `*` is not supported between objects of type `int` and `None | Unknown | Array`
- jax/experimental/jet.py:536:27 error[unsupported-operator] Operator `-` is not supported between objects of type `Literal[1]` and `None | Unknown | Array`
- jax/experimental/jet.py:539:13 error[unsupported-operator] Operator `-` is not supported between objects of type `Literal[1]` and `None | Unknown | Array`
- jax/experimental/jet.py:539:36 error[unsupported-operator] Operator `*` is not supported between two objects of type `None | Unknown | Array`
- jax/experimental/jet.py:563:16 error[unsupported-operator] Operator `*` is not supported between objects of type `int` and `None | Unknown | Array`
- jax/_src/export/_export.py:1294:46 error[invalid-assignment] Object of type `list[UnspecifiedValue]` is not assignable to `list[Sharding | UnspecifiedValue]`
- jax/_src/numpy/lax_numpy.py:2206:34 error[invalid-assignment] Object of type `list[int]` is not assignable to `list[Array | ndarray[tuple[Any, ...], dtype[Any]] | numpy.bool[builtins.bool] | ... omitted 4 union elements]`
- jax/_src/numpy/vectorize.py:282:25 error[invalid-assignment] Object of type `list[tuple[()]]` is not assignable to `list[tuple[str, ...]]`
- jax/_src/shard_map.py:542:44 error[invalid-assignment] Object of type `list[NoFail]` is not assignable to `list[ShapedArray | NoFail]`
meson (https://github.com/mesonbuild/meson)
- mesonbuild/backend/ninjabackend.py:2459:27 error[invalid-assignment] Object of type `list[str] | list[Unknown]` is not assignable to `list[str | NinjaCommandArg]`
- mesonbuild/backend/ninjabackend.py:1421:46 error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `list[NinjaCommandArg | str]`, found `list[str]`
mypy (https://github.com/python/mypy)
- mypyc/ir/rtypes.py:1260:51 error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `list[RType]`, found `list[RStruct]`
- mypyc/primitives/generic_ops.py:126:9 error[invalid-argument-type] Argument to function `function_op` is incorrect: Expected `list[RType]`, found `list[RPrimitive]`
- mypy/checker.py:5760:31 error[invalid-argument-type] Argument to bound method `check_method_call_by_name` is incorrect: Expected `list[Expression]`, found `list[TempNode]`
- mypy/checker.py:5776:30 error[invalid-argument-type] Argument to bound method `check_method_call_by_name` is incorrect: Expected `list[Expression]`, found `list[TempNode]`
- mypy/checkexpr.py:5068:28 error[invalid-return-type] Return type does not match returned value: expected `list[Type]`, found `list[AnyType]`
- mypy/fastparse.py:987:29 error[invalid-assignment] Object of type `list[AnyType]` is not assignable to `list[Type | None]`
pandas (https://github.com/pandas-dev/pandas)
- pandas/tests/arrays/masked/test_arithmetic.py:16:1 error[unsupported-operator] Operator `+=` is not supported between objects of type `list[int]` and `list[int | float]`
- pandas/core/indexes/multi.py:592:22 error[invalid-assignment] Object of type `list[list[Unknown]]` is not assignable to `list[Sequence[Hashable]]`
- pandas/core/indexing.py:1838:63 error[invalid-assignment] Object of type `list[slice[Any, Any, Any]]` is not assignable to `list[slice[Any, Any, Any] | ndarray[tuple[Any, ...], dtype[signedinteger[_64Bit]]]]`
- pandas/core/internals/managers.py:1262:16 error[invalid-return-type] Return type does not match returned value: expected `list[ndarray[tuple[Any, ...], dtype[Any]]]`, found `list[None | Unknown]`
+ pandas/core/internals/managers.py:1262:16 error[invalid-return-type] Return type does not match returned value: expected `list[ndarray[tuple[Any, ...], dtype[Any]]]`, found `list[ndarray[tuple[Any, ...], dtype[Any]] | None]`
- pandas/io/excel/_odfreader.py:158:30 error[invalid-argument-type] Argument to bound method `extend` is incorrect: Expected `Iterable[list[str | bytes | date | ... omitted 11 union elements]]`, found `list[list[str]]`
- pandas/io/formats/html.py:347:23 error[invalid-assignment] Object of type `list[str]` is not assignable to `list[Hashable]`
- pandas/io/formats/html.py:380:19 error[invalid-assignment] Object of type `list[str]` is not assignable to `list[Hashable]`
- pandas/io/pytables.py:5166:39 error[invalid-assignment] Object of type `list[slice[Any, Any, Any]]` is not assignable to `list[slice[Any, Any, Any] | Index]`
- pandas/io/sql.py:1049:39 error[invalid-assignment] Object of type `list[None | Unknown]` is not assignable to `list[ndarray[tuple[Any, ...], dtype[Any]]]`
+ pandas/io/sql.py:1049:39 error[invalid-assignment] Object of type `list[ndarray[tuple[Any, ...], dtype[Any]] | None]` is not assignable to `list[ndarray[tuple[Any, ...], dtype[Any]]]`
prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/futures.py:517:28 error[invalid-assignment] Object of type `list[None | Unknown]` is not assignable to `list[R@PrefectFutureList]`
+ src/prefect/futures.py:517:28 error[invalid-assignment] Object of type `list[R@PrefectFutureList | None]` is not assignable to `list[R@PrefectFutureList]`
rotki (https://github.com/rotki/rotki)
- rotkehlchen/chain/evm/decoding/quickswap/v3/decoder.py:176:16 error[invalid-return-type] Return type does not match returned value: expected `dict[str, list[tuple[int, (...) -> Unknown]]]`, found `dict[str, list[tuple[int, (...) -> Unknown]] | list[tuple[int, bound method Self@post_decoding_rules._v3_router_post_decoding(transaction: EvmTransaction, decoded_events: list[EvmEvent], all_logs: list[EvmTxReceiptLog]) -> list[EvmEvent]]]]`
- rotkehlchen/chain/evm/decoding/quickswap/v4/decoder.py:73:16 error[invalid-return-type] Return type does not match returned value: expected `dict[str, list[tuple[int, (...) -> Unknown]]]`, found `dict[str, list[tuple[int, (...) -> Unknown]] | list[tuple[int, bound method Self@post_decoding_rules._router_post_decoding(transaction: EvmTransaction, decoded_events: list[EvmEvent], all_logs: list[EvmTxReceiptLog]) -> list[EvmEvent]]]]`
scikit-learn (https://github.com/scikit-learn/scikit-learn)
- sklearn/neural_network/tests/test_mlp.py:102:5 error[invalid-assignment] Invalid subscript assignment with key of type `Literal[0]` and value of type `ndarray[tuple[Any, ...], dtype[Any]]` on object of type `list[int]`
- sklearn/neural_network/tests/test_mlp.py:103:5 error[invalid-assignment] Invalid subscript assignment with key of type `Literal[1]` and value of type `ndarray[tuple[Any, ...], dtype[Any]]` on object of type `list[int]`
- sklearn/neural_network/tests/test_mlp.py:104:5 error[invalid-assignment] Invalid subscript assignment with key of type `Literal[0]` and value of type `ndarray[tuple[Any, ...], dtype[Any]]` on object of type `list[int]`
- sklearn/neural_network/tests/test_mlp.py:105:5 error[invalid-assignment] Invalid subscript assignment with key of type `Literal[1]` and value of type `ndarray[tuple[Any, ...], dtype[Any]]` on object of type `list[int]`
sockeye (https://github.com/awslabs/sockeye)
- sockeye/model.py:812:23 error[invalid-assignment] Object of type `list[None | Unknown]` is not assignable to `list[int] | None`
+ sockeye/model.py:812:23 error[invalid-assignment] Object of type `list[int | None]` is not assignable to `list[int] | None`
sympy (https://github.com/sympy/sympy)
- sympy/polys/puiseux.py:514:32 error[invalid-assignment] Object of type `Unknown | list[int]` is not assignable to `list[MPQ | int]`
- sympy/matrices/matrixbase.py:3931:46 error[invalid-assignment] Object of type `list[int]` is not assignable to `list[int | MatrixBase]`
- sympy/matrices/matrixbase.py:4878:31 error[invalid-assignment] Object of type `list[list[Expr] | list[Zero]]` is not assignable to `list[list[Expr]]`
vision (https://github.com/pytorch/vision)
- torchvision/transforms/v2/_container.py:141:17 error[invalid-assignment] Object of type `list[int]` is not assignable to `list[int | float] | None`
- torchvision/transforms/v2/_container.py:148:17 error[no-matching-overload] No overload of function `sum` matches arguments
- torchvision/transforms/v2/_container.py:149:44 error[not-iterable] Object of type `list[int | float] | None` may not be iterable1a6348c to
d3e77ff
Compare
|
The added diagnostic in |
c9e1e58 to
4aff95f
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4aff95fbba
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return BinaryExpressionOperandTypes::Inferred( | ||
| self.infer_expression(left, TypeContext::default()), | ||
| self.infer_expression(left, operand_tcx(left)), | ||
| right_ty, |
There was a problem hiding this comment.
Remove TypedDict context in
| fallback literal inference
When the left operand is a dict literal and the TypedDict fast-path rejects it, this fallback now re-infers the left literal with operand_tcx(left), which may be a TypedDict target context. That reintroduces the same spurious missing-typed-dict-key/invalid-key diagnostics this branch is meant to avoid (the comment still says it should re-infer without TypedDict context). In cases like assigning a merged dict expression to a TypedDict, the left partial literal can now emit premature key errors purely because of the outer context.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
This is confusing, and I'm not sure what we actually want to have happen here. The situation is:
x: MyTypedDict = <dict_literal> | <expression2>If inferring expression2 with the default context yields a TypedDict type, then we speculatively check whether dict_literal matches that type. If it doesn't match, then currently on the main branch we fall back to inferring dict_literal also with the default context. But it seems like it might be more correct to infer dict_literal with the inherited MyTypedDict context? In fact it seems like it might be more correct to infer both sides that way.
On the other hand, do we care to support a wacky situation like this:
class MyTypedDict(TypedDict):
a: int
b: str
x: MyTypedDict = {"a": 42} | {"b": "hello"}The problem there is that the unioned value is a valid MyTypedDict, but the two halves of it aren't, so passing MyTypedDict as type context to either side will result in errors. On the other hand, this is pretty convoluted, and we don't support it today in any case. @ibraheemdev what's your instinct here?
There was a problem hiding this comment.
But it seems like it might be more correct to infer dict_literal with the inherited MyTypedDict context?
If we failed to perform the speculative typed dict update, dict_literal is not even a valid subset of MyTypedDict, and so inferring it as MyTypedDict directly would likely lead to a lot of missing-key-errors that don't seem very useful.
On the other hand, do we care to support a wacky situation like this:
pyright and mypy doesn't seem to support this either, so it seems fine to ignore it. Maybe we should just ignore TypedDict context entirely outside of the speculative updates to avoid the extra errors, if there is no way to produce a valid TypedDict otherwise (unless there is a case I am missing)?
There was a problem hiding this comment.
As discussed, this is not entirely sound, but seems to work well enough in the common case. It might be worth adding a TODO test where eagerly passing the type context can break, e.g.,
class X:
def __add__(self, _: list[int]) -> list[int | str]:
return []
x: list[int | str] = X() + [1]which type-checks fine on main, but errors on this PR.
* main: Document adding fixes in CONTRIBUTING.md (#24393) Sort formatter diagnostics in snapshots (#24375) [`pyupgrade`] Fix panic caused by handling of octals in `UP012` (#24390) Upgrade to nix v0.31.2 (#24385) Strip form feeds from indent passed to `dedent_to` (#24381) add recent move of the `deferred` submodule to `.git-blame-ignore-revs` (#24379) [ty] Fix extra_items TypedDict tests (#24367) [ty] Use `infer_type_expression` for validating PEP-613 type aliases (#24370) [`flake8-simplify`] Make the fix for `collapsible-if` (`SIM102`) safe in `preview` (#24371) [ty] Validate TypedDict fields when subclassing (#24338) [ty] pass type context to sequence literals in binary operations (#24197) Add release environment to notify-dependents job (#24372) Bump 0.15.9 (#24369) [ty] Move the `deferred` submodule inside `infer/builder` (#24368) [ty] Infer the `extra_items` keyword argument to class-based TypedDicts as an annotation expression (#24362) [ty] Validate type qualifiers in functional TypedDict fields and the `extra_items` keyword to functional TypedDicts (#24360)
Fixes astral-sh/ty#3002.
This is a quick fix for this special case. A more general solution will be passing type context through generic method calls, with binary operations like these handled via their dunder methods.