From 94ec3fe7ed8b34c4bd1815d765aa93bf387cfce1 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 13 Dec 2024 01:04:13 +0900 Subject: [PATCH] fix: Panic when displaying generic params with defaults, again --- crates/hir-ty/src/display.rs | 17 +++++++++++++++-- crates/ide/src/hover/tests.rs | 35 +++++++++++++++++++++++++++++++++++ 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 ea18b89c5c..3786a3427f 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); + +impl HashMap { + pub fn new() -> HashMap { + loop {} + } +} + +impl PartialEq for HashMap { + fn eq(&self, other: &HashMap) -> bool { + false + } +} + +fn main() { + let s$0 = HashMap::<_, u64>::ne; +} +"#, + expect![[r#" + *s* + + ```rust + let s: fn ne>(&HashMap<{unknown}, u64>, &HashMap<{unknown}, u64>) -> bool + ``` + + --- + + size = 0, align = 1 + "#]], + ); }