Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions crates/ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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::Type<'db>>, hir::Name)>)> {
) -> Vec<(hir::Trait, Vec<(Option<TyOrConst<'db>>, 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.
Expand All @@ -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::<Vec<_>>(),
)
Expand Down Expand Up @@ -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::Type<'_>>, hir::Name)>)],
notable_traits: &[(hir::Trait, Vec<(Option<TyOrConst<'_>>, hir::Name)>)],
subst_types: Option<Vec<(hir::Symbol, hir::Type<'_>)>>,
edition: Edition,
) -> Option<HoverAction> {
Expand All @@ -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) {
Expand Down
113 changes: 55 additions & 58 deletions crates/ide/src/hover/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -477,7 +477,7 @@ pub(super) fn definition(
db: &RootDatabase,
def: Definition,
famous_defs: Option<&FamousDefs<'_, '_>>,
notable_traits: &[(Trait, Vec<(Option<Type<'_>>, Name)>)],
notable_traits: &[(Trait, Vec<(Option<TyOrConst<'_>>, Name)>)],
macro_arm: Option<u32>,
render_extras: bool,
subst_types: Option<&Vec<(Symbol, Type<'_>)>>,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -939,7 +889,7 @@ pub(super) fn literal(

fn render_notable_trait(
db: &RootDatabase,
notable_traits: &[(Trait, Vec<(Option<Type<'_>>, Name)>)],
notable_traits: &[(Trait, Vec<(Option<TyOrConst<'_>>, Name)>)],
edition: Edition,
display_target: DisplayTarget,
) -> Option<String> {
Expand All @@ -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(&"?"),
}
})
Expand Down Expand Up @@ -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<T: HasCrate + HasSource + Copy>(
it: &T,
expr: fn(&<T as HasSource>::Ast) -> Option<ast::Expr>,
err: hir::ConstEvalError<'_>,
db: &RootDatabase,
display_target: DisplayTarget,
) -> Option<String> {
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<String> {
if matches!(
def,
Expand Down
4 changes: 3 additions & 1 deletion crates/ide/src/hover/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
"#,
Expand All @@ -9114,7 +9116,7 @@ fn main(notable$0: u32) {}

---

Implements notable traits: `Notable<Assoc = &str, Assoc2 = char>`
Implements notable traits: `Notable<Assoc = &str, Assoc2 = char, ID = 3>`

---

Expand Down