Repository: rust-lang/rust-analyzer (rust)

Issue:
Chalk panic on displaying type of trait function with type parameter
**rust-analyzer version**: rust-analyzer 0.0.0 (18414cdf64 2024-08-12)

**rustc version**: rustc 1.80.1 (3f5fd8dd4 2024-08-06)

**code snippet to reproduce**: 
```rust
trait T {
    fn f<A>();
}

struct S {}
impl T for S {
    fn f<A>() {}
}

fn main() {
    let x = S::f::<i32>;
}
```
Panic:
```
thread 'main' panicked at /Users/davidrichey/.cargo/registry/src/index.crates.io-6f17d22bba15001f/chalk-ir-0.98.0/src/lib.rs:2238:9:
assertion `left == right` failed
  left: 2
 right: 1
stack backtrace:
   0: rust_begin_unwind
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:652:5
   1: core::panicking::panic_fmt
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/panicking.rs:72:14
   2: core::panicking::assert_failed_inner
   3: core::panicking::assert_failed
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/panicking.rs:363:5
   4: chalk_ir::Binders<T>::substitute
             at /Users/davidrichey/.cargo/registry/src/index.crates.io-6f17d22bba15001f/chalk-ir-0.98.0/src/lib.rs:2238:9
   5: hir_ty::display::generic_args_sans_defaults::{{closure}}::{{closure}}
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/hir-ty/src/display.rs:1468:33
   6: <core::option::Option<T> as stdx::IsNoneOr>::is_none_or
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/stdx/src/lib.rs:317:24
   7: hir_ty::display::generic_args_sans_defaults::{{closure}}
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/hir-ty/src/display.rs:1465:21
   8: hir_ty::display::generic_args_sans_defaults
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/hir-ty/src/display.rs:1473:24
   9: <chalk_ir::Ty<hir_ty::interner::Interner> as hir_ty::display::HirDisplay>::hir_fmt
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/hir-ty/src/display.rs:1031:29
  10: hir_ty::display::HirDisplayWrapper<T>::write_to
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/hir-ty/src/display.rs:399:9
  11: ide::inlay_hints::label_of_ty::rec
  12: ide::inlay_hints::label_of_ty
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/inlay_hints.rs:430:13
  13: ide::inlay_hints::bind_pat::hints
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs:70:21
  14: ide::inlay_hints::hints
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/inlay_hints.rs:590:25
  15: ide::inlay_hints::inlay_hints::{{closure}}
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/inlay_hints.rs:508:28
  16: core::iter::traits::iterator::Iterator::for_each::call::{{closure}}
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/iter/traits/iterator.rs:815:29
  17: core::iter::adapters::map::map_fold::{{closure}}
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/iter/adapters/map.rs:89:21
  18: core::iter::adapters::filter_map::filter_map_fold::{{closure}}
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/iter/adapters/filter_map.rs:40:20
  19: core::iter::traits::iterator::Iterator::fold
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/iter/traits/iterator.rs:2589:21
  20: <core::iter::adapters::filter_map::FilterMap<I,F> as core::iter::traits::iterator::Iterator>::fold
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/iter/adapters/filter_map.rs:148:9
  21: <core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/iter/adapters/map.rs:129:9
  22: core::iter::traits::iterator::Iterator::for_each
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/iter/traits/iterator.rs:818:9
  23: ide::inlay_hints::inlay_hints
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/inlay_hints.rs:517:21
  24: ide::Analysis::inlay_hints::{{closure}}
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/lib.rs:434:27
  25: ide::Analysis::with_db::{{closure}}
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/lib.rs:824:29
  26: std::panicking::try::do_call
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:559:40
  27: std::panicking::try
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:523:19
  28: std::panic::catch_unwind
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panic.rs:149:14
  29: salsa::Cancelled::catch
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/salsa/src/lib.rs:633:15
  30: ide::Analysis::with_db
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/lib.rs:824:9
  31: ide::Analysis::inlay_hints
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/lib.rs:434:9
  32: ide::static_index::StaticIndex::add_file
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/static_index.rs:126:27
  33: ide::static_index::StaticIndex::compute
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/ide/src/static_index.rs:257:13
  34: rust_analyzer::cli::scip::<impl rust_analyzer::cli::flags::Scip>::run
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs:66:18
  35: rust_analyzer::actual_main
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/rust-analyzer/src/bin/main.rs:88:46
  36: rust_analyzer::main
             at /Users/davidrichey/Desktop/test/rust-analyzer/crates/rust-analyzer/src/bin/main.rs:39:9
  37: core::ops::function::FnOnce::call_once
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
```

Pull request:
fix: Panic while hovering associated function with type annotation on generic param that not inherited from its container type
Fixes #17871

We call `generic_args_sans_defaults` here;

https://github.com/rust-lang/rust-analyzer/blob/64a140527b383e3a2fe95908881624fc5374c60c/crates/hir-ty/src/display.rs#L1021-L1034

but the following substitution inside that function panic in #17871;

https://github.com/rust-lang/rust-analyzer/blob/64a140527b383e3a2fe95908881624fc5374c60c/crates/hir-ty/src/display.rs#L1468

it's because the `Binders.binder` inside `default_parameters` has a same length with the generics of the function we are hovering on, but the generics of it is split into two, `fn_params` and `parent_params`.
Because of this, it may panic if the function has one or more default parameters and both `fn_params` and `parent_params` are non-empty, like the case in the title of this PR.

So, we must call `generic_args_sans_default` first and then split it into `fn_params` and `parent_params`

Patch:
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 7c481958d1..5a96d396ab 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -1019,26 +1019,25 @@ impl HirDisplay for Ty {
                     let (parent_len, self_param, type_, const_, impl_, lifetime) =
                         generics.provenance_split();
                     let parameters = parameters.as_slice(Interner);
+                    debug_assert_eq!(
+                        parameters.len(),
+                        parent_len + self_param as usize + type_ + const_ + impl_ + lifetime
+                    );
                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
                     if parameters.len() - impl_ > 0 {
                         // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes
+                        let parameters =
+                            generic_args_sans_defaults(f, Some(generic_def_id), parameters);
                         let without_impl = self_param as usize + type_ + const_ + lifetime;
                         // parent's params (those from enclosing impl or trait, if any).
                         let (fn_params, parent_params) = parameters.split_at(without_impl + impl_);
-                        debug_assert_eq!(parent_params.len(), parent_len);
-
-                        let parent_params =
-                            generic_args_sans_defaults(f, Some(generic_def_id), parent_params);
-                        let fn_params =
-                            &generic_args_sans_defaults(f, Some(generic_def_id), fn_params)
-                                [0..without_impl];
 
                         write!(f, "<")?;
                         hir_fmt_generic_arguments(f, parent_params, None)?;
                         if !parent_params.is_empty() && !fn_params.is_empty() {
                             write!(f, ", ")?;
                         }
-                        hir_fmt_generic_arguments(f, fn_params, None)?;
+                        hir_fmt_generic_arguments(f, &fn_params[0..without_impl], None)?;
                         write!(f, ">")?;
                     }
                 }
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 5a7deab3a4..45d423d03c 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -1436,8 +1436,7 @@ impl<'a> InferenceContext<'a> {
         let remaining = unresolved.map(|it| path.segments()[it..].len()).filter(|it| it > &0);
         let ty = match ty.kind(Interner) {
             TyKind::Alias(AliasTy::Projection(proj_ty)) => {
-                let ty = self.table.normalize_projection_ty(proj_ty.clone());
-                self.table.resolve_ty_shallow(&ty)
+                self.db.normalize_projection(proj_ty.clone(), self.table.trait_env.clone())
             }
             _ => ty,
         };
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index 00791c5149..c46382a0ea 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -14,13 +14,13 @@ use hir_def::{
 };
 use hir_expand::name::Name;
 use intern::sym;
-use stdx::{never, panic_context};
+use stdx::panic_context;
 use triomphe::Arc;
 
 use crate::{
     db::HirDatabase, infer::unify::InferenceTable, utils::UnevaluatedConstEvaluatorFolder, AliasEq,
     AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment, Interner, ProjectionTy,
-    ProjectionTyExt, Solution, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause,
+    ProjectionTyExt, Solution, TraitRefExt, Ty, TyKind, WhereClause,
 };
 
 /// This controls how much 'time' we give the Chalk solver before giving up.
@@ -90,16 +90,6 @@ pub(crate) fn normalize_projection_query(
     projection: ProjectionTy,
     env: Arc<TraitEnvironment>,
 ) -> Ty {
-    if projection.substitution.iter(Interner).any(|arg| {
-        arg.ty(Interner)
-            .is_some_and(|ty| ty.data(Interner).flags.intersects(TypeFlags::HAS_TY_INFER))
-    }) {
-        never!(
-            "Invoking `normalize_projection_query` with a projection type containing inference var"
-        );
-        return TyKind::Error.intern(Interner);
-    }
-
     let mut table = InferenceTable::new(db, env);
     let ty = table.normalize_projection_ty(projection);
     table.resolve_completely(ty)


Test patch:
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index 26e9243e73..2819838612 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -2141,24 +2141,3 @@ fn test() {
 }"#,
     );
 }
-
-#[test]
-fn issue_17866() {
-    check_infer(
-        r#"
-trait T {
-    type A;
-}
-
-type Foo = <S as T>::A;
-
-fn main() {
-    Foo {};
-}
-"#,
-        expect![[r#"
-            60..75 '{     Foo {}; }': ()
-            66..72 'Foo {}': {unknown}
-        "#]],
-    );
-}
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 516e32ef91..18f0aeba29 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -8602,3 +8602,31 @@ fn test() {
         "#]],
     );
 }
+
+#[test]
+fn issue_17871() {
+    check(
+        r#"
+trait T {
+    fn f<A>();
+}
+
+struct S {}
+impl T for S {
+    fn f<A>() {}
+}
+
+fn main() {
+    let x$0 = S::f::<i32>;
+}
+"#,
+        expect![[r#"
+            *x*
+
+            ```rust
+            // size = 0, align = 1
+            let x: fn f<S, i32>()
+            ```
+        "#]],
+    );
+}