Skip to content

[ty] Avoid duplicated work during multi-inference#23923

Merged
ibraheemdev merged 2 commits intomainfrom
ibraheem/speculative-inference
Mar 13, 2026
Merged

[ty] Avoid duplicated work during multi-inference#23923
ibraheemdev merged 2 commits intomainfrom
ibraheem/speculative-inference

Conversation

@ibraheemdev
Copy link
Member

Instead of ignoring intermediate inference results, we can create a temporary TypeInferenceBuilder and merge the chosen inference results into the current region. This should hopefully reclaim some of the performance regressions introduced by #23844 and #21210.

@ibraheemdev ibraheemdev added performance Potential performance improvement ty Multi-file analysis & type inference labels Mar 12, 2026
@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 12, 2026

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 85.29%. The percentage of expected errors that received a diagnostic held steady at 78.13%. The number of fully passing files held steady at 64/132.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 12, 2026

Memory usage report

Summary

Project Old New Diff Outcome
trio 117.74MB 117.74MB -0.00% (384.00B) ⬇️
flake8 47.89MB 47.89MB -0.00% (700.00B) ⬇️
sphinx 265.10MB 265.10MB -0.00% (5.26kB) ⬇️
prefect 705.00MB 704.98MB -0.00% (24.43kB) ⬇️

Significant changes

Click to expand detailed breakdown

trio

Name Old New Diff Outcome
IntersectionType<'db>::from_two_elements_::interned_arguments 57.23kB 57.06kB -0.30% (176.00B) ⬇️
IntersectionType<'db>::from_two_elements_ 63.66kB 63.52kB -0.21% (136.00B) ⬇️
infer_definition_types 7.57MB 7.57MB -0.00% (72.00B) ⬇️

flake8

Name Old New Diff Outcome
infer_expression_types_impl 1.07MB 1.07MB -0.03% (376.00B) ⬇️
IntersectionType<'db>::from_two_elements_::interned_arguments 20.62kB 20.45kB -0.83% (176.00B) ⬇️
IntersectionType<'db>::from_two_elements_ 19.44kB 19.30kB -0.74% (148.00B) ⬇️

sphinx

Name Old New Diff Outcome
IntersectionType<'db>::from_two_elements_::interned_arguments 173.94kB 172.22kB -0.99% (1.72kB) ⬇️
IntersectionType<'db>::from_two_elements_ 204.88kB 203.44kB -0.71% (1.45kB) ⬇️
infer_expression_types_impl 21.50MB 21.50MB -0.00% (536.00B) ⬇️
infer_scope_types_impl 15.57MB 15.57MB -0.00% (480.00B) ⬇️
infer_definition_types 24.01MB 24.01MB -0.00% (384.00B) ⬇️
is_redundant_with_impl::interned_arguments 2.06MB 2.06MB -0.02% (352.00B) ⬇️
IntersectionType 893.17kB 892.98kB -0.02% (200.00B) ⬇️
is_redundant_with_impl 1.80MB 1.80MB -0.01% (192.00B) ⬇️

prefect

Name Old New Diff Outcome
is_redundant_with_impl 5.57MB 5.57MB -0.13% (7.57kB) ⬇️
IntersectionType<'db>::from_two_elements_ 345.92kB 341.10kB -1.39% (4.82kB) ⬇️
is_redundant_with_impl::interned_arguments 5.36MB 5.35MB -0.07% (3.87kB) ⬇️
IntersectionType 2.31MB 2.31MB -0.12% (2.73kB) ⬇️
infer_expression_types_impl 60.74MB 60.74MB -0.00% (1.68kB) ⬇️
IntersectionType<'db>::from_two_elements_::interned_arguments 341.43kB 339.80kB -0.48% (1.63kB) ⬇️
infer_scope_types_impl 52.93MB 52.93MB -0.00% (840.00B) ⬇️
UnionType 3.46MB 3.46MB -0.02% (672.00B) ⬇️
infer_definition_types 88.85MB 88.85MB -0.00% (656.00B) ⬇️

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 12, 2026

mypy_primer results

Changes were detected when running on open source projects
pydantic (https://github.com/pydantic/pydantic)
- pydantic/_internal/_core_metadata.py:87:54: error[invalid-assignment] Invalid assignment to key "pydantic_js_extra" with declared type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | ((dict[str, Divergent], type[Any], /) -> None)` on TypedDict `CoreMetadata`: value of type `dict[object, object]`
+ pydantic/_internal/_core_metadata.py:87:54: error[invalid-assignment] Invalid assignment to key "pydantic_js_extra" with declared type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | ((dict[str, int | float | str | ... omitted 3 union elements], type[Any], /) -> None)` on TypedDict `CoreMetadata`: value of type `dict[object, object]`
- pydantic/fields.py:949:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:949:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:989:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:989:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1032:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1032:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1072:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1072:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1115:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1115:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1154:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1154:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1194:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1194:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1573:13: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`, found `dict[str, Divergent] | dict[Never, Never] | (((dict[str, Divergent], /) -> None) & ~Top[dict[Unknown, Unknown]]) | None`
+ pydantic/fields.py:1573:13: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`, found `dict[str, int | float | str | ... omitted 3 union elements] | dict[Never, Never] | (((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) & ~Top[dict[Unknown, Unknown]]) | None`

ibis (https://github.com/ibis-project/ibis)
+ ibis/expr/datatypes/tests/test_value.py:77:56: error[missing-argument] No argument provided for required parameter `value_type`
+ ibis/expr/datatypes/tests/test_value.py:77:65: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `Float64`
+ ibis/tests/expr/test_value_exprs.py:1102:50: error[invalid-argument-type] Argument is incorrect: Expected `IntervalUnit`, found `Literal["D"]`
- Found 4889 diagnostics
+ Found 4892 diagnostics

@codspeed-hq
Copy link

codspeed-hq bot commented Mar 12, 2026

Merging this PR will not alter performance

✅ 26 untouched benchmarks
⏩ 30 skipped benchmarks1


Comparing ibraheem/speculative-inference (8ea2caa) with main (a9a544c)

Open in CodSpeed

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.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 12, 2026

ecosystem-analyzer results

No diagnostic changes detected ✅

Full report with detailed diff (timing results)

@@ -4993,11 +4992,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
MultiInferenceState::Ignore,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this correct after the changes in this PR? Doesn't this mean that when we .extend() below, if speculative inference succeeded, we still won't get the expression types, causing Unknown hover results on some argument expressions?

I'm able to reproduce that with this example code:

from typing import TypeVar

T = TypeVar("T")

def list1(x: T) -> list[T]:
    return [x]

def f() -> list[int] | list[str]:
    return list1(1 + 2)

we lose hover expression types on 1 + 2 with this PR. We should probably add this as a hover test?

Is this new speculative-inference usable in all cases where we currently use MultiInferenceState? Could it replace it entirely?

Copy link
Member Author

@ibraheemdev ibraheemdev Mar 13, 2026

Choose a reason for hiding this comment

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

Is this new speculative-inference usable in all cases where we currently use MultiInferenceState? Could it replace it entirely?

I think so, and I hope that to be the result of these incremental refactors. MultiInferenceState::Ignore is a little ugly in that it breaks the interal invariant of that all expression types are stored for a given inference.

@ibraheemdev ibraheemdev merged commit 37ef0b4 into main Mar 13, 2026
51 checks passed
@ibraheemdev ibraheemdev deleted the ibraheem/speculative-inference branch March 13, 2026 01:34
carljm added a commit that referenced this pull request Mar 13, 2026
* main: (94 commits)
  Fix shell injection via `shell=True` in subprocess calls (#23894)
  [ty] Refactor `relation.rs` to store state on a struct rather than passing around 7 arguments every time we recurse (#23837)
  Don't return code actions for non-Python documents (#23905)
  [ty] Make the default database truly statically infallible (#23929)
  [ty] Add `Download` button to ty playground which creates a zip export (#23478)
  [ty] Respect `kw_only` overwrites in dataclasses (#23930)
  [ty] Clarify in diagnostics that `from __future__ import annotations` only stringifies type annotations (#23928)
  [ty]  Add a `Copy Markdown` button to playground (#23002)
  [ty] Fix folding range classification of lines starting with `#` (#23831)
  [ty] Fix folding ranges for notebooks (#23830)
  [ty] fix too-many-cycle panics when inferring literal type loop variables (#23875)
  Add `RegularCallableTypeOf` and `into_regular_callable` in `ty_extensions` (#23909)
  [ty] treat properties as full structural types (#23925)
  [ty] Avoid duplicated work during multi-inference (#23923)
  [ty]: make `possibly-missing-attribute` ignored by default
  [ty]: split out `possibly-missing-submodule` from `possibly-missing-attribute`
  Update astral-sh/setup-uv action to v7.5.0 (#23922)
  [ty] Show truthiness in ConstraintSet display and simplify falsy error message (#23913)
  Bump 0.15.6 (#23919)
  [ty] Narrow type context during collection literal inference (#23844)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ecosystem-analyzer performance Potential performance improvement ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants