rust-lang / rust-analyzer

A Rust compiler front-end for IDEs
https://rust-analyzer.github.io/
Apache License 2.0
14.32k stars 1.61k forks source link

Slow method completion when `impl IntoIterator` argument is present #18456

Open Fuuzetsu opened 3 weeks ago

Fuuzetsu commented 3 weeks ago

rust-analyzer version: rust-analyzer version: 2024-09-02 [/nix/store/4n7jkl09aplbdbchiflmscppqlr0d2pk-rust-analyzer-2024-09-02/bin/rust-analyzer] rustc version: (eg. output of rustc -V) rustc 1.82.0 (f6e511eec 2024-10-15)

editor or extension: (eg. VSCode, Vim, Emacs, etc. For VSCode users, specify your extension version; for users of other editors, provide the distribution if applicable) VSCode with v0.3.2029 extension version

relevant settings: (eg. client settings, or environment variables like CARGO, RUSTC, RUSTUP_HOME or CARGO_HOME)

    "rust-analyzer.trace.server": "off",
    "rust-analyzer.trace.extension": true,
    "rust-analyzer.server.extraEnv": {
        "RA_PROFILE": "*@50>500"
    }

code snippet to reproduce:

I don't have a minimal example that still reproduces a problem in tiny project. Maybe there are some extra conditions to trigger this.

I start with this code:

struct Foo {
    x: i32
}

fn foo(
    ui: Foo,
    // extra_gaps: impl IntoIterator<Item = ()>,    
) {
    let x = ui.
}

Once I type the . on the ui., RA goes to fetch completions and it's normal speed.

    2298ms handle_completion
      2066ms import_on_the_fly_method @ potential_import_name = "" 
        2064ms ImportAssets::search_for_imports
          2064ms ImportAssets::search_for
            2064ms ImportAssets::trait_applicable_items
              1085ms items_with_name @ name = "" assoc_item_search = AssocItemsOnly crate = Some("viewer") 
                1085ms find_items
                  1067ms crate_symbols
                    1066ms SymbolsDatabase::module_symbols @ module = Module { id: ModuleId { krate: Idx::<CrateData>(747), block: None, local_id: Idx::<ModuleData>(0) } }  (264 calls)
                      1064ms module_symbols (264 calls)
                         586ms DefDatabase::body @ def = FunctionId(FunctionId(10932))  (794 calls)
                           526ms body_with_source_map_query (604 calls)
               975ms iterate_method_candidates_with_traits
                 975ms iterate_method_candidates_dyn @ with_local_impls = 214 traits_in_scope = 214 name = None 
                   975ms iterate_method_candidates_dyn @ mode = MethodCall name = None traits_in_scope_len = 214 
                     975ms iterate_method_candidates_with_autoref @ name = None 
                       975ms iterate_method_candidates_by_receiver @ name = None  (3 calls)
                         975ms run_in_snapshot (6 calls)
                           975ms iterate_trait_method_candidates @ name = None  (5 calls)
                             935ms HirDatabase::trait_solve @ krate = Idx::<CrateData>(747) block = None goal = Canonical { value: InEnvironment { environment: Env([]), goal: Implemented(AdtId(StructId(StructId(1795)))<[]>: TraitId(377)) }, binders: [] }  (359 calls)
                               934ms trait_solve_query @ detail = "IntoEither"  (333 calls)
                                 933ms solve  @ krate = Idx::<CrateData>(747) block = None  (333 calls)

but if I uncomment extra_gaps, it suddenly takes multiple times longer!

   17252ms handle_completion
     16840ms import_on_the_fly_method @ potential_import_name = "" 
       16687ms ImportAssets::search_for_imports
         16687ms ImportAssets::search_for
           16687ms ImportAssets::trait_applicable_items
              1018ms items_with_name @ name = "" assoc_item_search = AssocItemsOnly crate = Some("viewer") 
                1018ms find_items
                  1000ms crate_symbols
                    1000ms SymbolsDatabase::module_symbols @ module = Module { id: ModuleId { krate: Idx::<CrateData>(747), block: None, local_id: Idx::<ModuleData>(0) } }  (264 calls)
                       998ms module_symbols (264 calls)
                         539ms DefDatabase::body @ def = FunctionId(FunctionId(10932))  (794 calls)
             15664ms iterate_method_candidates_with_traits
               15664ms iterate_method_candidates_dyn @ with_local_impls = 214 traits_in_scope = 214 name = None 
                 15664ms iterate_method_candidates_dyn @ mode = MethodCall name = None traits_in_scope_len = 214 
                   15664ms iterate_method_candidates_with_autoref @ name = None 
                     15664ms iterate_method_candidates_by_receiver @ name = None  (3 calls)
                       15664ms run_in_snapshot (6 calls)
                         15664ms iterate_trait_method_candidates @ name = None  (5 calls)
                           15622ms HirDatabase::trait_solve @ krate = Idx::<CrateData>(747) block = None goal = Canonical { value: InEnvironment { environment: Env([for<> FromEnv(!0_42: TraitId(229)), for<> AliasEq(AliasTy(?) = 0<[]>), for<> FromEnv(!0_42: TraitId(37))]), goal: Implemented(AdtId(StructId(StructId(1795)))<[]>: TraitId(377)) }, binders: [] }  (359 calls)
                             15528ms trait_solve_query @ detail = "FormatWith"  (45 calls)
                               15528ms solve  @ krate = Idx::<CrateData>(747) block = None  (45 calls)
                                  1278ms HirDatabase::impl_datum @ krate = Idx::<CrateData>(747) impl_id = ImplId(77943)  (2110906 calls)

Here's from another attempt with the argument present, this time it took even longer

   56935ms handle_completion
     56694ms import_on_the_fly_method @ potential_import_name = "" 
       56694ms ImportAssets::search_for_imports
         56694ms ImportAssets::search_for
           56693ms ImportAssets::trait_applicable_items
              1108ms items_with_name @ name = "" assoc_item_search = AssocItemsOnly crate = Some("viewer") 
                1108ms find_items
                  1086ms crate_symbols
                    1085ms SymbolsDatabase::module_symbols @ module = Module { id: ModuleId { krate: Idx::<CrateData>(747), block: None, local_id: Idx::<ModuleData>(0) } }  (264 calls)
                      1083ms module_symbols (264 calls)
                         721ms DefDatabase::body @ def = FunctionId(FunctionId(10932))  (794 calls)
                           685ms body_with_source_map_query (643 calls)
             55581ms iterate_method_candidates_with_traits
               55581ms iterate_method_candidates_dyn @ with_local_impls = 214 traits_in_scope = 214 name = None 
                 55581ms iterate_method_candidates_dyn @ mode = MethodCall name = None traits_in_scope_len = 214 
                   55581ms iterate_method_candidates_with_autoref @ name = None 
                     55581ms iterate_method_candidates_by_receiver @ name = None  (3 calls)
                       55581ms run_in_snapshot (6 calls)
                         55581ms iterate_trait_method_candidates @ name = None  (4 calls)
                           55542ms HirDatabase::trait_solve @ krate = Idx::<CrateData>(747) block = None goal = Canonical { value: InEnvironment { environment: Env([for<> FromEnv(!0_42: TraitId(229)), for<> AliasEq(AliasTy(?) = 0<[]>), for<> FromEnv(!0_42: TraitId(37))]), goal: Implemented(AdtId(StructId(StructId(1795)))<[]>: TraitId(377)) }, binders: [] }  (306 calls)
                             55510ms trait_solve_query @ detail = "IntoEither"  (295 calls)
                               55508ms solve  @ krate = Idx::<CrateData>(747) block = None  (295 calls)
                                  1467ms HirDatabase::associated_ty_data @ id = AssocTypeId(6428)  (2926649 calls)
                                  2064ms HirDatabase::associated_ty_value @ krate = Idx::<CrateData>(747) id = AssociatedTyValueId(11017)  (2916522 calls)
                                  5964ms HirDatabase::impl_datum @ krate = Idx::<CrateData>(747) impl_id = ImplId(13804)  (10557056 calls)

I wish I had a better reproducer but I do not. I can try to answer any questions or run with some other debug settings if needed. Let me know.

Fuuzetsu commented 3 weeks ago

I guess for all traits in scope it solves for the generic IntoTrait and that takes a lot of time. I suppose this would explain why in a small clean project it doesn't take a long time.

I don't understand why it's trying to do this at all though: I'm trying to do completion on Foo and I am not touching the impl so it shouldn't need to do this at all.