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

Skip to content

[ty] Avoid redundant solve for empty collection context#25527

Merged
carljm merged 1 commit into
mainfrom
cjm/empty-collection-context-fast-path
Jun 1, 2026
Merged

[ty] Avoid redundant solve for empty collection context#25527
carljm merged 1 commit into
mainfrom
cjm/empty-collection-context-fast-path

Conversation

@carljm

@carljm carljm commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Avoid building and solving a SpecializationBuilder constraint set for an empty collection literal when contextual inference has already provided its complete specialization.

For this case, directly apply the contextual specialization and return the resulting collection instance.

Motivation

Profiling pydantic exposed an expensive path for empty collection literals with large contextual types. Even when the context completely determines the collection type variables and the literal has no elements that could add information, inference continued through constraint projection and solving.

This is especially expensive for pydantic's large schema unions.

Validation

Existing tests pass, no ecosystem diagnostic changes.

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

astral-sh-bot Bot commented Jun 1, 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 91.94%. The percentage of expected errors that received a diagnostic held steady at 87.09%. The number of fully passing files held steady at 92/134.

@astral-sh-bot

astral-sh-bot Bot commented Jun 1, 2026

Copy link
Copy Markdown

Memory usage report

Summary

Project Old New Diff Outcome
flake8 43.16MB 43.16MB -0.01% (2.24kB) ⬇️
trio 107.20MB 107.19MB -0.01% (9.37kB) ⬇️
sphinx 256.42MB 256.36MB -0.03% (67.07kB) ⬇️
prefect 691.74MB 691.61MB -0.02% (125.60kB) ⬇️

Significant changes

Click to expand detailed breakdown

flake8

Name Old New Diff Outcome
infer_expression_types_impl 1.09MB 1.09MB -0.16% (1.77kB) ⬇️
infer_scope_types_impl 868.20kB 867.80kB -0.05% (408.00B) ⬇️
infer_definition_types 1.78MB 1.78MB -0.00% (72.00B) ⬇️

trio

Name Old New Diff Outcome
infer_expression_types_impl 6.76MB 6.76MB -0.06% (3.91kB) ⬇️
infer_definition_types 7.40MB 7.40MB -0.04% (3.40kB) ⬇️
when_constraint_set_assignable_to_owned_impl 624.71kB 623.54kB -0.19% (1.17kB) ⬇️
when_constraint_set_assignable_to_owned_impl::interned_arguments 183.39kB 182.53kB -0.47% (880.00B) ⬇️
infer_scope_types_impl 4.12MB 4.12MB -0.00% (24.00B) ⬇️

sphinx

Name Old New Diff Outcome
infer_expression_types_impl 21.97MB 21.93MB -0.19% (43.04kB) ⬇️
infer_definition_types 23.39MB 23.38MB -0.07% (17.50kB) ⬇️
when_constraint_set_assignable_to_owned_impl 2.41MB 2.41MB -0.08% (1.99kB) ⬇️
infer_scope_types_impl 13.43MB 13.42MB -0.01% (1.68kB) ⬇️
when_constraint_set_assignable_to_owned_impl::interned_arguments 714.31kB 712.85kB -0.20% (1.46kB) ⬇️
IntersectionType 540.39kB 540.03kB -0.07% (368.00B) ⬇️
is_redundant_with_impl::interned_arguments 1.16MB 1.16MB -0.02% (264.00B) ⬇️
UnionType 647.70kB 647.47kB -0.04% (240.00B) ⬇️
is_redundant_with_impl 991.30kB 991.10kB -0.02% (204.00B) ⬇️
infer_expression_type_impl 3.01MB 3.01MB -0.00% (144.00B) ⬇️
Type<'db>::member_lookup_with_policy_ 7.28MB 7.28MB -0.00% (72.00B) ⬇️
infer_deferred_types 4.82MB 4.82MB -0.00% (72.00B) ⬇️
StaticClassLiteral<'db>::implicit_attribute_inner_ 2.39MB 2.39MB -0.00% (72.00B) ⬇️

prefect

Name Old New Diff Outcome
infer_expression_types_impl 60.49MB 60.43MB -0.09% (56.55kB) ⬇️
infer_definition_types 88.44MB 88.40MB -0.05% (45.22kB) ⬇️
infer_scope_types_impl 50.65MB 50.64MB -0.02% (9.40kB) ⬇️
when_constraint_set_assignable_to_owned_impl 4.88MB 4.87MB -0.10% (5.04kB) ⬇️
when_constraint_set_assignable_to_owned_impl::interned_arguments 1.52MB 1.52MB -0.24% (3.70kB) ⬇️
is_redundant_with_impl::interned_arguments 2.36MB 2.36MB -0.08% (1.98kB) ⬇️
is_redundant_with_impl 2.16MB 2.16MB -0.06% (1.39kB) ⬇️
IntersectionType 970.91kB 969.77kB -0.12% (1.14kB) ⬇️
UnionType 1.32MB 1.32MB -0.05% (752.00B) ⬇️
infer_deferred_types 10.40MB 10.40MB -0.00% (456.00B) ⬇️

@astral-sh-bot

astral-sh-bot Bot commented Jun 1, 2026

Copy link
Copy Markdown

ecosystem-analyzer results

No diagnostic changes detected ✅

Large timing changes:

Project Old Time New Time Change
pydantic 2.11s 0.79s -62%

Full report with detailed diff (timing results)

@codspeed-hq

codspeed-hq Bot commented Jun 1, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by ×2.2

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 3 improved benchmarks
✅ 62 untouched benchmarks
⏩ 60 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation ty_micro[pydantic_core_schema_dict] 424.6 ms 94.8 ms ×4.5
WallTime pydantic 34.7 s 16.9 s ×2
Memory ty_micro[pydantic_core_schema_dict] 19.5 MB 16.3 MB +19.73%

Tip

Curious why this is faster? Use the CodSpeed MCP and ask your agent.


Comparing cjm/empty-collection-context-fast-path (461b9bd) with main (b82dfe7)

Open in CodSpeed

Footnotes

  1. 60 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.

@carljm carljm force-pushed the cjm/empty-collection-context-fast-path branch from addf82c to 461b9bd Compare June 1, 2026 17:14
@carljm carljm marked this pull request as ready for review June 1, 2026 18:04
@AlexWaygood AlexWaygood added the performance Potential performance improvement label Jun 1, 2026
Comment on lines +6601 to +6604
// Keep this parallel with the slow path below: a covariant context provides
// only an upper bound, which does not determine the specialization for an empty
// literal. A contravariant context provides a lower bound, for which inference
// selects the narrowest valid solution.

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.

It would be nice to not have to keep this consistent manually, but I don't see an easy way to do that that doesn't introduce more complexity than it removes...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. On the plus side, it seems like something that's unlikely to change?

@carljm carljm merged commit ec248a2 into main Jun 1, 2026
59 checks passed
@carljm carljm deleted the cjm/empty-collection-context-fast-path branch June 1, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants