From 405520150d851034aa6e5909b348a38bb2e2b1f2 Mon Sep 17 00:00:00 2001
From: Shoyu Vanilla <modulo641@gmail.com>
Date: Fri, 6 Dec 2024 01:10:46 +0900
Subject: [PATCH] fix: Panic when displaying generic params with defaults

---
 crates/hir-ty/src/display.rs  |  6 ++++-
 crates/ide/src/hover/tests.rs | 50 +++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 94a340fbec..3dfa0e97ce 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -1047,10 +1047,14 @@ impl HirDisplay for Ty {
                     );
                     // 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 {
+                        let params_len = parameters.len();
                         // `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;
+                        assert!(params_len >= parameters.len());
+                        let defaults = params_len - parameters.len();
+                        let without_impl =
+                            self_param as usize + type_ + const_ + lifetime - defaults;
                         // parent's params (those from enclosing impl or trait, if any).
                         let (fn_params, parent_params) = parameters.split_at(without_impl + impl_);
 
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 0986d5542c..1c08514a67 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -9416,3 +9416,53 @@ fn f<T: UnCompat$0>
         "#]],
     );
 }
+
+#[test]
+fn issue_18613() {
+    check(
+        r#"
+fn main() {
+    struct S<T, D = bool>();
+    let x$0 = S::<()>;
+}"#,
+        expect![[r#"
+            *x*
+
+            ```rust
+            let x: fn S<()>() -> S<()>
+            ```
+
+            ---
+
+            size = 0, align = 1
+        "#]],
+    );
+
+    check(
+        r#"
+pub struct Global;
+pub struct Box<T, A = Global>(T, A);
+
+impl<T> Box<T> {
+    pub fn new(x: T) -> Self { loop {} }
+}
+
+pub struct String;
+
+fn main() {
+    let box_value$0 = Box::<String>new();
+}
+"#,
+        expect![[r#"
+            *box_value*
+
+            ```rust
+            let box_value: fn Box<String>(String, Global) -> Box<String>
+            ```
+
+            ---
+
+            size = 0, align = 1
+        "#]],
+    );
+}