Skip to content

internal: Change StructId to be a tracked struct in salsa - #23170

Open
Wilfred wants to merge 1 commit into
rust-lang:masterfrom
Wilfred:fix/stale-ast-id-after-rename
Open

internal: Change StructId to be a tracked struct in salsa#23170
Wilfred wants to merge 1 commit into
rust-lang:masterfrom
Wilfred:fix/stale-ast-id-after-rename

Conversation

@Wilfred

@Wilfred Wilfred commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Use a lifetime on StructId, defining a StructIdLt type following the
BlockLocLt pattern.

Ensure StructIdLt is a tracked type in salsa. This fixes a rare crash
where a user renames a struct and rust-analyzer panics:

Can't find ast id ErasedFileAstId { .. }

This seems to be because we could observe old interned StructId
values from previous salsa revisions.

We're moving to using lifetimes in these structs anyway, so this is
both a code cleanup and should be a fix for a crash.

AI disclosure: Code partly written by GPT-5.6 Sol, commit messages,
comments and code review entirely by me.

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 17, 2026

@ChayimFriedman2 ChayimFriedman2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Of course we cannot assume that. All analysis functions assume the IDs they get, of all kinds, are from the current revision. If something challenges that, we should fix that and not those methods (it'll also break when we add lifetimes to Salsa IDs).

View changes since this review

@Wilfred

Wilfred commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review. My mental model of salsa is generally just 'fancy memoisation'. I think the right thing here is to use lifetimes properly in the relevant salsa-tracked structs, let me update the PR.

Use a lifetime on StructId, defining a StructIdLt type following the
BlockLocLt pattern.

Ensure StructIdLt is a tracked type in salsa. This fixes a rare crash
where a user renames a struct and rust-analyzer panics:

    Can't find ast id ErasedFileAstId { .. }

This seems to be because we could observe old interned StructId
values from previous salsa revisions.

We're moving to using lifetimes in these structs anyway, so this is
both a code cleanup and should be a fix for a crash.

AI disclosure: Code partly written by GPT-5.6 Sol, commit messages,
comments and code review entirely by me.
@Wilfred
Wilfred force-pushed the fix/stale-ast-id-after-rename branch from d10b56c to 0090042 Compare August 21, 2026 17:14
@Wilfred Wilfred changed the title fix: Panic on querying attributes after struct rename internal: Change StructId to be a tracked struct in salsa Aug 21, 2026
@Wilfred

Wilfred commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

OK, I've updated this to use salsa tracking, which I think is the right fix. I've copied the pattern in #22534, and this should be another step towards #22868.

I've really struggled to get a satisfying Rust-code-level test for this, so I've just dropped unit test I had before. I do think the code is correct and fixes a real panic though.

Let me know what you think.

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

Using lifetimes on its own cannot fix that, it'll just makes code that passes IDs between revisions not compile. We should do that anyway, but if you saw a real panic from this (and not just your test that was incorrect), this will not fix it.

@Wilfred

Wilfred commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

I am indeed seeing sporadic panics from this, they take the form:

request handler panicked: Can't find ast id ErasedFileAstId { kind: Struct, index: 0, hash: 15AF } in AstIdMap: ... long map truncate

I wouldn't want to waste your time with theoretical bugs, I've kept all my PRs strictly to panics that I'm seeing in practice.

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

I didn't say you don't, what I said is that if you see real panics (like you confirmed) then this change won't fix them.

@Wilfred

Wilfred commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

Fair enough, just wanted to be explicit that I'm grateful for your regular and thorough reviews :)

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

IOW: you need to find the piece of code responsible for reusing IDs between revisions (which is a bug), and fix it. Using lifetimes is something we should do but it's tracked separately, while it could ease discovery of the problematic code (by making it not compile) it won't solve that by itself (and I don't know how much lifetimes we'll need to add).

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

An alternative (and perhaps more plausible) explanation is speculative completion: it does some sketchy things that could theoretically maybe cause things like that (we know it can mess the AttrId tracking and that causes panics, although misusing Salsa IDs is different and I don't know if it can do that). If you see panics in completion specifically, I'll search there first.

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

Or, if you have a backtrace, maybe I can have a better idea.

@Wilfred

Wilfred commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

FWIW I'm seeing the panic on LSP requests textDocument/diagnostic, textDocument/codeAction and textDocument/semanticTokens/full, but I haven't seen any on completion requests.

I'll dig up a stack trace too.

@ChayimFriedman2

ChayimFriedman2 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

If you can have a stack trace with debuginfo, even better (we don't ship out binaries with debuginfo but maybe Meta does, that's what I'd do in your place - this helps debugging and the only reason we don't do that is that it increases binary size and thus download time, which is probably not a problem in an internal network).

@Wilfred

Wilfred commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

Argh, I've lost line numbers, but I've got function names. This is from rust-analyzer at commit 137005e:

0: __rustc::rust_begin_unwind
1: core::panicking::panic_fmt
2: span::ast_id::AstIdMap::get_erased
3: span::ast_id::AstIdMap::get
4: <T as hir_def::src::HasSource>::ast_ptr
5: hir_def::src::HasSource::source
6: hir_def::attrs::attrs_from_ast_id_loc
7: hir_def::attrs::attrs_source
8: hir_def::attrs::collect_attrs
9: <hir_def::attrs::AttrFlags as hir_def::attrs::AttrFlags::query::InnerTrait_>::query_
10: <hir_def::attrs::AttrFlags::query::_::query__Configuration_ as salsa::function::Configuration>::execute::inner_
11: <hir_def::attrs::AttrFlags::query::_::query__Configuration_ as salsa::function::Configuration>::execute
12: salsa::function::execute::<impl salsa::function::IngredientImpl<C>>::execute_query
13: salsa::function::execute::<impl salsa::function::IngredientImpl<C>>::execute
14: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
15: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
16: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
17: salsa::function::maybe_changed_after::deep_verify_edges
18: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
19: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
20: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
21: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
22: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
23: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
24: salsa::function::maybe_changed_after::deep_verify_edges
25: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
26: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
27: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
28: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
29: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
30: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
31: salsa::function::maybe_changed_after::deep_verify_edges
32: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
33: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
34: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
35: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
36: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
37: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
38: salsa::function::maybe_changed_after::deep_verify_edges
39: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
40: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
41: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
42: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
43: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
44: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
45: salsa::function::maybe_changed_after::deep_verify_edges
46: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
47: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
48: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
49: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
50: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
51: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
52: salsa::function::maybe_changed_after::deep_verify_edges
53: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
54: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
55: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
56: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
57: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
58: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
59: salsa::function::maybe_changed_after::deep_verify_edges
60: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
61: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
62: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
63: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
64: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
65: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
66: salsa::function::maybe_changed_after::deep_verify_edges
67: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
68: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
69: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
70: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
71: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
72: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
73: salsa::function::maybe_changed_after::deep_verify_edges
74: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
75: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
76: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
77: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
78: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
79: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
80: salsa::function::maybe_changed_after::deep_verify_edges
81: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
82: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
83: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
84: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
85: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
86: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
87: salsa::function::maybe_changed_after::deep_verify_edges
88: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
89: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
90: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
91: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
92: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
93: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
94: salsa::function::maybe_changed_after::deep_verify_edges
95: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
96: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
97: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
98: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
99: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
100: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
101: salsa::function::maybe_changed_after::deep_verify_edges
102: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
103: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
104: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
105: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
106: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
107: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
108: salsa::function::maybe_changed_after::deep_verify_edges
109: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
110: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
111: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
112: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
113: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
114: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
115: salsa::function::maybe_changed_after::deep_verify_edges
116: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
117: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
118: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
119: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
120: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
121: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
122: salsa::function::maybe_changed_after::deep_verify_edges
123: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
124: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
125: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
126: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
127: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
128: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
129: salsa::function::maybe_changed_after::deep_verify_edges
130: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
131: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
132: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
133: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
134: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
135: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
136: salsa::function::maybe_changed_after::deep_verify_edges
137: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
138: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
139: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
140: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
141: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
142: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
143: salsa::function::maybe_changed_after::deep_verify_edges
144: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
145: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
146: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
147: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
148: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
149: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
150: salsa::function::maybe_changed_after::deep_verify_edges
151: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
152: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
153: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
154: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
155: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
156: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after
157: salsa::function::maybe_changed_after::deep_verify_edges
158: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::deep_verify_memo
159: salsa::function::maybe_changed_after::<impl salsa::function::memo::MemoHeader>::verify_memo
160: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold::inner
161: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after_cold
162: salsa::function::maybe_changed_after::<impl salsa::function::IngredientImpl<C>>::maybe_changed_after
163: <salsa::function::IngredientImpl<C> as salsa::ingredient::Ingredient>::maybe_changed_after

@ChayimFriedman2

Copy link
Copy Markdown
Contributor

Ouch it's cut - do you have the full backtrace? The start is especially important because it contains the IDE code invoking things.

@Wilfred

Wilfred commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

Argh, I think I need to fix my error collector, I don't seem to have more than that right now. I did see a salsa query backtrace if that's at all helpful:

0: AttrFlags::query_(Id(27bc96)) -> (R24912, Durability::LOW)
1: const_eval_query(Id(48f38f)) -> (R24913, Durability::LOW)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants