rust-analyzer icon indicating copy to clipboard operation
rust-analyzer copied to clipboard

Auto completion failed with nalgebra

Open Niwol opened this issue 1 month ago • 6 comments

rust-analyzer version: 0.3.2693 / 0.3.2702

rustc version: rustc 1.91.1 (ed61e7d7e 2025-11-07)

editor or extension: VSCode

relevant settings: None

repository link (if public, optional): -

code snippet to reproduce:

use nalgebra as na;

fn main() {
    let a = na::dvector![1.0, 2.0];
    // popup show here
    a.
}

I have a very specific error with the nalgebra crate which fails to autocomplete on nalgebra stucts. Whenever I try to access a method or member variable of a nalgebra struct I don't have any autocompletion anymore and a popup shows in VSCode with the message: "Request textDocument/completion failed. Source: rust-analyzer" if I click on "Go to output": [Error - 11:27:17 AM] Request textDocument/completion failed. Message: request handler panicked: cannot find !BoundConst { var: 4 } in param-env: ParamEnv { clauses: [ ...

This error only appeared with nalgebra, other crates just work fine. I have entirely reinstalled Rust and VSCode but this didn't help. The only way to fix this error for me was to switch back the rust-analyzer extension in VSCode to 0.3.2683. I hope this is enough information to reproduce the error.

Niwol avatar Dec 07 '25 10:12 Niwol

Maybe a similar issue with https://github.com/rust-lang/rust-analyzer/issues/21173

ShoyuVanilla avatar Dec 08 '25 07:12 ShoyuVanilla

I'm seeing the same exact error just after installing nalgebra. In case it helps, here is more of the error message:

Message: request handler panicked: cannot find `!BoundConst { var: 4 }` in param-env: ParamEnv {
    clauses: [
        Clause(
            Binder {
                value: TraitPredicate(!0: Sized, polarity:Positive),
                bound_vars: [],
            },
        ),
        Clause(
            Binder {
                value: TraitPredicate(!1: Sized, polarity:Positive),
                bound_vars: [],
            },
        ),
        ...
        Clause(
            Binder {
                value: OutlivesPredicate(
                    !1,
                    'static,
                ),
                bound_vars: [],
            },
        ),
        Clause(
            Binder {
                value: TraitPredicate(!2: Dim, polarity:Positive),
                bound_vars: [],
            },
        ),
        Clause(
            Binder {
                value: TraitPredicate(!2: Sync, polarity:Positive),
                bound_vars: [],
            },
        ),
       ...
  ]
}

stack backtrace:
   0: std::panicking::panic_handler
             at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library\std\src\panicking.rs:698
   1: core::panicking::panic_fmt
             at /rustc/ed61e7d7e242494fb7057f2657300d9e77bb4fcb/library\core\src\panicking.rs:75
   2: <<I as ra_ap_rustc_type_ir::interner::Interner>::PlaceholderConst as ra_ap_rustc_type_ir::inherent::PlaceholderConst<I>>::find_const_ty_from_env
   3: ra_ap_rustc_next_trait_solver::solve::<impl ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>>::compute_const_arg_has_type_goal
   4: hir_ty::next_solver::infer::context::<impl ra_ap_rustc_type_ir::infer_ctxt::InferCtxtLike for hir_ty::next_solver::infer::InferCtxt>::enter_forall
   5: ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>::enter_canonical
   6: ra_ap_rustc_type_ir::search_graph::SearchGraph<D,X>::evaluate_goal_in_task
   7: ra_ap_rustc_type_ir::search_graph::SearchGraph<D,X>::evaluate_goal
   8: ra_ap_rustc_type_ir::inherent::Predicate::as_normalizes_to
   9: ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>::try_evaluate_added_goals
  10: ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>::evaluate_added_goals_and_make_canonical_response
  11: hir_ty::next_solver::infer::context::<impl ra_ap_rustc_type_ir::infer_ctxt::InferCtxtLike for hir_ty::next_solver::infer::InferCtxt>::probe::{{closure}}
  12: hir_ty::next_solver::infer::context::<impl ra_ap_rustc_type_ir::infer_ctxt::InferCtxtLike for hir_ty::next_solver::infer::InferCtxt>::probe
  13: hir_def::_::<impl hir_def::BlockId>::loc
  14: ra_ap_rustc_next_trait_solver::solve::eval_ctxt::probe::TraitProbeCtxt<D,I,F>::enter
  15: ra_ap_rustc_next_trait_solver::solve::trait_goals::<impl ra_ap_rustc_next_trait_solver::solve::assembly::GoalKind<D,I> for ra_ap_rustc_type_ir::predicate::TraitPredicate<I>>::consider_impl_candidate
  16: ra_ap_rustc_next_trait_solver::solve::assembly::<impl ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>>::assemble_impl_candidates::{{closure}}
  17: hir_ty::method_resolution::TraitImpls::for_each_crate_and_block_trait_and_type
  18: <hir_ty::next_solver::interner::DbInterner as ra_ap_rustc_type_ir::interner::Interner>::for_each_relevant_impl
  19: ra_ap_rustc_next_trait_solver::solve::trait_goals::<impl ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>>::compute_trait_goal
  20: hir_ty::next_solver::infer::context::<impl ra_ap_rustc_type_ir::infer_ctxt::InferCtxtLike for hir_ty::next_solver::infer::InferCtxt>::probe
  21: ra_ap_rustc_next_trait_solver::solve::eval_ctxt::probe::ProbeCtxt<D,I,F,T>::enter
  22: ra_ap_rustc_next_trait_solver::solve::normalizes_to::<impl ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>>::compute_normalizes_to_goal
  23: hir_ty::next_solver::infer::context::<impl ra_ap_rustc_type_ir::infer_ctxt::InferCtxtLike for hir_ty::next_solver::infer::InferCtxt>::enter_forall
  24: ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>::enter_canonical
  25: ra_ap_rustc_type_ir::search_graph::SearchGraph<D,X>::evaluate_goal_in_task
  26: ra_ap_rustc_type_ir::search_graph::SearchGraph<D,X>::evaluate_goal
  27: ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>::try_evaluate_added_goals
  28: ra_ap_rustc_next_trait_solver::solve::alias_relate::<impl ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>>::compute_alias_relate_goal
  29: hir_ty::next_solver::infer::context::<impl ra_ap_rustc_type_ir::infer_ctxt::InferCtxtLike for hir_ty::next_solver::infer::InferCtxt>::enter_forall
  30: ra_ap_rustc_next_trait_solver::solve::eval_ctxt::EvalCtxt<D,I>::enter_canonical
  31: ra_ap_rustc_type_ir::search_graph::SearchGraph<D,X>::evaluate_goal_in_task
  32: ra_ap_rustc_type_ir::search_graph::SearchGraph<D,X>::evaluate_goal
  33: hir_ty::next_solver::fulfill::FulfillmentCtxt::try_evaluate_obligations
  34: core::ops::function::FnOnce::call_once
  35: hir_ty::infer::unify::could_unify_impl
  36: hir::Type::could_unify_with
  37: ide_completion::render::match_types
  38: <core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::try_fold
  39: ide_completion::render::function::render_method
  40: ide_completion::render::function::render_method
  41: ide_completion::completions::Completions::add_method
  42: <ide_completion::completions::dot::complete_methods::Callback<F> as hir::MethodCandidateCallback>::on_inherent_method
  43: hir::Type::iterate_method_candidates_split_inherent
  44: ide_completion::completions::dot::complete_dot
  45: ide_completion::completions::complete_name_ref
  46: ide_completion::completions
  47: salsa::cancelled::Cancelled::catch
  48: std::thread::local::LocalKey<T>::with
  49: ide::Analysis::completions
  50: rust_analyzer::handlers::request::handle_completion
  51: <[T] as core::fmt::Debug>::fmt

aj-r avatar Dec 10 '25 23:12 aj-r

I'm not sure that this is the same as #21173 since the ParamEnv was empty in that case, but not empty here. But I suppose we can see if #21235 fixes it?

aj-r avatar Dec 11 '25 00:12 aj-r

Not fixed by https://github.com/rust-lang/rust-analyzer/pull/21235.

ChayimFriedman2 avatar Dec 11 '25 00:12 ChayimFriedman2

So here the situation is way more complicated than in https://github.com/rust-lang/rust-analyzer/pull/21235.

In short, what happens is that we try to unify two types originating from different GenericDefIds. Non-luckily for us, they both contain generic params. Trying to treat generic params from different owners uniformly is a catastrophic idea for the solver, and the source for the panic here.

Unfortunately, I believe our code is riddled with such things. This is why I was leaving such comments:

https://github.com/rust-lang/rust-analyzer/blob/fface27171988b3d605ef45cf986c25533116f7e/crates/hir/src/lib.rs#L2282

The solution, as I imagine it, is to have a separate hir type BoundType that can contain params. Type will be guaranteed to not contain TyKind::Param (recursively). Going froma BoundType to a Type is possible by instantiating it, or by verifying it contains no params. Actions between BoundParams of different owners are forbidden (fallible/panic).

@rust-lang/rust-analyzer What are your thoughts? Do you agree this is a better API?

ChayimFriedman2 avatar Dec 11 '25 00:12 ChayimFriedman2

I've always thought we need some kind of better API for this, yeah. BoundType seems a bit confusing to me, from the names I'd have expected them to work the other way around. BindableType would maybe express the same thing but clearer, or PolyType if we want to go a bit more jargon-y.

You don't necessarily go from a BoundType to a Type though, do you? If you instantiate e.g. an ADT's type in the context of a function, where that function might have its own type parameters, you just go from the ADT's set of params to the function's set of params. So I think you need to be able to instantiate a BoundType (or however it's called) with a set of other BoundTypes, in which case it again becomes a BoundType but in the other context. And then the question is how often we really need Type, isn't it? 🤔 Maybe that would be served better by a method that allows transferring a BoundType to another context, checking that it contains no type parameters. And in that case we don't need Type anymore, so we could call BoundType just Type 😄 I think that was part of the original idea of having Type carry a param env (trait env) in the first place, actually.

flodiebold avatar Dec 11 '25 09:12 flodiebold