rust-lang/rust-analyzer#16394 changed the logging initialisation to
create a Config struct, but never did anything with it. Call `.init()`
so slow tests have tracing configured.
You can test this by adding a test failure to a slow test,
e.g. `test_format_document_2018`, and then running it:
```
$ RA_LOG=trace RUN_SLOW_TESTS=1 cargo t test_format_document_2018
```
Previously this didn't log anything, even though RA_LOG was set.
Example
---
```rust
struct Other;
struct Vec<T>(T);
enum Foo {
Vec(Vec<$0>)
}
```
**Before this PR**
```text
st Vec<…> Vec<{unknown}> [name]
en Foo Foo []
st Other Other []
sp Self Foo []
```
**After this PR**
```text
en Foo Foo []
st Other Other []
sp Self Foo []
st Vec<…> Vec<{unknown}> []
```
On some filesystems, particularly FUSE on Linux, we don't get
Create(...) events. We do get Access(Open(Any)) events, so handle
those consistently with create/modify/remove events.
This fixes missed file notifications when using Sapling SCM with
EdenFS, although I believe the problem can occur on other FUSE
environments.
Reproduction:
Commit a change with Sapling that adds a new file foo.rs and
references it with `mod foo;` in lib.rs. Configure rust-analyzer as
follows:
```
{
"rust-analyzer.files.watcher": "server",
"rust-analyzer.server.extraEnv": {
"RA_LOG": "vfs_notify=debug"
},
}
```
Go to the previous commit, restart rust-analyzer, then go to the next
commit. The logs only show:
```
2026-03-18T07:16:54.211788903-07:00 DEBUG vfs-notify event event=NotifyEvent(Ok(Event { kind: Access(Open(Any)), paths: ["/data/users/wilfred/scratch/src/foo.rs"], attr:tracker: None, attr:flag: None, attr:info: None, attr:source: None }))
2026-03-18T07:16:54.211906733-07:00 DEBUG vfs-notify event event=NotifyEvent(Ok(Event { kind: Access(Open(Any)), paths: ["/data/users/wilfred/scratch/src/foo.rs"], attr:tracker: None, attr:flag: None, attr:info: None, attr:source: None }))
2026-03-18T07:16:54.216467168-07:00 DEBUG vfs-notify event event=NotifyEvent(Ok(Event { kind: Access(Open(Any)), paths: ["/data/users/wilfred/scratch/src/lib.rs"], attr:tracker: None, attr:flag: None, attr:info: None, attr:source: None }))
2026-03-18T07:16:54.216811304-07:00 DEBUG vfs-notify event event=NotifyEvent(Ok(Event { kind: Access(Open(Any)), paths: ["/data/users/wilfred/scratch/src/lib.rs"], attr:tracker: None, attr:flag: None, attr:info: None, attr:source: None }))
```
Observe that `mod foo;` has a red squiggle and shows "unresolved
module, can't find module file: foo.rs, or foo/mod.rs". This
commit fixes that.
This is not a logical change, and just makes the next commit simpler.
It also shouldn't impact performance, because the vast majority of
events have a single path.
Previously, Config::root_path() would always return the LSP rootUri of
the first workspace folder. This can cause issues when the user has
multiple workspaces open in their editor, especially if the first one
in the list isn't a Rust project.
This was noted as an issue in rust-lang/rust-analyzer#21483, and added
comments suggesting that we should deprecate root_path().
This change splits root_path() into a `workspace_root_for()` function
that handles the multiple workspace case correctly, and a
`default_root_path()` fallback.
This is particularly useful when the user has configured
project-relative paths to e.g. their discover command or rustfmt, but
it's the correct behaviour in general.
AI disclosure: First draft was written with Claude Opus.
This is legal when there are dev-dependencies, and rust-analyzer
itself even does this. This causes spurious warnings in several cases,
such as generating SCIP for rust-analyzer:
```
$ cargo run --bin rust-analyzer --release -- scip .
2026-03-12T18:40:33.824092Z WARN cyclic deps: cfg(Idx::<CrateBuilder>(21)) -> cfg(Idx::<CrateBuilder>(21)), alternative path: cfg(Idx::<CrateBuilder>(21))
```
In this case, the `cfg` crate enables its `tt` feature by depending
on itself in dev-dependencies.
Specifically, this allows the following patterns and expressions which
were not allowed before:
```rust
let <T as Trait>::Assoc { a } = <T as Trait>::Assoc { a: 0 };
let (<E as Trait>::Assoc::ES { a } | <E as Trait>::Assoc::ET(a))
= <E as Trait>::Assoc::ES { a: 0 };
let (<E>::ES { a } | <E>::ET(a)) = <E>::ES { a: 0 };
```
Co-authored-by: Waffle Lapkin <waffle.lapkin@gmail.com>
Co-authored-by: Chayim Refael Friedman <chayimfr@gmail.com>
Those will never cease to surprise me.
Basically, an associated type bound can be either `Trait<Assoc: Trait>` or `Self::Assoc: Trait`. The former is included in `explicit_implied_predicates_of()` and therefore in elaboration, but the later is not. We included both, so fix that.
This does not fix the fundamental issue that cycles in elaboration can cause hangs/stack overflows, just this incorrect case. rustc deals with cycles by detecting them ahead of time (before any elaboration) and aborting with an error, I'm not sure yet how to handle them for r-a.
Also refactor the code a bit (the hundredth time) in an attempt to make it clearer, and return iterators instead of slices from the functions to be more flexible.