-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Querify whether a type implements StructuralEq
and PartialStructuralEq
#72177
Querify whether a type implements StructuralEq
and PartialStructuralEq
#72177
Conversation
StructuralEq
and PartialStructuralEq
StructuralEq
and PartialStructuralEq
StructuralEq
and PartialStructuralEq
StructuralEq
and PartialStructuralEq
#[inline] | ||
pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool { | ||
// Fast path for some builtin types | ||
if self.is_primitive() || self.is_str() { |
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.
This is incomplete at the moment, since many builtin types don't actually implement StructuralEq
but are handled specially in the type visitor in structural_match
. I don't know if we want to resolve this problem by checking for them here or by implementing the trait for various builtins (arrays, pointers, references, etc.), but it seems like we should figure this out before merging this.
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 suspect if we attempt to handle this by implementing the trait in all the cases of interest, we're going to run into the problem where we cannot implement it for types with a for <'a> ...
, which arise from function pointers with a reference argument. (See also #46989 (comment) ... and I'm struggling to find a specific issue about this particular wart in the language today...)
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.
Is it bad to leave them unhandled here for now? All that means is that you miss the fast path for those types, right?
Then that is not a correctness concern; it is at most a performance concern, right? Which to me implies that we can merge this without figuring out the answer to your question.......
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.
So right now, this will return false
for types such as [i64; 4]
and &str
. This is correct at the moment because is_structural_eq_shallow
is always used in conjunction with type visitors that handle those cases separately, only invoking the query for TyKind::Adt
. We could just document this fact and call it a day, or switch this query to accept only TyKind::Adt
s, but I think it will be less prone to misuse if we handle the fundamental types inside the query instead of making the caller do it.
If you agree, there's two ways to accomplish this, we could either move this special-casing into the query itself or implement StructuralEq
for fundamental types. Your point about function pointers suggests that we just do the first one, since we can't cover all the fundamental types via trait impls anyway.
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.
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.
My main reaction is: I think you're rightfully worried about the method being prone to misuse.
- In particular, I'm worried that the doc-comment you've put above
is_structurally_eq_shallow
might actually detract from readers' understanding of the code as written. (It adopts a relatively simple specification ("when this returns true, you can conclude X; when it returns false, you cannot conclude anything"), which is what led me to say "can't we just land this code as is, and expand it later?"). But as you point out, all the current call-sites are making stronger assumptions about its behavior ("when given an ADT, then true implies X, and false implies not-X").
My first thought is: It would be nice to decide what interface we want, and then have the calls match it. But then my second thought is: It seems silly to put the effort into making all the call-sites handle the general case when they know that the method will produce usable results immediately when given an ADT.
In the long-term, you're probably right that we should move the special-casing into the query itself, so that it will handle any input ty
properly.
However, I do not want to block this PR on that addition. For various reasons (such as ease of identifying source of performance regressions), I think we should land this PR as is, with an addition to the doc-comment saying that the is_structurally_eq_*
methods happen to be precise when given an ADT. (i.e., I am advising that we indeed "just document this fact and call it a day", except I'm only saying "call it a day" for the short term; maybe add a FIXME for the longer term goal.)
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.
(It adopts a relatively simple specification ("when this returns true, you can conclude X; when it returns false, you cannot conclude anything")
actually maybe you never intended this interpretation? I personally read into the first sentence quite literally as just "if" and not "if and only if".
In any case, I still recommend the approach of adding the comment explaining the situation, landing the PR, and leaving further generalization for later work.
☔ The latest upstream changes (presumably #72262) made this pull request unmergeable. Please resolve the merge conflicts. |
ca8eca8
to
d53bea7
Compare
c4eaa62
to
37270ae
Compare
This should fix some of the perf loss from #67343. @bors try @rust-timer queue |
Awaiting bors try build completion |
⌛ Trying commit 37270ae with merge 24a2bc1a0f9dd3ad72bffa6f2b9ee946bb5f4fe9... |
Awaiting bors try build completion |
⌛ Trying commit 37270ae with merge b8fb01d57e56c6d811238ef6891b1b6d963b5d59... |
☀️ Try build successful - checks-azure |
Queued b8fb01d57e56c6d811238ef6891b1b6d963b5d59 with parent d79f1bd, future comparison URL. |
Finished benchmarking try commit b8fb01d57e56c6d811238ef6891b1b6d963b5d59, comparison URL. |
This seems fine to me. I want to hear more from @ecstatic-morse about the issue they raised up above before I mark it as r+'ed. |
(r=me if ecstatic-morse agrees with my logic that we don't have to find the answer to their question yet to land this...) |
@bors r+ |
📌 Commit 37270ae has been approved by |
@bors r- |
/// | ||
/// This function is "shallow" because it may return `true` for a type whose fields are not | ||
/// `StructuralEq`. You will need to use a type visitor if you want to know whether a call to | ||
/// `PartialEq::eq` will proceed structurally for a given type. |
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.
/// `PartialEq::eq` will proceed structurally for a given type. | |
/// `PartialEq::eq` will proceed structurally for a given type. | |
/// | |
/// Note: This function is "precise" when called on an ADT type; | |
/// that is, for an input ADT type, this will return `true` if | |
/// *and only if* the input ADT type implements both | |
/// `PartialStructuralEq` and `StructuralEq`. For non-ADT's, it | |
/// does not provide that strong a guarantee. |
I r+'ed this based on a misreading of @ecstatic-morse 's response above. Then after reflecting futher, I cancelled my r+, added a response to @ecstatic-morse along with my suggestion of how to proceed in the short term. r=me with my suggested change. If @ecstatic-morse wants to take a different approach for this PR, then I'm happy to see it. |
Closing this PR. I opened #73066 almost a week ago which contains my preferred approach. |
…, r=pnkfelix Querify whether a type has structural equality (Take 2) Alternative to rust-lang#72177. Unlike in rust-lang#72177, this helper method works for all types, falling back to a query for `TyKind::Adt`s that determines whether the `{Partial,}StructuralEq` traits are implemented. This is my preferred interface for this method. I think this is better than just documenting that the helper only works for ADTs. If others disagree, we can just merge rust-lang#72177 with the fixes applied. This has already taken far too long.
…, r=pnkfelix Querify whether a type has structural equality (Take 2) Alternative to rust-lang#72177. Unlike in rust-lang#72177, this helper method works for all types, falling back to a query for `TyKind::Adt`s that determines whether the `{Partial,}StructuralEq` traits are implemented. This is my preferred interface for this method. I think this is better than just documenting that the helper only works for ADTs. If others disagree, we can just merge rust-lang#72177 with the fixes applied. This has already taken far too long.
At present, computing this is relatively expensive. This PR adds a query along with a helper method on
TyS
to cache the "shallow" version of this check. See #67343 (comment) for background. The deep version will still need to go through the type visitor in thestructural_match
module.I'm not quite sure how to handle obligation causes, since they require a
Span
and aHirId
. For now, this PR switches toObligationCause::dummy()
, which is tolerable since we don't report a fulfilment error in thestructural_match
module. I don't really know what the right choice is here.r? @pnkfelix