This commit is contained in:
A4-Tacks 2025-12-22 15:57:59 -05:00 committed by GitHub
commit c5f2fc466b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 97 additions and 67 deletions

View file

@ -76,6 +76,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),
@ -511,7 +522,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.
@ -523,14 +534,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<_>>(),
)
@ -603,7 +632,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> {
@ -617,9 +646,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) {

View file

@ -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<Type<'_>>, Name)>)],
notable_traits: &[(Trait, Vec<(Option<TyOrConst<'_>>, Name)>)],
macro_arm: Option<u32>,
render_extras: bool,
subst_types: Option<&Vec<(Symbol, Type<'_>)>>,
@ -548,65 +548,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,
@ -927,7 +877,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> {
@ -949,7 +899,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(&"?"),
}
})
@ -1093,6 +1052,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,

View file

@ -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<Assoc = &str, Assoc2 = char>`
Implements notable traits: `Notable<Assoc = &str, Assoc2 = char, ID = 3>`
---