Skip to content

[ty] Represent InitVar as a special form internally, not a class#24248

Merged
AlexWaygood merged 1 commit intomainfrom
alex/initvar-special
Mar 30, 2026
Merged

[ty] Represent InitVar as a special form internally, not a class#24248
AlexWaygood merged 1 commit intomainfrom
alex/initvar-special

Conversation

@AlexWaygood
Copy link
Copy Markdown
Member

@AlexWaygood AlexWaygood commented Mar 27, 2026

Summary

All type qualifiers are represented internally as variants of the special_form::TypeQualifier enum. All type qualifiers, that is, except dataclasses.InitVar, which typeshed (accurately) tells us is a class rather than an instance of typing._SpecialForm. This unfortunate fact means that we have quite a bit of special casing for specifically InitVar, which is scattered around the ty codebase.

This PR overrides typeshed to represent InitVar as a special form internally, like all our other type qualifiers, rather than a class. While this is strictly more lines of code overall, it's a decrease in complexity and an increase in robustness: all our handling for InitVars now takes the same codepaths as our handling for other type qualifiers. There's significantly less ad-hoc special casing. This is similar to the way we already override typeshed for NamedTuple and Any -- typeshed tells us that both of these symbols are classes, too.

There is a disadvantage to this PR, which is that we no longer have a way of representing "instance of the class InitVar" internally (because we no longer recognize InitVar as being a class at all). This means that we do have to introduce some new special casing to handle subscripting InitVar, calling InitVar, and using InitVar as the second argument to isinstance(). I still think this PR is worth it overall, though: runtime uses of InitVar are very rare, and having all our type qualifiers be listed in the TypeQualifier enum opens the door to further generalisations in some of our checks, on top of the ones I've implemented here.

Test Plan

mdtests extended

@AlexWaygood AlexWaygood added internal An internal refactor or improvement ty Multi-file analysis & type inference labels Mar 27, 2026
@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot bot commented Mar 27, 2026

Typing conformance results

No changes detected ✅

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

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot bot commented Mar 27, 2026

Memory usage report

Memory usage unchanged ✅

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot bot commented Mar 27, 2026

ecosystem-analyzer results

No diagnostic changes detected ✅

Full report with detailed diff (timing results)

@AlexWaygood AlexWaygood force-pushed the alex/initvar-special branch 4 times, most recently from 9ea82c4 to 0df65a0 Compare March 27, 2026 17:07
@AlexWaygood AlexWaygood marked this pull request as ready for review March 27, 2026 17:15
@carljm carljm removed their request for review March 27, 2026 17:20
@AlexWaygood
Copy link
Copy Markdown
Member Author

#24251 is what the "further generalisation" I have in mind would look like, but I don't want to open that PR until the functional TypedDict work lands (it'll create unnecessary merge conflicts with that work, it's not high-priority, and I'll be able to simplify that PR a little after the functional TypedDict work lands).

Copy link
Copy Markdown
Contributor

@sharkdp sharkdp left a comment

Choose a reason for hiding this comment

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

This makes sense to me, thank you.

@AlexWaygood AlexWaygood force-pushed the alex/initvar-special branch from 0df65a0 to 825d237 Compare March 30, 2026 10:16
@AlexWaygood AlexWaygood enabled auto-merge (squash) March 30, 2026 10:17
@AlexWaygood AlexWaygood merged commit 459f202 into main Mar 30, 2026
48 checks passed
@AlexWaygood AlexWaygood deleted the alex/initvar-special branch March 30, 2026 10:20
carljm added a commit that referenced this pull request Mar 31, 2026
* main: (35 commits)
  Store definition indexes as u32 (#24307)
  Avoid re-using symbol in RUF024 fix (#24316)
  [ty] Add materialization to `Divergent` type (#24255)
  [ty] Make `Divergent` a top-level type variant (#24252)
  [ty] Fix nested global and nonlocal lookups through forwarding scopes (#24279)
  Fetch the cargo-dist binary directly instead of using the installer (#24258)
  [ty] Fix panic on `list[Annotated[()]]` (#24303)
  Don't measure the AST deallocation time in parser benchmarks (#24301)
  Enable CodSpeed's memory benchmarks for simulation benchmarks (#24298)
  Upgrade imara-diff to 0.2.0 (#24299)
  [ty] Represent `InitVar` as a special form internally, not a class (#24248)
  `RUF067`: Allow dunder-named assignments in non-strict mode
  [`pyupgrade`] UP018 should detect more unnecessarily wrapped literals (UP018) (#24093)
  [ty] Remove unused `system.glob` method (#24300)
  [ty] Reject functional TypedDict with mismatched name (#24295)
  Update Rust crate arc-swap to v1.9.0 (#24292)
  [ty] Remove unused `@Todo(Functional TypedDicts)` (#24297)
  Update CodSpeedHQ/action action to v4.12.1 (#24290)
  Update taiki-e/install-action action to v2.69.6 (#24293)
  Update Rust crate toml to v1.0.7 (#24289)
  ...
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 ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants