Skip to content

Commit ca2df25

Browse files
committed
Add render associated constant in notable trait
Example --- ```rust impl Notable for u32 { type Assoc = &str; type Assoc2 = char; const ID: u32 = 3; } ``` **Before this PR** ```text Implements notable traits: `Notable<Assoc = &str, Assoc2 = char>` ``` **After this PR** ```text Implements notable traits: `Notable<Assoc = &str, Assoc2 = char, ID = 3>` ```
1 parent c9472ba commit ca2df25

File tree

3 files changed

+97
-67
lines changed

3 files changed

+97
-67
lines changed

crates/ide/src/hover.rs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ pub enum HoverDocFormat {
7878
PlainText,
7979
}
8080

81+
enum TyOrConst<'db> {
82+
Const(hir::Const),
83+
Type(hir::Type<'db>),
84+
}
85+
86+
impl<'db> TyOrConst<'db> {
87+
fn as_type(&self) -> Option<&hir::Type<'db>> {
88+
if let Self::Type(ty) = self { Some(ty) } else { None }
89+
}
90+
}
91+
8192
#[derive(Debug, Clone, Hash, PartialEq, Eq, UpmapFromRaFixture)]
8293
pub enum HoverAction {
8394
Runnable(Runnable),
@@ -514,7 +525,7 @@ pub(crate) fn hover_for_definition(
514525
fn notable_traits<'db>(
515526
db: &'db RootDatabase,
516527
ty: &hir::Type<'db>,
517-
) -> Vec<(hir::Trait, Vec<(Option<hir::Type<'db>>, hir::Name)>)> {
528+
) -> Vec<(hir::Trait, Vec<(Option<TyOrConst<'db>>, hir::Name)>)> {
518529
if ty.is_unknown() {
519530
// The trait solver returns "yes" to the question whether the error type
520531
// impls any trait, and we don't want to show it as having any notable trait.
@@ -526,14 +537,32 @@ fn notable_traits<'db>(
526537
.filter_map(move |&trait_| {
527538
let trait_ = trait_.into();
528539
ty.impls_trait(db, trait_, &[]).then(|| {
540+
// FIXME: This may be better implement
541+
let impl_items = hir::Impl::all_for_trait(db, trait_)
542+
.into_iter()
543+
.find(|it| it.self_ty(db).could_unify_with_deeply(db, ty))
544+
.map_or(Vec::new(), |impl_| impl_.items(db));
529545
(
530546
trait_,
531547
trait_
532548
.items(db)
533549
.into_iter()
534-
.filter_map(hir::AssocItem::as_type_alias)
535-
.map(|alias| {
536-
(ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db))
550+
.filter_map(|item| match item {
551+
hir::AssocItem::Function(_) => None,
552+
hir::AssocItem::Const(it) => {
553+
let name = Some(it.name(db)?);
554+
let assoc_const = impl_items
555+
.iter()
556+
.find_map(|item| {
557+
item.as_const().filter(|it| it.name(db) == name)
558+
})
559+
.map(TyOrConst::Const);
560+
Some((assoc_const, name?))
561+
}
562+
hir::AssocItem::TypeAlias(it) => Some((
563+
ty.normalize_trait_assoc_type(db, &[], it).map(TyOrConst::Type),
564+
it.name(db),
565+
)),
537566
})
538567
.collect::<Vec<_>>(),
539568
)
@@ -606,7 +635,7 @@ fn runnable_action(
606635
fn goto_type_action_for_def(
607636
sema: &Semantics<'_, RootDatabase>,
608637
def: Definition,
609-
notable_traits: &[(hir::Trait, Vec<(Option<hir::Type<'_>>, hir::Name)>)],
638+
notable_traits: &[(hir::Trait, Vec<(Option<TyOrConst<'_>>, hir::Name)>)],
610639
subst_types: Option<Vec<(hir::Symbol, hir::Type<'_>)>>,
611640
edition: Edition,
612641
) -> Option<HoverAction> {
@@ -620,9 +649,11 @@ fn goto_type_action_for_def(
620649

621650
for &(trait_, ref assocs) in notable_traits {
622651
push_new_def(trait_.into());
623-
assocs.iter().filter_map(|(ty, _)| ty.as_ref()).for_each(|ty| {
624-
walk_and_push_ty(db, ty, &mut push_new_def);
625-
});
652+
assocs.iter().filter_map(|(ty, _)| ty.as_ref()).filter_map(TyOrConst::as_type).for_each(
653+
|ty| {
654+
walk_and_push_ty(db, ty, &mut push_new_def);
655+
},
656+
);
626657
}
627658

628659
if let Ok(generic_def) = GenericDef::try_from(def) {

crates/ide/src/hover/render.rs

Lines changed: 55 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::{
2929
HoverAction, HoverConfig, HoverResult, Markup, MemoryLayoutHoverConfig,
3030
MemoryLayoutHoverRenderKind,
3131
doc_links::{remove_links, rewrite_links},
32-
hover::{SubstTyLen, notable_traits, walk_and_push_ty},
32+
hover::{SubstTyLen, TyOrConst, notable_traits, walk_and_push_ty},
3333
interpret::render_const_eval_error,
3434
};
3535

@@ -477,7 +477,7 @@ pub(super) fn definition(
477477
db: &RootDatabase,
478478
def: Definition,
479479
famous_defs: Option<&FamousDefs<'_, '_>>,
480-
notable_traits: &[(Trait, Vec<(Option<Type<'_>>, Name)>)],
480+
notable_traits: &[(Trait, Vec<(Option<TyOrConst<'_>>, Name)>)],
481481
macro_arm: Option<u32>,
482482
render_extras: bool,
483483
subst_types: Option<&Vec<(Symbol, Type<'_>)>>,
@@ -553,65 +553,15 @@ pub(super) fn definition(
553553
Definition::Const(it) => {
554554
let body = it.eval(db);
555555
Some(match body {
556-
Ok(it) => match it.render_debug(db) {
557-
Ok(it) => it,
558-
Err(err) => {
559-
let it = it.render(db, display_target);
560-
if env::var_os("RA_DEV").is_some() {
561-
format!(
562-
"{it}\n{}",
563-
render_const_eval_error(db, err.into(), display_target)
564-
)
565-
} else {
566-
it
567-
}
568-
}
569-
},
570-
Err(err) => {
571-
let source = it.source(db)?;
572-
let mut body = source.value.body()?.syntax().clone();
573-
if let Some(macro_file) = source.file_id.macro_file() {
574-
let span_map = db.expansion_span_map(macro_file);
575-
body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into());
576-
}
577-
if env::var_os("RA_DEV").is_some() {
578-
format!("{body}\n{}", render_const_eval_error(db, err, display_target))
579-
} else {
580-
body.to_string()
581-
}
582-
}
556+
Ok(it) => const_value(&it, db, display_target),
557+
Err(err) => source_value(&it, |it| it.body(), err, db, display_target)?,
583558
})
584559
}
585560
Definition::Static(it) => {
586561
let body = it.eval(db);
587562
Some(match body {
588-
Ok(it) => match it.render_debug(db) {
589-
Ok(it) => it,
590-
Err(err) => {
591-
let it = it.render(db, display_target);
592-
if env::var_os("RA_DEV").is_some() {
593-
format!(
594-
"{it}\n{}",
595-
render_const_eval_error(db, err.into(), display_target)
596-
)
597-
} else {
598-
it
599-
}
600-
}
601-
},
602-
Err(err) => {
603-
let source = it.source(db)?;
604-
let mut body = source.value.body()?.syntax().clone();
605-
if let Some(macro_file) = source.file_id.macro_file() {
606-
let span_map = db.expansion_span_map(macro_file);
607-
body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into());
608-
}
609-
if env::var_os("RA_DEV").is_some() {
610-
format!("{body}\n{}", render_const_eval_error(db, err, display_target))
611-
} else {
612-
body.to_string()
613-
}
614-
}
563+
Ok(it) => const_value(&it, db, display_target),
564+
Err(err) => source_value(&it, |it| it.body(), err, db, display_target)?,
615565
})
616566
}
617567
_ => None,
@@ -939,7 +889,7 @@ pub(super) fn literal(
939889

940890
fn render_notable_trait(
941891
db: &RootDatabase,
942-
notable_traits: &[(Trait, Vec<(Option<Type<'_>>, Name)>)],
892+
notable_traits: &[(Trait, Vec<(Option<TyOrConst<'_>>, Name)>)],
943893
edition: Edition,
944894
display_target: DisplayTarget,
945895
) -> Option<String> {
@@ -961,7 +911,16 @@ fn render_notable_trait(
961911
f(&name.display(db, edition))?;
962912
f(&" = ")?;
963913
match ty {
964-
Some(ty) => f(&ty.display(db, display_target)),
914+
Some(TyOrConst::Type(ty)) => f(&ty.display(db, display_target)),
915+
Some(TyOrConst::Const(it)) => match it.eval(db) {
916+
Ok(value) => f(&const_value(&value, db, display_target)),
917+
Err(err) => {
918+
match source_value(it, |it| it.body(), err, db, display_target) {
919+
Some(s) => f(&s),
920+
None => f(&"?"),
921+
}
922+
}
923+
},
965924
None => f(&"?"),
966925
}
967926
})
@@ -1105,6 +1064,44 @@ fn closure_ty(
11051064
Some(res)
11061065
}
11071066

1067+
fn const_value(
1068+
evaluated: &hir::EvaluatedConst<'_>,
1069+
db: &RootDatabase,
1070+
display_target: DisplayTarget,
1071+
) -> String {
1072+
match evaluated.render_debug(db) {
1073+
Ok(it) => it,
1074+
Err(err) => {
1075+
let it = evaluated.render(db, display_target);
1076+
if env::var_os("RA_DEV").is_some() {
1077+
format!("{it}\n{}", render_const_eval_error(db, err.into(), display_target))
1078+
} else {
1079+
it
1080+
}
1081+
}
1082+
}
1083+
}
1084+
1085+
fn source_value<T: HasCrate + HasSource + Copy>(
1086+
it: &T,
1087+
expr: fn(&<T as HasSource>::Ast) -> Option<ast::Expr>,
1088+
err: hir::ConstEvalError<'_>,
1089+
db: &RootDatabase,
1090+
display_target: DisplayTarget,
1091+
) -> Option<String> {
1092+
let source = it.source(db)?;
1093+
let mut body = expr(&source.value)?.syntax().clone();
1094+
if let Some(macro_file) = source.file_id.macro_file() {
1095+
let span_map = db.expansion_span_map(macro_file);
1096+
body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into());
1097+
}
1098+
Some(if env::var_os("RA_DEV").is_some() {
1099+
format!("{body}\n{}", render_const_eval_error(db, err, display_target))
1100+
} else {
1101+
body.to_string()
1102+
})
1103+
}
1104+
11081105
fn definition_path(db: &RootDatabase, &def: &Definition, edition: Edition) -> Option<String> {
11091106
if matches!(
11101107
def,

crates/ide/src/hover/tests.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9097,11 +9097,13 @@ fn notable_local() {
90979097
trait Notable {
90989098
type Assoc;
90999099
type Assoc2;
9100+
const ID: u32;
91009101
}
91019102
91029103
impl Notable for u32 {
91039104
type Assoc = &str;
91049105
type Assoc2 = char;
9106+
const ID: u32 = 3;
91059107
}
91069108
fn main(notable$0: u32) {}
91079109
"#,
@@ -9114,7 +9116,7 @@ fn main(notable$0: u32) {}
91149116
91159117
---
91169118
9117-
Implements notable traits: `Notable<Assoc = &str, Assoc2 = char>`
9119+
Implements notable traits: `Notable<Assoc = &str, Assoc2 = char, ID = 3>`
91189120
91199121
---
91209122

0 commit comments

Comments
 (0)