diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index fa4b4b6d24be..6b09ba3bd6b1 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -78,6 +78,17 @@ pub enum HoverDocFormat { PlainText, } +enum TyOrConst<'db> { + Const(hir::Const), + Type(hir::Type<'db>), +} + +impl<'db> TyOrConst<'db> { + fn as_type(&self) -> Option<&hir::Type<'db>> { + if let Self::Type(ty) = self { Some(ty) } else { None } + } +} + #[derive(Debug, Clone, Hash, PartialEq, Eq, UpmapFromRaFixture)] pub enum HoverAction { Runnable(Runnable), @@ -514,7 +525,7 @@ pub(crate) fn hover_for_definition( fn notable_traits<'db>( db: &'db RootDatabase, ty: &hir::Type<'db>, -) -> Vec<(hir::Trait, Vec<(Option>, hir::Name)>)> { +) -> Vec<(hir::Trait, Vec<(Option>, hir::Name)>)> { if ty.is_unknown() { // The trait solver returns "yes" to the question whether the error type // impls any trait, and we don't want to show it as having any notable trait. @@ -526,14 +537,32 @@ fn notable_traits<'db>( .filter_map(move |&trait_| { let trait_ = trait_.into(); ty.impls_trait(db, trait_, &[]).then(|| { + // FIXME: This may have a better implementation + let impl_items = hir::Impl::all_for_trait(db, trait_) + .into_iter() + .find(|it| it.self_ty(db).could_unify_with_deeply(db, ty)) + .map_or(Vec::new(), |impl_| impl_.items(db)); ( trait_, trait_ .items(db) .into_iter() - .filter_map(hir::AssocItem::as_type_alias) - .map(|alias| { - (ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db)) + .filter_map(|item| match item { + hir::AssocItem::Function(_) => None, + hir::AssocItem::Const(it) => { + let name = Some(it.name(db)?); + let assoc_const = impl_items + .iter() + .find_map(|item| { + item.as_const().filter(|it| it.name(db) == name) + }) + .map(TyOrConst::Const); + Some((assoc_const, name?)) + } + hir::AssocItem::TypeAlias(it) => Some(( + ty.normalize_trait_assoc_type(db, &[], it).map(TyOrConst::Type), + it.name(db), + )), }) .collect::>(), ) @@ -606,7 +635,7 @@ fn runnable_action( fn goto_type_action_for_def( sema: &Semantics<'_, RootDatabase>, def: Definition, - notable_traits: &[(hir::Trait, Vec<(Option>, hir::Name)>)], + notable_traits: &[(hir::Trait, Vec<(Option>, hir::Name)>)], subst_types: Option)>>, edition: Edition, ) -> Option { @@ -620,9 +649,11 @@ fn goto_type_action_for_def( for &(trait_, ref assocs) in notable_traits { push_new_def(trait_.into()); - assocs.iter().filter_map(|(ty, _)| ty.as_ref()).for_each(|ty| { - walk_and_push_ty(db, ty, &mut push_new_def); - }); + assocs.iter().filter_map(|(ty, _)| ty.as_ref()).filter_map(TyOrConst::as_type).for_each( + |ty| { + walk_and_push_ty(db, ty, &mut push_new_def); + }, + ); } if let Ok(generic_def) = GenericDef::try_from(def) { diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index a1eff3aaee78..70fc5001f53b 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -29,7 +29,7 @@ use crate::{ HoverAction, HoverConfig, HoverResult, Markup, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, doc_links::{remove_links, rewrite_links}, - hover::{SubstTyLen, notable_traits, walk_and_push_ty}, + hover::{SubstTyLen, TyOrConst, notable_traits, walk_and_push_ty}, interpret::render_const_eval_error, }; @@ -477,7 +477,7 @@ pub(super) fn definition( db: &RootDatabase, def: Definition, famous_defs: Option<&FamousDefs<'_, '_>>, - notable_traits: &[(Trait, Vec<(Option>, Name)>)], + notable_traits: &[(Trait, Vec<(Option>, Name)>)], macro_arm: Option, render_extras: bool, subst_types: Option<&Vec<(Symbol, Type<'_>)>>, @@ -553,65 +553,15 @@ pub(super) fn definition( Definition::Const(it) => { let body = it.eval(db); Some(match body { - Ok(it) => match it.render_debug(db) { - Ok(it) => it, - Err(err) => { - let it = it.render(db, display_target); - if env::var_os("RA_DEV").is_some() { - format!( - "{it}\n{}", - render_const_eval_error(db, err.into(), display_target) - ) - } else { - it - } - } - }, - Err(err) => { - let source = it.source(db)?; - let mut body = source.value.body()?.syntax().clone(); - if let Some(macro_file) = source.file_id.macro_file() { - let span_map = db.expansion_span_map(macro_file); - body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into()); - } - if env::var_os("RA_DEV").is_some() { - format!("{body}\n{}", render_const_eval_error(db, err, display_target)) - } else { - body.to_string() - } - } + Ok(it) => const_value(&it, db, display_target), + Err(err) => source_value(&it, |it| it.body(), err, db, display_target)?, }) } Definition::Static(it) => { let body = it.eval(db); Some(match body { - Ok(it) => match it.render_debug(db) { - Ok(it) => it, - Err(err) => { - let it = it.render(db, display_target); - if env::var_os("RA_DEV").is_some() { - format!( - "{it}\n{}", - render_const_eval_error(db, err.into(), display_target) - ) - } else { - it - } - } - }, - Err(err) => { - let source = it.source(db)?; - let mut body = source.value.body()?.syntax().clone(); - if let Some(macro_file) = source.file_id.macro_file() { - let span_map = db.expansion_span_map(macro_file); - body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into()); - } - if env::var_os("RA_DEV").is_some() { - format!("{body}\n{}", render_const_eval_error(db, err, display_target)) - } else { - body.to_string() - } - } + Ok(it) => const_value(&it, db, display_target), + Err(err) => source_value(&it, |it| it.body(), err, db, display_target)?, }) } _ => None, @@ -939,7 +889,7 @@ pub(super) fn literal( fn render_notable_trait( db: &RootDatabase, - notable_traits: &[(Trait, Vec<(Option>, Name)>)], + notable_traits: &[(Trait, Vec<(Option>, Name)>)], edition: Edition, display_target: DisplayTarget, ) -> Option { @@ -961,7 +911,16 @@ fn render_notable_trait( f(&name.display(db, edition))?; f(&" = ")?; match ty { - Some(ty) => f(&ty.display(db, display_target)), + Some(TyOrConst::Type(ty)) => f(&ty.display(db, display_target)), + Some(TyOrConst::Const(it)) => match it.eval(db) { + Ok(value) => f(&const_value(&value, db, display_target)), + Err(err) => { + match source_value(it, |it| it.body(), err, db, display_target) { + Some(s) => f(&s), + None => f(&"?"), + } + } + }, None => f(&"?"), } }) @@ -1105,6 +1064,44 @@ fn closure_ty( Some(res) } +fn const_value( + evaluated: &hir::EvaluatedConst<'_>, + db: &RootDatabase, + display_target: DisplayTarget, +) -> String { + match evaluated.render_debug(db) { + Ok(it) => it, + Err(err) => { + let it = evaluated.render(db, display_target); + if env::var_os("RA_DEV").is_some() { + format!("{it}\n{}", render_const_eval_error(db, err.into(), display_target)) + } else { + it + } + } + } +} + +fn source_value( + it: &T, + expr: fn(&::Ast) -> Option, + err: hir::ConstEvalError<'_>, + db: &RootDatabase, + display_target: DisplayTarget, +) -> Option { + let source = it.source(db)?; + let mut body = expr(&source.value)?.syntax().clone(); + if let Some(macro_file) = source.file_id.macro_file() { + let span_map = db.expansion_span_map(macro_file); + body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into()); + } + Some(if env::var_os("RA_DEV").is_some() { + format!("{body}\n{}", render_const_eval_error(db, err, display_target)) + } else { + body.to_string() + }) +} + fn definition_path(db: &RootDatabase, &def: &Definition, edition: Edition) -> Option { if matches!( def, diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 071eacf6604c..0ed48c3cf7ea 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -9097,11 +9097,13 @@ fn notable_local() { trait Notable { type Assoc; type Assoc2; + const ID: u32; } impl Notable for u32 { type Assoc = &str; type Assoc2 = char; + const ID: u32 = 3; } fn main(notable$0: u32) {} "#, @@ -9114,7 +9116,7 @@ fn main(notable$0: u32) {} --- - Implements notable traits: `Notable` + Implements notable traits: `Notable` ---