rust-lang / rust-lang/rust

Bevy traits slow with -Znext-solver=globally

Open
#158,103 13 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug I-compiletime needs-triage T-types WG-trait-system-refactor
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Edit: @eugineerd below has a simple macro-less reproduction which is just the same line repeated 80 times

rust-analyzer version: rust-analyzer version: 0.4.2940-standalone

rustc version: rustc 1.98.0-nightly (57d06900f 2026-05-27)

editor or extension: vscode, extension: 0.4.2940

relevant settings: "rust-analyzer.server.extraEnv": {"RA_PROFILE": "*>500",},

repository link (if public, optional): https://github.com/bevyengine/bevy/tree/c6f634ca9f406d68ba5109d921247b654cb42c10

code snippet to reproduce: https://github.com/bevyengine/bevy/blob/c6f634ca9f406d68ba5109d921247b654cb42c10/examples/ui/widgets/feathers_gallery.rs

In the file above, specifically in the normal rust expressions inside bsn! macro invocation in the function "demo_column_1", a simple autocomplete takes more than 18s.

The macro might seem like a smoking gun here, but it struggles just the same after expanding it.
At the same time, the deeply nested nature of the expanded code seemed like an issue, but i tested changing the macro to output a lot of let bindings which are later used and combined into the final value, but this seemed to have made inference slower, even if each let binding is of type Box<dyn Trait> (Trait being the same for all). So it probably isn't the macro, but something else.

Of course this is a worst-case, an enormous 400 line macro invocation which expands to more than 1k lines of code, but we hope smaller versions of this can become very common for users of bevy.

This is all on a Ryzen 9 9900X with 32gb of RAM, not the weakest machine by far.

I've recorded a profile of one way this issue becomes obvious (autocomplete inside a closure in the function body) with samply. Sadly, thats not even necessary for this to be an issue: simply having the file open causes operations in all other files to take 18s or more.

samply command:

sudo sysctl kernel.perf_event_mlock_kb=2048
sudo sysctl kernel.perf_event_paranoid=-1
SAMPLY_USE_DEBUGINFOD=1 samply record --profile-name rust-analyzer --output /tmp/rust-analyzer.json.gz --reuse-threads -r 20000 -p $(pgrep -o rust-analyzer)

download link for the profile file: https://share.yadamiel.com/rust-analyzer.json.gz
You can view it using samply load rust-analyzer.json.gz which will start a local webserver to serve the profile to profiler.firefox.com. Note that it by default only shows one thread, to see the full profile, select all of them.

Heres the RA_PROFILE logs of the same timespan as the samply profile

2026-06-18T20:40:16.634042933+02:00  WARN overly long loop turn took 8.267930083s:
(event handling took 94.94µs): Notification { method: "textDocument/didChange" }
(garbage collection took Some(8.26383417s))
    8267ms GlobalState::handle_event @ event = Event::Lsp 
   17742ms semantic_diagnostics
     17742ms diagnostics @ name = None 
   17742ms semantic_diagnostics
     17742ms diagnostics @ name = None 
   16641ms semantic_diagnostics
     16641ms diagnostics @ name = None 
   17769ms handle_code_action
     17742ms semantic_diagnostics
       17742ms diagnostics @ name = None 
   17769ms handle_code_action
     17742ms semantic_diagnostics
       17742ms diagnostics @ name = None 
   17844ms handle_completion
     17744ms CompletionContext::new
       17579ms CompletionContext::analyze
         17579ms SemanticsImpl::analyze_impl (2 calls)
   17841ms handle_semantic_tokens_full_delta
     17841ms highlight
       17599ms normalize_opaque_type @ goal = Goal { param_env: ParamEnv { clauses: [] }, predicate: NormalizesTo(AliasTerm { args: [], kind: OpaqueTy { def_id: InternedOpaqueTyId(InternedOpaqueTyId(Id(14f401))) }, .. }, ?0t) } def_id = InternedOpaqueTyId(InternedOpaqueTyId(Id(14f401)))  (2 calls)
         17598ms normalize_opaque_type @ goal = Goal { param_env: ParamEnv { clauses: [] }, predicate: NormalizesTo(AliasTerm { args: [], kind: OpaqueTy { def_id: InternedOpaqueTyId(InternedOpaqueTyId(Id(14f403))) }, .. }, ?0t) } def_id = InternedOpaqueTyId(InternedOpaqueTyId(Id(14f403)))  (2 calls)
           17596ms normalize_opaque_type @ goal = Goal { param_env: ParamEnv { clauses: [] }, predicate: NormalizesTo(AliasTerm { args: [], kind: OpaqueTy { def_id: InternedOpaqueTyId(InternedOpaqueTyId(Id(14f404))) }, .. }, ?0t) } def_id = InternedOpaqueTyId(InternedOpaqueTyId(Id(14f404)))  (4 calls)
             17591ms infer_query
                 888ms impl_trait_ref @ impl_id = ImplId(ImplId(1248f2))  (1743753 calls)
2026-06-18T20:40:49.750369849+02:00  WARN overly long loop turn took 7.168189722s:
(event handling took 187.615µs): Notification { method: "textDocument/didChange" }
(garbage collection took Some(7.162855639s))
    7176ms GlobalState::handle_event @ event = Event::Lsp 
   17155ms semantic_diagnostics
     17154ms diagnostics @ name = None 
   18677ms semantic_diagnostics
     18677ms diagnostics @ name = None 
   18677ms semantic_diagnostics
     18677ms diagnostics @ name = None 
   18458ms handle_code_action
     18453ms semantic_diagnostics
       18453ms diagnostics @ name = None 
   18711ms handle_code_action
     18681ms semantic_diagnostics
       18680ms diagnostics @ name = None 
   18799ms handle_semantic_tokens_full_delta
     18799ms highlight
       18505ms normalize_opaque_type @ goal = Goal { param_env: ParamEnv { clauses: [] }, predicate: NormalizesTo(AliasTerm { args: [], kind: OpaqueTy { def_id: InternedOpaqueTyId(InternedOpaqueTyId(Id(14f401))) }, .. }, ?0t) } def_id = InternedOpaqueTyId(InternedOpaqueTyId(Id(14f401)))  (2 calls)
         18503ms normalize_opaque_type @ goal = Goal { param_env: ParamEnv { clauses: [] }, predicate: NormalizesTo(AliasTerm { args: [], kind: OpaqueTy { def_id: InternedOpaqueTyId(InternedOpaqueTyId(Id(14f403))) }, .. }, ?0t) } def_id = InternedOpaqueTyId(InternedOpaqueTyId(Id(14f403)))  (2 calls)
           18500ms normalize_opaque_type @ goal = Goal { param_env: ParamEnv { clauses: [] }, predicate: NormalizesTo(AliasTerm { args: [], kind: OpaqueTy { def_id: InternedOpaqueTyId(InternedOpaqueTyId(Id(14f404))) }, .. }, ?0t) } def_id = InternedOpaqueTyId(InternedOpaqueTyId(Id(14f404)))  (4 calls)
   18771ms handle_completion_resolve
     18668ms CompletionContext::new
       18570ms CompletionContext::analyze
         18570ms SemanticsImpl::analyze_impl (2 calls)
           18570ms infer_query
               903ms impl_trait_ref @ impl_id = ImplId(ImplId(1248f2))  (1743753 calls)

According to the samply profile, at least 73% of samples happened due to hir_ty::infer:

Image

The flamegraph is also fun to view. so much hir_ty::infer:

Image

I'm very open to suggestions what to try, guidance how to better profile/narrow down the issue or just ideas how to make the macro more rust-analyzer friendly.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with examples/ui/widgets/feathers_gallery.rs, especially demo_column_1 and the repeated expressions inside the bsn! invocation, then reproduce the delay with -Znext-solver=globally. Use the supplied samply profile and RA_PROFILE logs to trace hir_ty::infer, normalize_opaque_type, and impl_trait_ref; done means identifying and fixing the cause so completion and related operations no longer take roughly 18 seconds on the reproduction.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers, performance
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.