diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index c3a8e0362fee..513a2a71d666 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -479,13 +479,14 @@ pub(crate) fn hover_for_definition( Definition::BuiltinType(it) => Some(it.ty(db)), _ => None, }; - let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default(); + let notable_traits = def_ty.as_ref().map(|ty| notable_traits(db, ty)).unwrap_or_default(); let subst_types = subst.map(|subst| subst.types(db)); let (markup, range_map) = render::definition( sema.db, def, famous_defs.as_ref(), + def_ty, ¬able_traits, macro_arm, render_extras, diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index da4f185d7564..7737723788b1 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -454,6 +454,7 @@ pub(super) fn definition( db: &RootDatabase, def: Definition, famous_defs: Option<&FamousDefs<'_, '_>>, + def_ty: Option>, notable_traits: &[(Trait, Vec<(Option>, Name)>)], macro_arm: Option, render_extras: bool, @@ -589,6 +590,18 @@ pub(super) fn definition( _ => None, }; + let type_params_info = || { + if matches!(def, Definition::GenericParam(_)) { + return None; + } + // FIXME: Show nested type params, such as `Vec` shows `T` and `A` + let type_param = def_ty?.as_type_param(db)?; + if type_param.is_implicit(db) || type_param.trait_bounds(db).is_empty() { + return None; + } + Some(type_param.display(db, display_target).to_string()) + }; + let layout_info = || match def { Definition::Field(it) => render_memory_layout( config.memory_layout, @@ -788,6 +801,10 @@ pub(super) fn definition( desc.push_str(" = "); desc.push_str(&value); } + if let Some(type_params_info) = type_params_info() { + desc.push_str("\nwhere\n "); + desc.push_str(&type_params_info); + } let subst_types = match config.max_subst_ty_len { SubstTyLen::Hide => String::new(), diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 30644fe2db89..d6d56a474a31 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -9838,6 +9838,134 @@ fn fn_$0( ); } +#[test] +fn test_hover_function_param_generic_bounds() { + check( + r#" +//- minicore: sized +trait Bound {} +fn foo(param: T) { + let _ = param$0; +} + "#, + expect![[r#" + *param* + + ```rust + param: T + where + T: Bound + ``` + "#]], + ); + + check( + r#" +//- minicore: sized +trait Bound {} +fn foo(param: T) +where + T: Bound, +{ + let _ = param$0; +} + "#, + expect![[r#" + *param* + + ```rust + param: T + where + T: Bound + ``` + "#]], + ); + + check( + r#" +//- minicore: sized +trait Bound {} +fn foo(param: T) +where + T: Bound, +{ + let used$0 = param; +} + "#, + expect![[r#" + *used* + + ```rust + let used: T + where + T: Bound + ``` + + --- + + type param may need Drop + "#]], + ); + + check( + r#" +//- minicore: sized +trait Bound {} +trait Bound2 {} +fn foo(param: T) +where + T: Bound, + T: Bound2, +{ + let used$0 = param; +} + "#, + expect![[r#" + *used* + + ```rust + let used: T + where + T: Bound + Bound2 + ``` + + --- + + type param may need Drop + "#]], + ); + + // XXX: Maybe `U` has more bounds that need to be show + check( + r#" +//- minicore: sized +trait Bound {} +trait Bound1 {} +struct Foo { field: T } +fn foo(param: Foo) { + let _ = param.field$0; +} + "#, + expect![[r#" + *field* + + ```rust + ra_test_fixture::Foo + ``` + + ```rust + field: T + where + T: Bound + ``` + + --- + + `T` = `U` + "#]], + ); +} + #[test] fn hover_path_inside_block_scope() { check(