Skip to content

[ty] Experiment with canonical empty generic contexts - #29127

Draft
dhruvmanila wants to merge 1 commit into
mainfrom
dhruv/generic-context-experiment
Draft

dhruvmanila wants to merge 1 commit into
mainfrom
dhruv/generic-context-experiment

Conversation

@dhruvmanila

Copy link
Copy Markdown
Member

Option<GenericContext> permits two equivalent empty representations: None and Some(empty). Binding a callback method's sole Self variable can produce the latter while an equivalent direct callable carries the former, allowing equivalent constraint alternatives to remain distinct.

This experiments with GenericContext::{None, Some(GenericContextInner)}, following TypeVarSet. Normal construction APIs canonicalize empty collections to None; the interned inner value holds the program and ordered variables directly. Callers operate on GenericContext without an additional Option.

The purpose is feedback on this representation and whether it overlaps with planned generic-context work. This is independent of #28828, which uses a smaller normalization fix.

A nongeneric signature can carry either no generic context or an empty one,
for example after binding the only Self type variable. These representations
compare differently even though they describe the same signature, creating
redundant alternatives during constraint solving.

Represent GenericContext as None or Some(GenericContextInner), with the
construction APIs returning None for empty collections. Keep Program and the
ordered variables directly in the interned inner struct, and update callers
to handle the empty variant without retaining a separate Option wrapper.

Preserve the distinction between absent and incomplete PEP 695 syntax using
the existing class syntax flag. Adapt existing test helpers to the new API.
@dhruvmanila dhruvmanila added internal An internal refactor or improvement (not for changelogs) ty The ty type checker labels Oct 6, 2026
@dhruvmanila
dhruvmanila deployed to automations October 6, 2026 10:54 — with GitHub Actions Active
@astral-sh-bot

astral-sh-bot Bot commented Oct 6, 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 98.24%. The percentage of expected errors that received a diagnostic held steady at 98.24%. The number of fully passing files held steady at 134/146.

@astral-sh-bot

astral-sh-bot Bot commented Oct 6, 2026

Copy link
Copy Markdown

Memory usage report

Summary

Project Old New Diff Outcome
flake8 38.28MB 38.25MB -0.07% (29.24kB) ⬇️
trio 92.58MB 92.37MB -0.22% (207.82kB) ⬇️
sphinx 172.48MB 172.21MB -0.16% (283.43kB) ⬇️
prefect 475.76MB 474.98MB -0.16% (799.85kB) ⬇️

Significant changes

Click to expand detailed breakdown

flake8

Name Old New Diff Outcome
GenericContext 140.19kB 0.00B -100.00% (140.19kB) ⬇️
GenericContextInner 0.00B 114.87kB +114.87kB (new) ⏫
Type<'db>::apply_specialization_inner_::interned_arguments 146.64kB 144.77kB -1.28% (1.88kB) ⬇️
remove_self_inner 7.23kB 8.62kB +19.35% (1.40kB) ⏫
Type<'db>::apply_specialization_inner_ 96.03kB 94.91kB -1.17% (1.12kB) ⬇️
infer_definition_types 1.17MB 1.17MB -0.06% (768.00B) ⬇️
infer_scope_types_impl 536.76kB 536.35kB -0.08% (416.00B) ⬇️
infer_expression_types_impl 786.21kB 785.84kB -0.05% (376.00B) ⬇️
infer_unpack_types 27.09kB 26.81kB -1.04% (288.00B) ⬇️
all_narrowing_constraints_for_expression 74.72kB 74.61kB -0.15% (112.00B) ⬇️
TypeVarInference 56.71kB 56.61kB -0.18% (104.00B) ⬇️
remove_self_inner::interned_arguments 13.01kB 12.94kB -0.54% (72.00B) ⬇️
merged_specialization_inner 19.38kB 19.34kB -0.20% (40.00B) ⬇️
infer_expression_type_impl 20.34kB 20.30kB -0.19% (40.00B) ⬇️
member_lookup_with_policy_and_receiver_inner 58.24kB 58.20kB -0.07% (40.00B) ⬇️
... 7 more

trio

Name Old New Diff Outcome
GenericContext 568.98kB 0.00B -100.00% (568.98kB) ⬇️
GenericContextInner 0.00B 454.71kB +454.71kB (new) ⏫
infer_definition_types 4.68MB 4.64MB -0.87% (41.48kB) ⬇️
Type<'db>::apply_specialization_inner_::interned_arguments 929.45kB 918.67kB -1.16% (10.78kB) ⬇️
FunctionType 1.20MB 1.19MB -0.78% (9.52kB) ⬇️
infer_expression_types_impl 5.96MB 5.96MB -0.13% (8.10kB) ⬇️
remove_self_inner 39.22kB 46.97kB +19.76% (7.75kB) ⏫
infer_scope_types_impl 2.83MB 2.83MB -0.23% (6.77kB) ⬇️
Type<'db>::apply_specialization_inner_ 652.40kB 645.88kB -1.00% (6.52kB) ⬇️
GenericAlias<'db>::try_mro_ 732.07kB 730.14kB -0.26% (1.93kB) ⬇️
when_constraint_set_assignable_to_owned_impl 511.80kB 510.02kB -0.35% (1.78kB) ⬇️
assignable_solutions_impl::interned_arguments 83.99kB 82.37kB -1.93% (1.62kB) ⬇️
TypePair 1.10MB 1.10MB -0.13% (1.50kB) ⬇️
CallableType 1.63MB 1.63MB -0.08% (1.40kB) ⬇️
analyze_non_terminal_call 432.24kB 430.99kB -0.29% (1.25kB) ⬇️
... 43 more

sphinx

Name Old New Diff Outcome
GenericContext 893.12kB 0.00B -100.00% (893.12kB) ⬇️
GenericContextInner 0.00B 670.43kB +670.43kB (new) ⏫
Type<'db>::apply_specialization_inner_::interned_arguments 1.16MB 1.14MB -1.67% (19.84kB) ⬇️
infer_definition_types 11.71MB 11.70MB -0.11% (12.83kB) ⬇️
Type<'db>::apply_specialization_inner_ 775.34kB 763.24kB -1.56% (12.10kB) ⬇️
remove_self_inner 55.35kB 66.42kB +20.00% (11.07kB) ⏫
infer_expression_types_impl 11.66MB 11.65MB -0.05% (5.69kB) ⬇️
infer_scope_types_impl 6.20MB 6.19MB -0.08% (4.88kB) ⬇️
infer_unpack_types 259.52kB 255.04kB -1.72% (4.48kB) ⬇️
FunctionType 1.78MB 1.78MB -0.24% (4.45kB) ⬇️
all_narrowing_constraints_for_expression 1.66MB 1.65MB -0.22% (3.69kB) ⬇️
infer_statement_types_impl 532.93kB 532.38kB -0.10% (568.00B) ⬇️
assignable_solutions_impl::interned_arguments 105.73kB 105.22kB -0.48% (520.00B) ⬇️
analyze_condition 425.15kB 424.69kB -0.11% (472.00B) ⬇️
analyze_non_terminal_call 475.84kB 475.51kB -0.07% (336.00B) ⬇️
... 22 more

prefect

Name Old New Diff Outcome
GenericContext 2.27MB 0.00B -100.00% (2.27MB) ⬇️
GenericContextInner 0.00B 1.74MB +1.74MB (new) ⏫
Type<'db>::apply_specialization_inner_::interned_arguments 4.10MB 4.02MB -1.75% (73.44kB) ⬇️
Type<'db>::apply_specialization_inner_ 2.96MB 2.91MB -1.48% (44.84kB) ⬇️
FunctionType 5.72MB 5.69MB -0.48% (28.00kB) ⬇️
remove_self_inner 142.50kB 170.20kB +19.44% (27.70kB) ⏫
infer_definition_types 37.82MB 37.80MB -0.06% (24.90kB) ⬇️
infer_scope_types_impl 19.66MB 19.65MB -0.07% (13.39kB) ⬇️
infer_expression_types_impl 24.05MB 24.04MB -0.05% (12.73kB) ⬇️
BoundMethodType<'db>::callables_ 437.49kB 427.70kB -2.24% (9.80kB) ⬇️
assignable_solutions_impl::interned_arguments 367.35kB 359.23kB -2.21% (8.12kB) ⬇️
Type<'db>::class_member_with_policy_inner_ 11.43MB 11.42MB -0.06% (6.93kB) ⬇️
when_constraint_set_assignable_to_owned_impl 3.58MB 3.57MB -0.17% (6.27kB) ⬇️
TypePair 9.01MB 9.01MB -0.06% (5.34kB) ⬇️
GenericAlias<'db>::try_mro_ 4.55MB 4.54MB -0.11% (5.05kB) ⬇️
... 52 more

@astral-sh-bot

astral-sh-bot Bot commented Oct 6, 2026

Copy link
Copy Markdown

ecosystem-analyzer results

No diagnostic changes detected ✅

Large timing changes:

Project Old Time New Time Change
django-modern-rest 0.07s 0.02s -65%

Full report with detailed diff (timing results)

This branch was successfully deployed

1 active deployment
automations — 6365dac0 Deployed Oct 6, 2026 by dhruvmanila via security-review / security review #90784
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal An internal refactor or improvement (not for changelogs) ty The ty type checker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant