about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs35
2 files changed, 50 insertions, 2 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 3dfa0e97cec..de8ce56df64 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -1053,8 +1053,21 @@ impl HirDisplay for Ty {
                             generic_args_sans_defaults(f, Some(generic_def_id), parameters);
                         assert!(params_len >= parameters.len());
                         let defaults = params_len - parameters.len();
-                        let without_impl =
-                            self_param as usize + type_ + const_ + lifetime - defaults;
+
+                        // Normally, functions cannot have default parameters, but they can,
+                        // for function-like things such as struct names or enum variants.
+                        // The former cannot have defaults but parents, and the later cannot have
+                        // parents but defaults.
+                        // So, if `parent_len` > 0, it have a parent and thus it doesn't have any
+                        // default. Therefore, we shouldn't subtract defaults because those defaults
+                        // are from their parents.
+                        // And if `parent_len` == 0, either parents don't exists or they don't have
+                        // any defaults. Thus, we can - and should - subtract defaults.
+                        let without_impl = if parent_len > 0 {
+                            params_len - parent_len - impl_
+                        } else {
+                            params_len - parent_len - impl_ - 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/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index ea18b89c5c9..3786a3427fd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -9465,4 +9465,39 @@ fn main() {
             size = 0, align = 1
         "#]],
     );
+
+    check(
+        r#"
+//- minicore: eq
+pub struct RandomState;
+pub struct HashMap<K, V, S = RandomState>(K, V, S);
+
+impl<K, V> HashMap<K, V, RandomState> {
+    pub fn new() -> HashMap<K, V, RandomState> {
+        loop {}
+    }
+}
+
+impl<K, V, S> PartialEq for HashMap<K, V, S> {
+    fn eq(&self, other: &HashMap<K, V, S>) -> bool {
+        false
+    }
+}
+
+fn main() {
+    let s$0 = HashMap::<_, u64>::ne;
+}
+"#,
+        expect![[r#"
+            *s*
+
+            ```rust
+            let s: fn ne<HashMap<{unknown}, u64>>(&HashMap<{unknown}, u64>, &HashMap<{unknown}, u64>) -> bool
+            ```
+
+            ---
+
+            size = 0, align = 1
+        "#]],
+    );
 }