mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-12-23 08:48:08 +00:00
Merge b161e8b93f into 624761a864
This commit is contained in:
commit
c5f2fc466b
3 changed files with 97 additions and 67 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>`
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue