rust-analyzer: [Since 0.4.1658] Cannot rename a non-local definition.
System Details
rust-analyzer version: 0.3.1665-standalone (first broken stable version) rustc version: rustc 1.72.1 (d5c2e9c34 2023-09-13)
Details
Since v0.4.1658-standalone it is not possible to rename any item inside one of my projects. More details in reproduction section.
Regression
Broken since v0.4.1658-standalone (nightly). Earlier versions work as expected.
1658 (first broken ver.): Actions Run: https://github.com/rust-lang/rust-analyzer/actions/runs/6153193088 Commit: https://github.com/rust-lang/rust-analyzer/commit/cc6c8209cbaf7df55013977cf5cc8488d6b7ff1c
1655 (previous functional release): Commit: https://github.com/rust-lang/rust-analyzer/commit/994df3d6a31d39f11600f30a6df0b744b13937c1
I believe this was introduced in https://github.com/rust-lang/rust-analyzer/pull/15232 . However probably not directly caused by said commit (the commit seems to restrict needed functionality), but an unexpected edge case where a local item is believed to be non-local.
Reproduction
I have tried to create a minimal reproduction, however did not succeed in creating a minimal repro (I even tried copying dependency structure and workspace code settings).
So I am forced to instead link to one of my real [WIP] projects.
Reproduction Steps:
- Clone
https://github.com/Reloaded-Project/Reloaded.Hooks-rs.git - Checkout
main - Open main folder in VSCode (folder with README.MD)
- Note: Projects are included via
.vscode/settings.json->rust-analyzer.linkedProjects.
- Note: Projects are included via
- Open any file in
reloaded-hooks-portablesuch asprojects/reloaded-hooks-portable/src/api/wrapper_instruction_generator.rs.
It is not possible to rename any type or even local variable due to:
[Error - 03:04:27] Request textDocument/rename failed.
Message: Cannot rename a non-local definition.
Code: -32602
About this issue
- Original URL
- State: closed
- Created 9 months ago
- Reactions: 18
- Comments: 58 (34 by maintainers)
Commits related to this issue
- Introduce improvements in deduplicating crates fixes #15656 . With this commit we have a more relaxed way of comparing to crates for equality. If two crates are `almost_equal` then deduplication take... — committed to alibektas/rust-analyzer by alibektas 9 months ago
- Relaxation for crate graph mergin Partially fixes #15656 . When a crate graph is extended which is the case when new workspaces are added to the project the rules for deduplication were too strict. O... — committed to alibektas/rust-analyzer by alibektas 9 months ago
- Relaxation for crate graph mergin Partially fixes #15656 . When a crate graph is extended which is the case when new workspaces are added to the project the rules for deduplication were too strict. O... — committed to alibektas/rust-analyzer by alibektas 9 months ago
- Relaxation for crate graph mergin Partially fixes #15656 . When a crate graph is extended which is the case when new workspaces are added to the project the rules for deduplication were too strict. O... — committed to alibektas/rust-analyzer by alibektas 9 months ago
- Auto merge of #15754 - alibektas:15656/linked_projects_are_local_too, r=Veykril fix: Dedup duplicate crates with differing origins in CrateGraph construction Partially fixes #15656 . Until now the c... — committed to rust-lang/rust-analyzer by bors 7 months ago
- Auto merge of #15754 - alibektas:15656/linked_projects_are_local_too, r=Veykril fix: Dedup duplicate crates with differing origins in CrateGraph construction Partially fixes #15656 . Until now the c... — committed to rust-lang/rust-analyzer by bors 7 months ago
- Auto merge of #15754 - alibektas:15656/linked_projects_are_local_too, r=Veykril fix: Dedup duplicate crates with differing origins in CrateGraph construction Partially fixes #15656 . Until now the c... — committed to rust-lang/rust-analyzer by bors 7 months ago
- Introduce a new CrateOrigin variant `Member` CrateGraph has been suffering from ignoring a unified definition of a Workspace : Cargo rightly assumes that each project has its own workspace but in RA ... — committed to alibektas/rust-analyzer by alibektas 6 months ago
- Add a new config to allow renaming of non-local items With #15656 we started disallowing renaming of non-local items. Although this makes sense there are some false positives that impacted users' wor... — committed to alibektas/rust-analyzer by alibektas 5 months ago
- Add a new config to allow renaming of non-local items With #15656 we started disallowing renaming of non-local items. Although this makes sense there are some false positives that impacted users' wor... — committed to alibektas/rust-analyzer by alibektas 5 months ago
- Auto merge of #16391 - alibektas:15656/renaming_allowed_by_config, r=Veykril Add a new config to allow renaming of non-local defs With #15656 we started disallowing renaming of non-local items. Alth... — committed to rust-lang/rust-analyzer by bors 5 months ago
- Auto merge of #16586 - Veykril:crate-graph-side-table, r=Veykril fix: Remove cargo knowledge from `CrateData` Fixes https://github.com/rust-lang/rust-analyzer/issues/16170, Fixes https://github.com/... — committed to rust-lang/rust-analyzer by bors 4 months ago
So if everything goes well 🤞 with today’s nightly this config should be available. You will just need to set the following config to “true”, we defaulted it to “false” to make the feature visible to users, as it works just fine for most of the time. Here is the related piece in the documentation
Hi, @alibektas! I just tried. It worked like a charm! I’m proud of you and this community. Thank you very much.
Ah, this issue might be why Rename Symbol no longer works on local variables in some rustc crates.
We use a
CrateGraphto represent how crates within a project relate to one another. With #15232 we forbade renaming of non-local items which means that if a crate’s originhttps://github.com/rust-lang/rust-analyzer/blob/f19479a2ad238ad861cfe8d57e63beeccb56169e/crates/base-db/src/input.rs#L143-L152
is something else other
Localwe cannot allow renaming to take place. The given example useslinkedProjects. This will create a “healthy” crate graph.The trouble starts when
Foodepends onBar( Following the repro foo isreloaded-hooks-x86-sysand Bar isreloaded-hooks-portable. This will causeBarto be ofCrateOrigin::Libraryfrom Foo’s perspective. This would have been OK had thelinkedProjectsnot already registeredBarasCrateOrigin::Local. So now we have something likeOr in simplified terms :
So resolving this issue will entail changes in
CrateGraphwhich may/may not be easy. I think until then we can revert change from #15232 . Let’s ask for @Veykril 's opinion.Here’s a test case where you can find a minimal repro.
ping @TCROC @vaniusrb
Adding a config was on my TODO list, let me work on it now and get back to you in a few hours. Sorry for the inconvenience!
refactor-broken-example.zip
Ok so I figured out how to reproduce this issue in minimized environments. There are 2 ways to cause it. Below are my findings:
Linking against 2 proc macros
The interesting thing is that in this case, only the 2nd proc macro crate breaks and doesn’t allow renaming vars:
example1-macros ✅
example2-macros ❌
And it seems to be directly correlated to the order of the projects that make use of the macros. If I rearrange the linked project settings to be like so:
with the example2 being before example1, example2 will work and example1 will break. The order of the macro projects does not seem to matter, but the order of the project that references the macro project seems to break it.
So if I switched these 2:
To be:
Then example 2 will work and example 1 will break.
bitvec
Adding a reference to the bitvec crate in example1 or example2 seems to break refactoring in any procedural macro crates. This can be seen in example1/Cargo.toml. Uncomment the
# bitvec = "1.0.1"and you will notice that you can no longer refactor things in example1-macros and start getting the “Cannot rename a non-local definition.” error.I attached an archive of the project to reproduce on your machines. Let me know if you guys have any questions and / or need anything else from me.
Thanks again everyone! Ur all beautiful human beings and Merry Christmas! ♥️
You mightve been still using the old version. VSCode updates the extensions after startup, so you need to reload the window once to actually run the new version.
@shepmaster thanks, that should suffice to figure it out.
So first of all sorry for taking so much time I was sick for a week. I have addressed the reasons behind this issue and my PR solves most of them. The project given as a repro however will still not be able use renaming. I will address this in a following PR. But let me mention why it currently remains unresolved.
As I mentioned before we deal with multiple occurrences of the same crate and the dedup rules were until now too strict ( two crates must be equal to be merged into one but this is not possible in the given example, see comment above) . After I relaxed the conditions for merging I saw that there are inconsistencies in versions of one crate “hashbrown” in the given repro ( see metadata for both reloaded_hooks_{portable,x86_sys} @Sewer56 ). But I couldn’t have relaxed the condition to say if one project has a dependency that has a different version than its other occurrence then merge them anyway. So this still needs to be addressed somehow but until then it wouldn’t hurt to come up with a solution that solves this issue in most of cases.
@alibektas first initial test seems to indicate that its working! 😃 I’m going to try it for a bit and see if I run into any issues with it! 😃
Honestly I have always built from the source by running just
cargo xtask installbut I believe you are right with pre-release. In fact if you go to the extension tab and right click on rust-analyzer you can see that the version with the same version number (0.4.1810) has a20 hours agomark next to it.And mind you that the feature will be available around 01:15 CET based on the most recent release time from yesterday.
Thank you @alibektas! 😃 No sorries necessary! 😃
Yes, all discovered and loaded projects, whether explicitly set via
linkedProjectsor implicitly loaded.I think that’s what I’m saying, yes 😅 It just fundamentally doesn’t make sense to me that we could consider only one version of a crate in a specific folder local and the other not, it should be purely a property of the folder they’re in.
@alibektas I’m not a maintainer so I’m not familiar with the codebase at all, but looks like it was a really sneaky bug! Looks like a simple enough fix from the surface level 😃
I’ll be curious to see what others think as well! (Looks good to me tho! 😉)
I’ll take a sec to learn how to build ra from source and test on my main project as well to see if it fixes it 😃
Sure let me wrap things up and post the link here
So finally I found the reason which is a little peculiar. It is that we have for the “proc_macro2” crate different
<Self as CrateData>.env["OUT_DIR"]values each time a new workspace is detected but for the deduplication we had previously assumed a one to one overlap of allEnvhashes. When I relax this condition such thatOUT_DIRplays no further role the issue is resolved. But before opening a PR I wanted to make sure that nothing speaks against it.As to testing : Since the said crate is an external crate collecting metadata and
extending them will not let use detect this error, same goes for the currentslow-testsinfra ( In both situations the error was undetected ). So any suggestions regarding a test case wouldn’t be so bad eitherThere is a
linkedProjectssetting which overwrites the scanning behaviorAh, I can tell you why this fails (and why it works fine if the
orchestratoris moved one level up). The project structure as is means that we only load theuicrate, but not theorchestrator(because it is too deep, we only scan the root and first level for cargo projects), so theorchestratoris considered non local as its not inside the workspace ofui(we might be able to cheat around a bit by respecting a crate’s position to the opened VSCode/LSP workspace root as well as any cargo workspaces). OTOH if you lift theorchestratorup one level we now load it as a cargo workspace as well, where the deduplication fix kicks in, making it just work.@shepmaster @Veykril I was also able to reproduce this using the archive provided by @shepmaster
I can confirm that with 0.3.1748 I am now able to rename symbols in
rustc_mir_transformonce again.👋 Thank you for your answer @ogapo . We were planning to make some changes to how we determine
CrateOrigin. Let me get back to you in a couple of weeks once I got some time to work on this and I am personally in favor of you making a PR ( assuming that you would like to contribute to the project yourself. )There is nothing to address in that case (aside from our PR relaxing things in regards to the origin), the root of the problem is that the crate that is being loaded in the linked projects while also being loaded as a dependency of another is subject to different
Cargo.lockfiles. This makes it inherently impossible for rust-analyzer to dedup the crate if dependencies of said crate have differing versions in the respective lock files. As such, the project should either take care of trying to sync the lock files or only add the cargo workspace to the linked projects that contains the other crate in its dep graph as well as that will be effectively loaded due to that anyways.The only thing that we should be looking into is recognizing this, and somehow inform the user that this kind of set up can cause IDE features like renaming to fail. Although I think there is a bug here in how we assign CrateOrigin’s still / how we forbid renaming as well. The crates in question where renaming fails here are still inside the project folders (presumably via
pathdependencies) in which case we shouldn’t forbid renames in the first place I think, since those are technically fine to modify. We only want to prevent the std lib sources and crates.io sources from being modified.I’ve confirmed that reverting to 0.3.1657 allows Rename Symbol to work in
rustc_mir_transform.