Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #18675 from ShoyuVanilla/issue-18664
fix: Panic when displaying generic params with defaults, again
Lukas Wirth 2024-12-12
parent 0ae3813 · parent 94ec3fe · commit cde07f2
-rw-r--r--crates/hir-ty/src/display.rs17
-rw-r--r--crates/ide/src/hover/tests.rs35
2 files changed, 50 insertions, 2 deletions
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 3dfa0e97ce..de8ce56df6 100644
--- a/crates/hir-ty/src/display.rs
+++ b/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/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 0139c04af8..50d0d4c5df 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/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
+ "#]],
+ );
}