Skip to content

Conversation

dcreager
Copy link
Member

@dcreager dcreager commented Oct 2, 2025

We have to track whether a typevar appears in a position where it's inferable or not. In a non-inferable position (in the body of the generic class or function that binds it), assignability must hold for every possible specialization of the typevar. In an inferable position, it only needs to hold for some specialization. #20093 is working on using constraint sets to model assignability of typevars, and the constraint sets that we produce will be the same for inferable vs non-inferable typevars; what changes is what we compare that constraint set to. (For a non-inferable typevar, the constraint set must equal the set of valid specializations; for an inferable typevar, it must not be never.)

When I first added support for tracking inferable vs non-inferable typevars, it seemed like it would be easiest to have separate Type variants for each. The alternative (which lines up with the Δ set in POPL15) would be to explicitly plumb through a list of inferable typevars through our type property methods. That seemed cumbersome.

In retrospect, that was the wrong decision. We've had to jump through hoops to translate types between the inferable and non-inferable variants, which has been quite brittle. Combined with the original point above, that much of the assignability logic will become more identical between inferable and non-inferable, there is less justification for the two Type variants. And plumbing an extra inferable parameter through all of these methods turns out to not be as bad as I anticipated.

@dcreager dcreager added internal An internal refactor or improvement ty Multi-file analysis & type inference labels Oct 2, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Oct 2, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

@github-actions
Copy link
Contributor

github-actions bot commented Oct 2, 2025

mypy_primer results

Changes were detected when running on open source projects
werkzeug (https://github.com/pallets/werkzeug)
- src/werkzeug/local.py:511:24: error[invalid-return-type] Return type does not match returned value: expected `T@LocalProxy`, found `~None | T@LocalProxy | Unknown`
- Found 383 diagnostics
+ Found 382 diagnostics

typeshed-stats (https://github.com/AlexWaygood/typeshed-stats)
+ src/typeshed_stats/gather.py:1000:13: error[invalid-argument-type] Argument to bound method `from_lines` is incorrect: Expected `str | ((str, /) -> Pattern)`, found `<class 'GitWildMatchPattern'>`
- Found 24 diagnostics
+ Found 25 diagnostics

schemathesis (https://github.com/schemathesis/schemathesis)
- src/schemathesis/config/_projects.py:534:9: error[invalid-assignment] Object of type `Unknown` is not assignable to attribute `_parent` on type `T@from_hierarchy | Unknown`
- Found 321 diagnostics
+ Found 320 diagnostics

mitmproxy (https://github.com/mitmproxy/mitmproxy)
- test/mitmproxy/contentviews/test__utils.py:23:38: error[invalid-argument-type] Argument to function `make_metadata` is incorrect: Expected `Message | TCPMessage | UDPMessage | WebSocketMessage | DNSMessage`, found `Response | None`
+ test/mitmproxy/contentviews/test__utils.py:23:38: error[invalid-argument-type] Argument to function `make_metadata` is incorrect: Expected `ContentviewMessage`, found `Response | None`

schema_salad (https://github.com/common-workflow-language/schema_salad)
- schema_salad/sourceline.py:17:33: error[invalid-argument-type] Argument to function `_add_lc_filename` is incorrect: Argument type `AnyStr@_add_lc_filename` does not satisfy constraints (`str`, `bytes`) of type variable `AnyStr`
- schema_salad/sourceline.py:20:33: error[invalid-argument-type] Argument to function `_add_lc_filename` is incorrect: Argument type `AnyStr@_add_lc_filename` does not satisfy constraints (`str`, `bytes`) of type variable `AnyStr`
- Found 166 diagnostics
+ Found 164 diagnostics

xarray (https://github.com/pydata/xarray)
- xarray/backends/api.py:1362:42: error[invalid-argument-type] Argument to function `_remove_path` is incorrect: Expected `NestedSequence[_FLike@_remove_path]`, found `(_FLike@_remove_path & Top[list[Unknown]]) | (NestedSequence[_FLike@_remove_path] & Top[list[Unknown]])`
+ xarray/tests/test_namedarray.py:449:19: error[no-matching-overload] No overload of bound method `_new` matches arguments

meson (https://github.com/mesonbuild/meson)
- mesonbuild/modules/hotdoc.py:52:12: error[invalid-return-type] Return type does not match returned value: expected `list[_T@ensure_list]`, found `(_T@ensure_list & Top[list[Unknown]]) | list[_T@ensure_list]`
- Found 887 diagnostics
+ Found 886 diagnostics

vision (https://github.com/pytorch/vision)
- references/detection/coco_utils.py:165:60: warning[possibly-unresolved-reference] Name `keypoints` used when possibly not defined
- Found 1481 diagnostics
+ Found 1480 diagnostics

mkdocs (https://github.com/mkdocs/mkdocs)
- mkdocs/config/config_options.py:219:20: error[invalid-return-type] Return type does not match returned value: expected `list[T@ListOfItems]`, found `Top[list[Unknown]] & ~AlwaysTruthy`
- Found 206 diagnostics
+ Found 205 diagnostics

prefect (https://github.com/PrefectHQ/prefect)
+ src/prefect/_internal/concurrency/api.py:39:16: warning[redundant-cast] Value is already of type `Call[T@cast_to_call]`
- src/prefect/states.py:365:16: error[invalid-return-type] Return type does not match returned value: expected `State[R@return_value_to_state]`, found `R@return_value_to_state & Top[State[Any]]`

openlibrary (https://github.com/internetarchive/openlibrary)
+ openlibrary/book_providers.py:747:9: error[invalid-argument-type] Argument to function `multisort_best` is incorrect: Expected `list[tuple[Literal["min", "max"], (@Todo, /) -> int | float]]`, found `list[Unknown | tuple[str, (rec) -> Unknown]]`
- Found 862 diagnostics
+ Found 863 diagnostics

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- ddtrace/contrib/internal/pymongo/client.py:340:68: warning[possibly-unresolved-reference] Name `cursor` used when possibly not defined
- Found 7593 diagnostics
+ Found 7592 diagnostics

ibis (https://github.com/ibis-project/ibis)
- ibis/util.py:107:16: error[invalid-return-type] Return type does not match returned value: expected `list[V@promote_list]`, found `(V@promote_list & Top[list[Unknown]]) | (Iterable[V@promote_list] & Top[list[Unknown]])`
- Found 3293 diagnostics
+ Found 3292 diagnostics

bokeh (https://github.com/bokeh/bokeh)
- src/bokeh/core/property/container.py:136:24: error[invalid-return-type] Return type does not match returned value: expected `PropertyValueList[T@List]`, found `list[T@List] & Top[PropertyValueList[Unknown]]`
- src/bokeh/core/property/container.py:161:24: error[invalid-return-type] Return type does not match returned value: expected `PropertyValueSet[T@Set]`, found `set[T@Set] & Top[PropertyValueSet[Unknown]]`
- src/bokeh/layouts.py:668:24: error[invalid-return-type] Return type does not match returned value: expected `list[L@_parse_children_arg]`, found `(L@_parse_children_arg & Top[list[Unknown]]) | list[L@_parse_children_arg]`
- Found 450 diagnostics
+ Found 447 diagnostics

pandas (https://github.com/pandas-dev/pandas)
- pandas/core/frame.py:2170:16: error[invalid-return-type] Return type does not match returned value: expected `MutableMappingT@to_dict | list[MutableMappingT@to_dict]`, found `@Todo | MutableMappingT@to_dict | <class 'dict'> | list[@Todo | MutableMappingT@to_dict | <class 'dict'>]`
- Found 3391 diagnostics
+ Found 3390 diagnostics

jax (https://github.com/google/jax)
- jax/_src/pallas/fuser/block_spec.py:1517:39: error[non-subscriptable] Cannot subscript object of type `None` with no `__getitem__` method
- Found 2397 diagnostics
+ Found 2396 diagnostics

sympy (https://github.com/sympy/sympy)
- sympy/functions/combinatorial/numbers.py:3193:61: warning[possibly-unresolved-reference] Name `s` used when possibly not defined
- sympy/ntheory/factor_.py:148:43: warning[possibly-unresolved-reference] Name `facs` used when possibly not defined
- sympy/ntheory/factor_.py:148:43: warning[possibly-unresolved-reference] Name `facs` used when possibly not defined
- sympy/polys/rings.py:871:22: error[unresolved-attribute] Type `object` has no attribute `domain`
+ sympy/polys/rings.py:872:55: error[unresolved-attribute] Type `object` has no attribute `is_element`
- sympy/polys/rings.py:880:20: error[invalid-return-type] Return type does not match returned value: expected `PolyElement[Er@PolyElement] | PolyElement[PolyElement[Er@PolyElement]]`, found `Top[PolyElement[Unknown]]`
- sympy/polys/rings.py:931:22: error[unresolved-attribute] Type `object` has no attribute `domain`
+ sympy/polys/rings.py:932:55: error[unresolved-attribute] Type `object` has no attribute `is_element`
- sympy/polys/rings.py:940:20: error[invalid-return-type] Return type does not match returned value: expected `PolyElement[Er@PolyElement] | PolyElement[PolyElement[Er@PolyElement]]`, found `Top[PolyElement[Unknown]]`
- sympy/polys/rings.py:1008:22: error[unresolved-attribute] Type `object` has no attribute `domain`
+ sympy/polys/rings.py:1009:55: error[unresolved-attribute] Type `object` has no attribute `is_element`
+ sympy/polys/rings.py:1098:49: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
+ sympy/polys/rings.py:1133:46: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
+ sympy/polys/rings.py:1169:50: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
+ sympy/polys/rings.py:1206:50: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
- sympy/polys/rings.py:1017:20: error[invalid-return-type] Return type does not match returned value: expected `PolyElement[Er@PolyElement] | PolyElement[PolyElement[Er@PolyElement]]`, found `Top[PolyElement[Unknown]]`
- sympy/polys/rings.py:1095:28: error[unresolved-attribute] Type `object` has no attribute `domain`
- sympy/polys/rings.py:1096:21: error[unresolved-attribute] Type `object` has no attribute `domain`
- sympy/polys/rings.py:1130:28: error[unresolved-attribute] Type `object` has no attribute `domain`
- sympy/polys/rings.py:1131:21: error[unresolved-attribute] Type `object` has no attribute `domain`
- sympy/polys/rings.py:1166:28: error[unresolved-attribute] Type `object` has no attribute `domain`
- sympy/polys/rings.py:1167:21: error[unresolved-attribute] Type `object` has no attribute `domain`
- sympy/polys/rings.py:1203:28: error[unresolved-attribute] Type `object` has no attribute `domain`
- sympy/polys/rings.py:1204:21: error[unresolved-attribute] Type `object` has no attribute `domain`
- sympy/polys/rings.py:3456:17: error[unsupported-operator] Operator `*` is unsupported between objects of type `PolyElement[Er@PolyElement] | Unknown` and `Unknown | PolyElement[Er@PolyElement] | int | float`
- Found 11057 diagnostics
+ Found 11046 diagnostics

core (https://github.com/home-assistant/core)
- homeassistant/auth/permissions/merge.py:63:13: error[invalid-assignment] Method `__setitem__` of type `bound method Top[dict[Unknown, Unknown]].__setitem__(key: Never, value: Never, /) -> None` cannot be called with a key of type `Never` and a value of type `Mapping[str, Mapping[str, Mapping[str, bool] | bool | None] | bool | None] | bool | None` on object of type `Mapping[str, SubCategoryType] & Top[dict[Unknown, Unknown]]`
+ homeassistant/auth/permissions/merge.py:63:13: error[invalid-assignment] Method `__setitem__` of type `bound method Top[dict[Unknown, Unknown]].__setitem__(key: Never, value: Never, /) -> None` cannot be called with a key of type `Never` and a value of type `CategoryType` on object of type `Mapping[str, SubCategoryType] & Top[dict[Unknown, Unknown]]`
- homeassistant/components/google_assistant/report_state.py:164:54: error[invalid-argument-type] Argument to function `create_checker` is incorrect: Expected `((HomeAssistant, str, dict[Unknown, Unknown] | MappingProxyType[Unknown, Unknown], Any, str, dict[Unknown, Unknown] | MappingProxyType[Unknown, Unknown], Any, /) -> bool | None) | None`, found `def extra_significant_check(hass: HomeAssistant, old_state: str, old_attrs: dict[Unknown, Unknown], old_extra_arg: dict[Unknown, Unknown], new_state: str, new_attrs: dict[Unknown, Unknown], new_extra_arg: dict[Unknown, Unknown]) -> Unknown`
+ homeassistant/components/google_assistant/report_state.py:164:54: error[invalid-argument-type] Argument to function `create_checker` is incorrect: Expected `ExtraCheckTypeFunc | None`, found `def extra_significant_check(hass: HomeAssistant, old_state: str, old_attrs: dict[Unknown, Unknown], old_extra_arg: dict[Unknown, Unknown], new_state: str, new_attrs: dict[Unknown, Unknown], new_extra_arg: dict[Unknown, Unknown]) -> Unknown`
- homeassistant/components/otbr/__init__.py:40:57: error[invalid-argument-type] Argument to function `async_register_firmware_info_provider` is incorrect: Expected `SyncHardwareFirmwareInfoModule | AsyncHardwareFirmwareInfoModule`, found `<module 'homeassistant.components.otbr.homeassistant_hardware'>`
+ homeassistant/components/otbr/__init__.py:40:57: error[invalid-argument-type] Argument to function `async_register_firmware_info_provider` is incorrect: Expected `HardwareFirmwareInfoModule`, found `<module 'homeassistant.components.otbr.homeassistant_hardware'>`
- homeassistant/components/owntracks/__init__.py:148:9: error[invalid-assignment] Method `__setitem__` of type `(bound method dict[str, Any].__setitem__(key: str, value: Any, /) -> None) | (Overload[(key: SupportsIndex, value: Any, /) -> None, (key: slice[Any, Any, Any], value: Iterable[Any], /) -> None])` cannot be called with a key of type `Literal["topic"]` and a value of type `Unknown` on object of type `dict[str, Any] | list[Any] | str | ... omitted 3 union elements`
+ homeassistant/components/owntracks/__init__.py:148:9: error[invalid-assignment] Method `__setitem__` of type `(bound method JsonValueType.__setitem__(key: str, value: dict[str, Any] | list[Any] | str | ... omitted 3 union elements, /) -> None) | (Overload[(key: SupportsIndex, value: dict[str, Any] | list[Any] | str | ... omitted 3 union elements, /) -> None, (key: slice[Any, Any, Any], value: Iterable[dict[str, Any] | list[Any] | str | ... omitted 3 union elements], /) -> None])` cannot be called with a key of type `Literal["topic"]` and a value of type `Unknown` on object of type `JsonValueType`
- homeassistant/components/random/config_flow.py:113:82: warning[possibly-unresolved-reference] Name `units` used when possibly not defined
- homeassistant/components/random/config_flow.py:113:82: warning[possibly-unresolved-reference] Name `units` used when possibly not defined
- homeassistant/components/template/config_flow.py:433:82: warning[possibly-unresolved-reference] Name `units` used when possibly not defined
- homeassistant/components/template/config_flow.py:433:82: warning[possibly-unresolved-reference] Name `units` used when possibly not defined
- homeassistant/components/template/config_flow.py:457:54: warning[possibly-unresolved-reference] Name `state_classes` used when possibly not defined
- homeassistant/components/template/config_flow.py:457:54: warning[possibly-unresolved-reference] Name `state_classes` used when possibly not defined
- homeassistant/components/zha/__init__.py:118:57: error[invalid-argument-type] Argument to function `async_register_firmware_info_provider` is incorrect: Expected `SyncHardwareFirmwareInfoModule | AsyncHardwareFirmwareInfoModule`, found `<module 'homeassistant.components.zha.homeassistant_hardware'>`
+ homeassistant/components/zha/__init__.py:118:57: error[invalid-argument-type] Argument to function `async_register_firmware_info_provider` is incorrect: Expected `HardwareFirmwareInfoModule`, found `<module 'homeassistant.components.zha.homeassistant_hardware'>`
+ homeassistant/core.py:1527:48: error[invalid-argument-type] Argument to function `_event_repr` is incorrect: Expected `EventType[Mapping[str, Any]] | str`, found `EventType[_DataT@async_fire_internal] | str`
+ homeassistant/core.py:1547:17: error[invalid-assignment] Object of type `Event[Mapping[str, Any]]` is not assignable to `Event[_DataT@async_fire_internal] | None`
+ homeassistant/core.py:1548:21: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `EventType[Mapping[str, Any]] | str`, found `EventType[_DataT@async_fire_internal] | str`
- homeassistant/helpers/singleton.py:83:12: error[invalid-return-type] Return type does not match returned value: expected `(_FuncType, /) -> _FuncType`, found `Overload[(func: (HomeAssistant, /) -> Coroutine[Any, Any, _T@singleton]) -> (HomeAssistant, /) -> Coroutine[Any, Any, _T@singleton], (func: (HomeAssistant, /) -> _U@singleton) -> (HomeAssistant, /) -> _U@singleton]`
+ homeassistant/helpers/singleton.py:83:12: error[invalid-return-type] Return type does not match returned value: expected `(_FuncType, /) -> _FuncType`, found `Overload[(func: _FuncType) -> _FuncType, (func: _FuncType) -> _FuncType]`
+ homeassistant/util/hass_dict.pyi:146:5: error[type-assertion-failure] Argument does not have asserted type `dict[str, int]`
+ homeassistant/util/hass_dict.pyi:147:5: error[type-assertion-failure] Argument does not have asserted type `int`
+ homeassistant/util/hass_dict.pyi:155:62: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
+ homeassistant/util/hass_dict.pyi:170:5: error[type-assertion-failure] Argument does not have asserted type `dict[str, int]`
- Found 13760 diagnostics
+ Found 13761 diagnostics
Memory usage changes were detected when running on open source projects
trio (https://github.com/python-trio/trio)
-     struct metadata = ~9MB
+     struct metadata = ~8MB

@github-actions
Copy link
Contributor

github-actions bot commented Oct 2, 2025

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-argument-type 5 5 4
unresolved-attribute 3 11 0
invalid-return-type 0 12 1
no-matching-overload 1 11 0
unused-ignore-comment 5 0 0
invalid-assignment 1 1 2
type-assertion-failure 3 0 0
redundant-cast 1 0 0
unsupported-operator 0 1 0
Total 19 41 7

Full report with detailed diff (timing results)

@dcreager dcreager force-pushed the dcreager/non-non-inferable branch from 6bc7ceb to 417caf0 Compare October 2, 2025 18:11
Base automatically changed from dcreager/non-inherited to main October 3, 2025 17:55
@dcreager dcreager force-pushed the dcreager/non-non-inferable branch from 417caf0 to 7b5684f Compare October 3, 2025 19:05
@dcreager
Copy link
Member Author

dcreager commented Oct 3, 2025

ecosystem analysis:

Several projects have removed diagnostics, which look like correct better understanding of the types involved:

  • hauntsaninja/boostedblob
  • homeassistant/core
  • cwltool
  • jax
  • meson
  • pytest
  • schema_salad
  • scikit-build-core
  • strawberry
  • werkzeug
  • xarray

Still looking at some of the new diagnostics. It also looks like we aren't expanding type aliases in as many places as before.

@dcreager dcreager force-pushed the dcreager/non-non-inferable branch from 7a69d29 to df385d2 Compare October 7, 2025 12:59
@dcreager dcreager force-pushed the dcreager/non-non-inferable branch from f11b47c to 74cc6b7 Compare October 7, 2025 16:54
@dcreager dcreager changed the base branch from main to dcreager/union-none October 7, 2025 16:54
Base automatically changed from dcreager/union-none to main October 7, 2025 17:33
@dcreager dcreager force-pushed the dcreager/non-non-inferable branch from 74cc6b7 to 6d12c00 Compare October 7, 2025 17:34
@dcreager dcreager force-pushed the dcreager/non-non-inferable branch from a2266c0 to 5f708ba Compare October 8, 2025 13:53
@codspeed-hq
Copy link

codspeed-hq bot commented Oct 8, 2025

CodSpeed Performance Report

Merging #20677 will improve performances by 4.49%

Comparing dcreager/non-non-inferable (0997627) with main (1ade4f2)

Summary

⚡ 1 improvement
✅ 20 untouched
⏩ 30 skipped1

Benchmarks breakdown

Mode Benchmark BASE HEAD Change
Instrumentation hydra-zen 784.1 ms 750.3 ms +4.49%

Footnotes

  1. 30 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@dcreager dcreager changed the base branch from main to dcreager/non-inferable-api October 14, 2025 14:54
@dcreager dcreager marked this pull request as ready for review October 14, 2025 19:28
@dcreager
Copy link
Member Author

The remaining ecosystem additions seem related to bidi checking of arguments and overload resolution. This overlaps with some of the work @ibraheemdev is doing e.g. in #20796, so for now, I'm opening this up for review, and would like to address the remaining ecosystem results with him as part of that work.

@dcreager
Copy link
Member Author

(Note that I pulled the pure refactoring part of this PR out into a separate #20865, so that it's easier to review the logic changes separate from the boilerplate API changes. Please review 20865 first)

dcreager added a commit that referenced this pull request Oct 15, 2025
)

A large part of the diff on #20677 just involves threading a new
`inferable` parameter through all of the type property methods. In the
interests of making that PR easier to review, I've pulled that bit out
into here, so that it can be reviewed in isolation. This should be a
pure refactoring, with no logic changes or behavioral changes.
Base automatically changed from dcreager/non-inferable-api to main October 15, 2025 13:05
…rable

* origin/main:
  [ty] Add (unused) `inferable` parameter to type property methods (#20865)
  Run macos tests on macos (#20889)
  Remove `release` CI job (#20887)
  [ty] CI: Faster ecosystem analysis (#20886)
  Remove `strip` from release profile (#20885)
  [ty] Sync vendored typeshed stubs (#20876)
  [ty] Add some completion ranking improvements (#20807)
  Improved error recovery for unclosed strings (including f- and t-strings) (#20848)
  Enable lto=fat (#20863)
  [`pyupgrade`] Extend `UP019` to detect `typing_extensions.Text` (`UP019`) (#20825)
  [`flake8-bugbear`] Omit annotation in preview fix for `B006` (#20877)
  fix(docs): Fix typo in `RUF015` description (#20873)
  [ty] Improve and extend tests for instance attributes redeclared in subclasses (#20866)
  [ty] Ignore slow seeds as a temporary measure (#20870)
  Remove parentheses around multiple exception types on Python 3.14+ (#20768)
  Update Black tests (#20794)
…rable

* origin/main:
  Don't use codspeed or depot runners in CI jobs on forks (#20894)
  [ty] cache Type::is_redundant_with (#20477)
  Fix run-away for mutually referential instance attributes (#20645)
  [ty] Limit shown import paths to at most 5 unless ty runs with `-v` (#20912)
  [ty] Use field-specifier return type as the default type for the field (#20915)
  [ty] Do not assume that `field`s have a default value (#20914)
  [ty] Fix match pattern value narrowing to use equality semantics (#20882)
  Update setup instructions for Zed 0.208.0+ (#20902)
  Move TOML indent size config (#20905)
  [syntax-errors]: implement F702 as semantic syntax error (#20869)
  [ty] Heterogeneous unpacking support for unions (#20377)
  [ty] refactor `Place` (#20871)
  Auto-accept snapshot changes as part of typeshed-sync PRs (#20892)
  [`airflow`] Add warning to `airflow.datasets.DatasetEvent` usage (`AIR301`) (#20551)
  [`flake8-pyi`] Fix operator precedence by adding parentheses when needed (`PYI061`) (#20508)
  [`pyupgrade`] Fix false negative for `TypeVar` with default argument in `non-pep695-generic-class` (`UP046`) (#20660)
  Update parser snapshots (#20893)
  Fix syntax error false positives for escapes and quotes in f-strings (#20867)
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Looks great, thank you! Very relieved that I no longer have to worry about the differences between these two variants!

There's a couple of places where it looks like our behaviour is changing subtly, where I wonder if we could add regression tests if the new behaviour is desirable? Especially if this is the cause of the changes in the ecosystem. But if that's hard to do, then no need to spend too much time on it

Comment on lines 319 to 331
#[salsa::tracked(
returns(ref),
cycle_fn=inferable_typevars_cycle_recover,
cycle_initial=inferable_typevars_cycle_initial,
heap_size=ruff_memory_usage::heap_size,
)]
fn inferable_typevars_inner(self, db: &'db dyn Db) -> FxHashSet<BoundTypeVarIdentity<'db>> {
// The second inner function is because the salsa macros seem to not like nested structs
// and impl blocks inside the function.
self.inferable_typevars_innerer(db)
}

fn inferable_typevars_innerer(self, db: &'db dyn Db) -> FxHashSet<BoundTypeVarIdentity<'db>> {
Copy link
Member

Choose a reason for hiding this comment

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

lol. Is it worth nesting these methods inside the inferable_typevars method, so that it's obvious to readers that they're implementation details of that method?

Copy link
Member

Choose a reason for hiding this comment

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

Do you remember what the issue was here? Might be worth opening a Salsa issue, the macros should be relatively transparent.

Copy link
Member Author

Choose a reason for hiding this comment

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

Putting innerer inside of inner didn't work, but I don't remember the specific error. Put all of it inside of the outer function works, though, since the type and impl block don't need to be inside the salsa-tracked function that way.

Copy link
Member

@ibraheemdev ibraheemdev left a comment

Choose a reason for hiding this comment

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

Very nice!

@dcreager
Copy link
Member Author

The performance analysis keeps bouncing back and forth between being a regression and an improvement as I rebase to pick up more changes from main. 😠

@AlexWaygood
Copy link
Member

The performance analysis keeps bouncing back and forth between being a regression and an improvement as I rebase to pick up more changes from main. 😠

the DateType benchmark does move quite a lot in general because it's a small codebase that has some very expensive subtype checks in it. (We originally added it because an early version of one of my protocol PRs would have meant that we never finished type-checking DateType 🙃)

So DateType is just very sensitive to small changes in efficiency of subtype checks between the specific types that are being used in that codebase. It looks like this PR is still a performance improvement on hydra-zen, which is a much bigger codebase!

…rable

* origin/main:
  [ty] Support dataclass-transform `field_specifiers` (#20888)
  Bump 0.14.1 (#20925)
  Standardize syntax error construction (#20903)
  [`pydoclint`] Implement `docstring-extraneous-parameter` (`DOC102`) (#20376)
  [ty] Fix panic 'missing root' when handling completion request (#20917)
  [ty] Run file watching tests serial when using nextest (#20918)
  [ty] Add version hint for failed stdlib attribute accesses (#20909)
  More CI improvements (#20920)
  [ty] Check typeshed VERSIONS for parent modules when reporting failed stdlib imports (#20908)
…rable

* origin/main:
  [ty] Avoid unnecessarily widening generic specializations (#20875)
@dcreager dcreager merged commit b0e10a9 into main Oct 16, 2025
41 checks passed
@dcreager dcreager deleted the dcreager/non-non-inferable branch October 16, 2025 19:59
dcreager added a commit that referenced this pull request Oct 17, 2025
* main:
  [ty] Prefer declared type for invariant collection literals (#20927)
  [ty] Don't track inferability via different `Type` variants (#20677)
  [ty] Use declared variable types as bidirectional type context (#20796)
  [ty] Avoid unnecessarily widening generic specializations (#20875)
  [ty] Support dataclass-transform `field_specifiers` (#20888)
  Bump 0.14.1 (#20925)
  Standardize syntax error construction (#20903)
  [`pydoclint`] Implement `docstring-extraneous-parameter` (`DOC102`) (#20376)
  [ty] Fix panic 'missing root' when handling completion request (#20917)
  [ty] Run file watching tests serial when using nextest (#20918)
  [ty] Add version hint for failed stdlib attribute accesses (#20909)
  More CI improvements (#20920)
  [ty] Check typeshed VERSIONS for parent modules when reporting failed stdlib imports (#20908)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ecosystem-analyzer internal An internal refactor or improvement ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants