-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[ty] Deterministic ordering of types #18091
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Hmm, this is indeed painful and also increases the work necessary to normalize types (because it's now necessary to perform a deep comparison).
I wonder if this is actually a problem. I'm not sure if it will be when we start garbage collecting interned values but is it today? |
I don't understand? astral-sh/ty#369 (comment) definitely feels like an actual problem to me. It's not just non-deterministic, it's also incorrect (sometimes). |
cd6a2d3
to
6e83ce9
Compare
The benchmarks seem completely neutral: https://codspeed.io/astral-sh/ruff/branches/david%2Fstable-ordering |
I'm not sure I fully understand yet whether the problem is:
|
I don't fully understand this point. Could you possibly give an example? |
@@ -149,6 +149,14 @@ impl<'db> ScopeId<'db> { | |||
NodeWithScopeKind::GeneratorExpression(_) => "<generator>", | |||
} | |||
} | |||
|
|||
pub(crate) fn ordering(self, db: &'db dyn Db, other: Self) -> std::cmp::Ordering { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this would be tricky to enforce unless salsa avoids adding PartialOrd
, Ord
to the interned structs as pointed out by Micha and in the linked salsa discussion.
@@ -229,9 +232,15 @@ impl<'db> GenericContext<'db> { | |||
|
|||
Specialization::new(db, self, expanded.into_boxed_slice()) | |||
} | |||
|
|||
pub(crate) fn ordering(self, db: &'db dyn Db, other: Self) -> Ordering { | |||
self.variables(db) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to implement .ordering
for TypeVarInstance
as it's interned?
I'm mainly questioning whether we need to override everywhere. We definitely should override it if it otherwise leads to incorrect ordering. I don't think we have to override in cases where it's only about determinism because ids are then a very convenient and fast way to arbitrarily sort items (if the only goal is that they have a fixed ordering but don't require a specific semantic ordering) It's not quite clear to me what you're fixing in this pr (at least one case seems semantic) |
I think our prior assumption was that ordering of types need only be deterministic within a given run of |
Until we implement persistent caching :-) |
Haha, fair. Although salsa might solve this if the rematerialized structs retain their relative order |
Summary
Our type ordering/normalization previously relied on
PartialOrd
/Ord
instances that were auto-generated forsalsa::interned
structs. These implementations compare by salsa ID, which is not necessarily deterministic (depends on when a particular type has been interned, and can therefore depend on file checking order).Besides not being deterministic, it was also incorrect. When comparing two equal unions
A1 | B1
andA2 | B2
, it was possible for one union to be ordered incorrectly (e.g. if bothA1
andB1
were interned nominal instances), leading to incorrect type-relation results.Writing these
ordering
functions by hand is exhausting and error-prone. This is why I only went so far as to fix the linked bug. Much more work would be involved to implement this for structs likeFunctionType
orCallableType
. We should probably look into auto-generating these methods somehow?Related salsa discussion
fixes astral-sh/ty#369
Test Plan
Ran the following command for a while and saw no flaky behavior (on the MRE from the linked ticket):