Add support for self-ref fields to the interned macro - #1260
Conversation
✅ Deploy Preview for salsa-rs canceled.
|
|
Turns out this feature was very bugged with the LRU we added (fortunately r-a disabled LRU for this) |
f388a75 to
9d8f2bd
Compare
|
Also unsure about the name of this tbh. These late fields are similar to untracked ones in that they do not add to the identity of the interned. |
aad6597 to
75e68ff
Compare
| let revisions = if has_self_ref { | ||
| quote!(usize::MAX) | ||
| } else { | ||
| let revisions = salsa_struct.revisions(); | ||
| quote!(#(#revisions)*) | ||
| }; |
There was a problem hiding this comment.
What's the reason that we need to disable LRU collection for self referential structs?
There was a problem hiding this comment.
Ah I think this is leftover from the previous iteration. I think LRU ought to be fine for self-refs
| /// existing value without changing its self-referential fields. Interned types containing these | ||
| /// fields disable slot reuse so that stored references remain valid. |
There was a problem hiding this comment.
Can you say more why this is necessary? How is it different from any other field that stores another interned struct? I'd expect that the 'db lifetime prevents you from holding a reference to the interned struct, which also prevents you from reading the field. If the value's different, the interned should get a different id.
After chatting with codex. The main issue seems to be that we exclude the self_ref field from hashing, but users can also provide Some(value), where there's no guarantee that value is indeed self. What's the reason that r-a needs the Some(value) constructor where value != self?
There was a problem hiding this comment.
We use this for modeling hygiene which is effectively a graph where the only cycles can be self-referential
See https://github.com/rust-lang/rust-analyzer/blob/master/crates/span/src/hygiene.rs
and the constructor call site https://github.com/rust-lang/rust-analyzer/blob/33815d5957836f6eff67f91aced8420ec5a377d3/crates/hir-expand/src/hygiene.rs#L110-L143
Only allowing the field to actually point to itself would make the feature kind of pointless
There was a problem hiding this comment.
Lol, right. If it's always self, then what's the point of it :)
If the field is != self, shouldn't it then be part of the interning key? Or what's the use case where two interned structs with different self_ref (or an instance where self_ref == self and one where self_ref != self). I think that would fix the LRU issue. I think that also suggest that Debug should print the self_ref unless it is self (in which case we can print <self>).
There was a problem hiding this comment.
Well, it just happens to be the case that for our purposes here, only the non-self ref keys are supposed to contribute to the identity. Or rather, the self-ref fields have no need to contribute as due to the way we construct these the self-ref fields will always be the same for the given non-self ref fields.
I can take a look at the key contribution later, I don't remember whether there was an implementation reason or whether it's just that we didn't need it. Though it would be nice if we could keep the key contribution excluded somehow for that minor perf improvement. I think hygiene accesses can be hot in r-a
There was a problem hiding this comment.
Couldn't you solve this in r-a by having a wrapper type that overrides Eq and Hash to always be true/0?
b73300c to
d9dbd45
Compare
ac95f02 to
f88978d
Compare
f88978d to
bc3373c
Compare
bc3373c to
f61e348
Compare
Merging this PR will degrade performance by 5.39%
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
|
Sorry for the many questions. We can also move this to Zulip if it's easier. How's the
|
|
no worries
We used to do this, but it required a lot of annoying branching everywhere iirc (it's been a while). |
It should be limited to the one method that does the parent or self lookup. All callsites should remain unchanged. But yes, the compiled code will contain more branching.
I don't think that should be the case. Both implementations read exactly one field. |
|
I can try cooking up a branch on r-a that tries to go the previous route again (and also read up on why I wanted this change). I can tell you'd like to get rid of the support code here :^) (which is fair if this feature turns out to not be necessary after all) |
|
I don't mind the feature on its own, if there are cases where it simplifies downstream code. But if it's something that can be implemented downstream without much complexity, it seems desirable not to add more complexity to salsa |
|
Instead of doing all of this, isn't it better to just expose (Also why doesn't it play well with interneds GC?) |
Completely forgot to add it to the macro since r-a had this hand rolled for 2 years now