Skip to content

Conversation

@AlexWaygood
Copy link
Member

Summary

This PR splits Type::KnownInstance into two Type variants.

Although the variants of KnownInstanceType are more similar to each other than they are to any other Type variants, there's nonetheless a blurring of two somewhat distinct concepts in the enum as it currently stands:

  • Most variants represent a single symbol that will always exist at one (or possibly two, if it's backported via typing_extensions) known locations at runtime. For example: typing.Required, typing.ClassVar, typing.Final, etc.
  • Four variants, however, are special enough that they could arguably each have their own Type variant. I don't think that would be worth the extra branches everywhere (and the associated maintenance burden), but the point stands that these each represent distinct concepts to the other variants in KnownInstanceType. These variants are KnownInstanceType::TypeAliasType() (used for all PEP-695 type statements), KnownInstanceType::TypeVar(), KnownInstanceType::Generic() and KnownInstanceType::Protocol().

This PR therefore splits the Type::KnownInstance variant into two, and splits the KnownInstanceType enum into two. Type::KnownInstance() continues to wrap associated data of type KnownInstanceType, but KnownInstanceType now only holds four variants (the four very special variants described above). Type::SpecialForm is added in this PR, and it wraps associated data of type SpecialFormType. All variants except the four special ones are moved to the new SpecialFormType enum.

The vast majority of variants previously on KnownInstanceType are now on SpecialFormType, and the refactor here enables the implementation of SpecialFormType to be significantly simpler than the previous version of KnownInstanceType was:

  • Because no variant wraps any associated data, SpecialFormType can now implement Display directly rather than having to have a display() method that takes a db. This simplifies the construction of many diagnostics.
  • Because no variant wraps any associated data, we can now use strum_macros::EnumString to autogenerate the FromStr deserialization used in SpecialFormType::try_from_file_and_name(). Previously this had to be written out by hand due to some variants wrapping data, but we know from experience that it's hard to remember to keep methods like this up to date (and the compiler can't enforce exhaustiveness over a match where the enum variants are on the right-hand side of the match).
  • SpecialFormType no longer needs a normalized() method: now that no variants wrap any data, they all just normalize to themselves.

Test Plan

  • Existing tests pass
  • This should be a pure refactor with no mypy_primer diff

@AlexWaygood AlexWaygood added internal An internal refactor or improvement ty Multi-file analysis & type inference labels May 28, 2025
@github-actions
Copy link
Contributor

github-actions bot commented May 28, 2025

mypy_primer results

No ecosystem changes detected ✅

@AlexWaygood AlexWaygood marked this pull request as ready for review May 28, 2025 11:07
Copy link
Member

@dcreager dcreager left a comment

Choose a reason for hiding this comment

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

I very much like not having to thread the db through in as many places as before

/// Ordering within variants is based on the wrapped data's salsa-assigned id and not on its values.
/// The id may change between runs, or when e.g. a `TypeVarInstance` was garbage-collected and recreated.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, salsa::Update, Ord, PartialOrd)]
pub enum KnownInstanceType<'db> {
Copy link
Member

Choose a reason for hiding this comment

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

Was there a rationale for moving this back into types.rs? All else equal, I quite liked how we were moving things into dedicated modules, to help reduce the overwhelming size of this file.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, I'm definitely in favour of continuing to reduce the size of types.rs! I mainly put this here because it didn't seem big enough anymore to deserve its own module, and I wasn't sure it really had enough in common with SpecialFormType to share a module with that enum. (What would we call the module?)

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps the same thing it was called before, known_instance.rs?

Copy link
Member Author

@AlexWaygood AlexWaygood May 28, 2025

Choose a reason for hiding this comment

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

put them both in known_instance.rs? Or put them in separate modules: SpecialFormType in special_form.rs and KnownInstanceType in known_instance.rs?

Copy link
Member Author

Choose a reason for hiding this comment

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

(Landing this, but happy to address this in a followup!)

Copy link
Member

Choose a reason for hiding this comment

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

(Happy with a followup) I like your suggestion of separate modules special_form and known_instance

Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

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

It gives me slight pause how many of the cases need to be the same for SpecialForm and KnownInstance, but overall I do think the simplification and clarification of SpecialForm is worth it. Nice work!

/// Ordering within variants is based on the wrapped data's salsa-assigned id and not on its values.
/// The id may change between runs, or when e.g. a `TypeVarInstance` was garbage-collected and recreated.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, salsa::Update, Ord, PartialOrd)]
pub enum KnownInstanceType<'db> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps the same thing it was called before, known_instance.rs?

@AlexWaygood AlexWaygood force-pushed the alex/singletons branch 2 times, most recently from c03bdce to 0bea68b Compare May 29, 2025 13:21
@AlexWaygood AlexWaygood enabled auto-merge (squash) May 29, 2025 13:24
@AlexWaygood AlexWaygood disabled auto-merge May 29, 2025 13:27
@AlexWaygood AlexWaygood merged commit 47a2ec0 into astral-sh:main May 29, 2025
35 checks passed
dcreager added a commit that referenced this pull request May 29, 2025
* main:
  Add `offset` method to `ruff_python_trivia::Cursor` (#18371)
  ty_ide: improve completions by using scopes
  ruff_python_parser: add `Tokens::before` method
  [ty] Split `Type::KnownInstance` into two type variants (#18350)
  Bump 0.11.12 (#18369)
@AlexWaygood AlexWaygood deleted the alex/singletons branch June 3, 2025 18:27
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.

3 participants