Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[ty] Infer empty collection constructors from later uses#26389

Merged
charliermarsh merged 2 commits into
mainfrom
charlie/bidirectional-builtin-collections
Jun 26, 2026
Merged

[ty] Infer empty collection constructors from later uses#26389
charliermarsh merged 2 commits into
mainfrom
charlie/bidirectional-builtin-collections

Conversation

@charliermarsh

@charliermarsh charliermarsh commented Jun 26, 2026

Copy link
Copy Markdown
Member

Summary

Unannotated collection literals participate in full-scope bidirectional inference, but empty constructor calls (list(), set(), and dict()) did not. For example, we previously accepted this function because result remained set[Unknown]:

def make_set() -> set[str]:
    result = set()
    result.add(1)
    reveal_type(result)  # revealed: set[int | str]
    return result  # error: [invalid-return-type]

This PR treats bare, zero-argument list(), set(), and dict() assignment values as collection initializers in the semantic index and reuses the existing collection-use constraint inference. (For now, we don't support aliased or attribute-accessed calls.)

Closes astral-sh/ty#3573.

@astral-sh-bot astral-sh-bot Bot added the ty Multi-file analysis & type inference label Jun 26, 2026
@astral-sh-bot

astral-sh-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 94.47%. The percentage of expected errors that received a diagnostic held steady at 89.19%. The number of fully passing files held steady at 95/134.

@astral-sh-bot

astral-sh-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

Memory usage report

Summary

Project Old New Diff Outcome
prefect 448.43MB 448.73MB +0.07% (305.84kB)
sphinx 166.58MB 166.86MB +0.17% (293.86kB)
trio 70.29MB 70.37MB +0.11% (78.97kB)
flake8 28.95MB 28.98MB +0.10% (30.79kB)

Significant changes

Click to expand detailed breakdown

prefect

Name Old New Diff Outcome
infer_expression_types_impl 37.84MB 37.97MB +0.35% (133.90kB)
infer_definition_types 49.97MB 49.99MB +0.04% (20.38kB)
Type<'db>::apply_specialization_inner_::interned_arguments 2.95MB 2.96MB +0.48% (14.38kB)
StaticClassLiteral<'db>::try_mro_ 3.38MB 3.39MB +0.39% (13.65kB)
Specialization 2.68MB 2.69MB +0.48% (13.09kB)
FunctionType 4.59MB 4.60MB +0.21% (9.64kB)
Type<'db>::apply_specialization_inner_ 2.03MB 2.04MB +0.46% (9.57kB)
member_lookup_with_policy_inner 10.22MB 10.22MB +0.08% (7.99kB)
when_constraint_set_assignable_to_owned_impl 2.05MB 2.06MB +0.34% (7.22kB)
all_narrowing_constraints_for_expression 5.22MB 5.22MB +0.12% (6.60kB)
semantic_index 113.94MB 113.94MB +0.00% (5.34kB)
GenericAlias 1.11MB 1.11MB +0.46% (5.20kB)
CallableType 2.87MB 2.87MB +0.17% (5.00kB)
infer_statement_types_impl 812.52kB 817.27kB +0.58% (4.75kB)
Type<'db>::class_member_with_policy_ 7.91MB 7.91MB +0.06% (4.62kB)
... 34 more

sphinx

Name Old New Diff Outcome
infer_expression_types_impl 14.77MB 14.89MB +0.78% (117.87kB)
infer_definition_types 13.67MB 13.69MB +0.16% (22.30kB)
analyze_non_terminal_call 663.09kB 683.05kB +3.01% (19.95kB)
all_narrowing_constraints_for_expression 1.93MB 1.94MB +0.84% (16.57kB)
StaticClassLiteral<'db>::try_mro_ 1.78MB 1.80MB +0.71% (13.00kB)
Type<'db>::apply_specialization_inner_::interned_arguments 1.54MB 1.55MB +0.73% (11.56kB)
Specialization 1.41MB 1.42MB +0.71% (10.28kB)
Type<'db>::apply_specialization_inner_ 1.03MB 1.04MB +0.72% (7.64kB)
FunctionType 1.78MB 1.79MB +0.41% (7.48kB)
when_constraint_set_assignable_to_owned_impl 979.57kB 986.82kB +0.74% (7.25kB)
member_lookup_with_policy_inner 4.28MB 4.29MB +0.14% (6.34kB)
infer_statement_types_impl 481.90kB 487.89kB +1.24% (5.99kB)
infer_unpack_types 305.88kB 311.56kB +1.86% (5.68kB)
CallableType 1.44MB 1.44MB +0.38% (5.53kB)
GenericAlias 619.73kB 624.02kB +0.69% (4.29kB)
... 35 more

trio

Name Old New Diff Outcome
infer_expression_types_impl 4.38MB 4.42MB +0.79% (35.38kB)
StaticClassLiteral<'db>::try_mro_ 527.12kB 532.94kB +1.10% (5.82kB)
infer_definition_types 3.97MB 3.97MB +0.09% (3.73kB)
Specialization 461.33kB 464.94kB +0.78% (3.61kB)
FunctionType 738.11kB 740.53kB +0.33% (2.42kB)
Type<'db>::apply_specialization_inner_::interned_arguments 507.73kB 510.08kB +0.46% (2.34kB)
member_lookup_with_policy_inner 1.03MB 1.03MB +0.22% (2.30kB)
when_constraint_set_assignable_to_owned_impl 269.52kB 271.54kB +0.75% (2.02kB)
analyze_non_terminal_call 382.63kB 384.63kB +0.52% (2.00kB)
StaticClassLiteral<'db>::try_mro_::interned_arguments 180.63kB 182.46kB +1.01% (1.83kB)
GenericAlias 190.41kB 192.23kB +0.96% (1.83kB)
Type<'db>::apply_specialization_inner_ 349.81kB 351.43kB +0.46% (1.62kB)
all_narrowing_constraints_for_expression 459.52kB 461.06kB +0.33% (1.54kB)
CallableType 666.44kB 667.97kB +0.23% (1.53kB)
Expression 1.27MB 1.27MB +0.11% (1.38kB)
... 20 more

flake8

Name Old New Diff Outcome
infer_expression_types_impl 645.48kB 650.79kB +0.82% (5.30kB)
Type<'db>::apply_specialization_inner_::interned_arguments 175.47kB 178.28kB +1.60% (2.81kB)
StaticClassLiteral<'db>::try_mro_ 215.98kB 218.62kB +1.22% (2.64kB)
Specialization 176.09kB 178.42kB +1.32% (2.33kB)
FunctionType 226.92kB 228.89kB +0.87% (1.97kB)
Type<'db>::apply_specialization_inner_ 119.18kB 121.10kB +1.61% (1.92kB)
CallableType 209.52kB 210.95kB +0.69% (1.44kB)
when_constraint_set_assignable_to_owned_impl 101.37kB 102.65kB +1.26% (1.28kB)
member_lookup_with_policy_inner 291.96kB 293.12kB +0.40% (1.16kB)
Type<'db>::class_member_with_policy_ 235.86kB 236.84kB +0.42% (1008.00B)
member_lookup_with_policy_inner::interned_arguments 206.13kB 207.07kB +0.45% (960.00B)
StaticClassLiteral<'db>::try_mro_::interned_arguments 73.97kB 74.81kB +1.14% (864.00B)
GenericAlias 76.71kB 77.55kB +1.10% (864.00B)
infer_definition_types 1001.23kB 1002.05kB +0.08% (848.00B)
Type<'db>::class_member_with_policy_::interned_arguments 169.61kB 170.42kB +0.48% (832.00B)
... 16 more

@charliermarsh charliermarsh force-pushed the charlie/bidirectional-builtin-collections branch from 800fdc8 to 7d4af40 Compare June 26, 2026 01:42
@astral-sh-bot

astral-sh-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-argument-type 13 0 1
no-matching-overload 10 0 0
unresolved-attribute 1 0 2
unsupported-operator 0 0 3
invalid-assignment 2 0 0
not-iterable 0 0 1
unused-type-ignore-comment 0 1 0
Total 26 1 7
Raw diff (34 changes)
beartype (https://github.com/beartype/beartype)
+ beartype/bite/collection/infercollectionitems.py:288:47 error[invalid-argument-type] Argument to function `make_hint_pep484604_union` is incorrect: Expected `Sequence[TypeForm[Any]]`, found `tuple[object, ...]`
+ beartype/bite/collection/infercollectionitems.py:289:49 error[invalid-argument-type] Argument to function `make_hint_pep484604_union` is incorrect: Expected `Sequence[TypeForm[Any]]`, found `tuple[object, ...]`

core (https://github.com/home-assistant/core)
- homeassistant/components/tasmota/light.py:224:40 error[unsupported-operator] Operator `in` is not supported between objects of type `Literal[ColorMode.HS]` and `set[ColorMode] | None | set[Unknown]`
+ homeassistant/components/tasmota/light.py:224:40 error[unsupported-operator] Operator `in` is not supported between objects of type `Literal[ColorMode.HS]` and `set[ColorMode] | None`
- homeassistant/components/tasmota/light.py:228:37 error[unsupported-operator] Operator `in` is not supported between objects of type `Literal[ColorMode.WHITE]` and `set[ColorMode] | None | set[Unknown]`
+ homeassistant/components/tasmota/light.py:228:37 error[unsupported-operator] Operator `in` is not supported between objects of type `Literal[ColorMode.WHITE]` and `set[ColorMode] | None`
- homeassistant/components/tasmota/light.py:239:17 error[unsupported-operator] Operator `in` is not supported between objects of type `Literal[ColorMode.COLOR_TEMP]` and `set[ColorMode] | None | set[Unknown]`
+ homeassistant/components/tasmota/light.py:239:17 error[unsupported-operator] Operator `in` is not supported between objects of type `Literal[ColorMode.COLOR_TEMP]` and `set[ColorMode] | None`

freqtrade (https://github.com/freqtrade/freqtrade)
- freqtrade/optimize/analysis/lookahead.py:137:57 error[invalid-argument-type] Argument to function `LookaheadAnalysis.get_result` is incorrect: Expected `DataFrame`, found `dict[Unknown, Unknown]`
+ freqtrade/optimize/analysis/lookahead.py:137:57 error[invalid-argument-type] Argument to function `LookaheadAnalysis.get_result` is incorrect: Expected `DataFrame`, found `dict[str, DataFrame]`

manticore (https://github.com/trailofbits/manticore)
+ tests/other/test_smtlibv2.py:139:25 error[invalid-argument-type] Argument to bound method `set.add` is incorrect: Expected `<class 'Expression'> | <class 'BoolOperation'> | <class 'BitVecOperation'> | ... omitted 4 union elements`, found `type`

mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
+ pymongo/asynchronous/mongo_client.py:892:37 error[invalid-argument-type] Argument to bound method `AsyncMongoClient._init_based_on_options` is incorrect: Expected `Collection[tuple[str, int]]`, found `set[Unknown | tuple[str, int | None]] & ~AlwaysFalsy`
+ pymongo/asynchronous/mongo_client.py:971:41 error[invalid-argument-type] Argument to bound method `AsyncMongoClient._init_based_on_options` is incorrect: Expected `Collection[tuple[str, int]]`, found `set[Unknown | tuple[str, int | None]] & ~AlwaysFalsy`
+ pymongo/synchronous/mongo_client.py:893:37 error[invalid-argument-type] Argument to bound method `MongoClient._init_based_on_options` is incorrect: Expected `Collection[tuple[str, int]]`, found `set[Unknown | tuple[str, int | None]] & ~AlwaysFalsy`
+ pymongo/synchronous/mongo_client.py:972:41 error[invalid-argument-type] Argument to bound method `MongoClient._init_based_on_options` is incorrect: Expected `Collection[tuple[str, int]]`, found `set[Unknown | tuple[str, int | None]] & ~AlwaysFalsy`

pandas (https://github.com/pandas-dev/pandas)
+ pandas/core/internals/construction.py:430:21 error[invalid-argument-type] Argument to function `construct_1d_arraylike_from_scalar` is incorrect: Expected `str | bytes | date | ... omitted 10 union elements`, found `object`
+ pandas/core/internals/construction.py:434:17 error[invalid-assignment] Invalid subscript assignment with key of type `int` and value of type `ExtensionArray | ndarray[tuple[Any, ...], dtype[Any]]` on object of type `list[int | float]`

pyppeteer (https://github.com/pyppeteer/pyppeteer)
- pyppeteer/launcher.py:148:40 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive

scikit-learn (https://github.com/scikit-learn/scikit-learn)
+ sklearn/linear_model/_logistic.py:2402:30 error[no-matching-overload] No overload of function `tile` matches arguments
- sklearn/linear_model/tests/test_logistic.py:1940:12 error[unresolved-attribute] Attribute `shape` is not defined on `list[Unknown]`, `int`, `float` in union `list[Unknown] | ndarray[tuple[Any, ...], dtype[Unknown]] | int | float`
+ sklearn/linear_model/tests/test_logistic.py:1940:12 error[unresolved-attribute] Attribute `shape` is not defined on `list[Any]`, `int`, `float` in union `list[Any] | ndarray[tuple[Any, ...], dtype[Unknown]] | int | float`
- sklearn/linear_model/tests/test_logistic.py:1941:12 error[unresolved-attribute] Attribute `shape` is not defined on `list[Unknown]`, `int`, `float` in union `list[Unknown] | ndarray[tuple[Any, ...], dtype[Unknown]] | int | float`
+ sklearn/linear_model/tests/test_logistic.py:1941:12 error[unresolved-attribute] Attribute `shape` is not defined on `list[Unknown | str | None | int | float]`, `int`, `float` in union `list[Unknown | str | None | int | float] | Unknown | ndarray[tuple[Any, ...], dtype[Any]] | int | float`
+ sklearn/linear_model/tests/test_logistic.py:1946:9 error[no-matching-overload] No overload of function `assert_allclose` matches arguments
+ sklearn/linear_model/tests/test_logistic.py:1995:5 error[no-matching-overload] No overload of function `assert_allclose` matches arguments
+ sklearn/metrics/tests/test_common.py:1305:13 error[invalid-assignment] Object of type `str` is not assignable to attribute `__name__` on type `(Unknown & Top[partial[Unknown]]) | partial[(...) -> Unknown] | (((...) -> Unknown) & Top[partial[Unknown]])`

scipy (https://github.com/scipy/scipy)
+ scipy/conftest.py:661:55 error[invalid-argument-type] Argument to function `filterwarnings` is incorrect: Expected `bool`, found `<class 'RuntimeWarning'> | str | <class 'DeprecationWarning'> | ... omitted 3 union elements`
+ scipy/conftest.py:661:55 error[invalid-argument-type] Argument to function `filterwarnings` is incorrect: Expected `int`, found `<class 'RuntimeWarning'> | str | <class 'DeprecationWarning'> | ... omitted 3 union elements`
+ scipy/conftest.py:661:55 error[invalid-argument-type] Argument to function `filterwarnings` is incorrect: Expected `str`, found `<class 'RuntimeWarning'> | str | <class 'DeprecationWarning'> | ... omitted 3 union elements`
+ scipy/conftest.py:661:55 error[invalid-argument-type] Argument to function `filterwarnings` is incorrect: Expected `str`, found `<class 'RuntimeWarning'> | str | <class 'DeprecationWarning'> | ... omitted 3 union elements`
+ scipy/conftest.py:661:55 error[invalid-argument-type] Argument to function `filterwarnings` is incorrect: Expected `type[Warning]`, found `<class 'RuntimeWarning'> | str | <class 'DeprecationWarning'> | ... omitted 3 union elements`
+ scipy/spatial/tests/test_distance.py:615:14 error[no-matching-overload] No overload of function `cdist` matches arguments
+ scipy/spatial/tests/test_distance.py:664:14 error[no-matching-overload] No overload of function `cdist` matches arguments
+ scipy/spatial/tests/test_distance.py:665:14 error[no-matching-overload] No overload of function `cdist` matches arguments
+ scipy/spatial/tests/test_distance.py:677:15 error[no-matching-overload] No overload of function `cdist` matches arguments
+ scipy/spatial/tests/test_distance.py:1394:19 error[no-matching-overload] No overload of function `pdist` matches arguments
+ scipy/spatial/tests/test_distance.py:1432:14 error[no-matching-overload] No overload of function `pdist` matches arguments
+ scipy/spatial/tests/test_distance.py:1433:14 error[no-matching-overload] No overload of function `pdist` matches arguments

sympy (https://github.com/sympy/sympy)
+ sympy/simplify/radsimp.py:206:35 error[unresolved-attribute] Attribute `base` is not defined on `Expr` in union `Expr | Unknown`
- sympy/simplify/radsimp.py:708:28 error[not-iterable] Object of type `set[Unknown] | Basic` may not be iterable
+ sympy/simplify/radsimp.py:708:28 error[not-iterable] Object of type `set[Expr] | Basic` may not be iterable

Full report with detailed diff (timing results)

@charliermarsh charliermarsh force-pushed the charlie/bidirectional-builtin-collections branch from 2471566 to 0ed9d0c Compare June 26, 2026 02:01
@charliermarsh charliermarsh marked this pull request as ready for review June 26, 2026 02:16
@charliermarsh charliermarsh requested review from a team as code owners June 26, 2026 02:16
@astral-sh-bot astral-sh-bot Bot requested a review from dcreager June 26, 2026 02:16
@charliermarsh charliermarsh requested review from ibraheemdev and removed request for dcreager June 26, 2026 02:16

@ibraheemdev ibraheemdev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!

I wonder if it makes sense to extend this (as a followup) to non-empty collection constructor calls, e.g., x = list((1, 2, 3)); x.append("4") for consistency with literals, but it may end up being somewhat unintuitive.

@charliermarsh charliermarsh merged commit 71541d4 into main Jun 26, 2026
63 checks passed
@charliermarsh charliermarsh deleted the charlie/bidirectional-builtin-collections branch June 26, 2026 10:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No bidirectional inference for set()

2 participants