Skip to content
Closed
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
67 changes: 59 additions & 8 deletions crates/hir-ty/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use hir_def::{
path::{Path, PathKind},
type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef},
visibility::Visibility,
HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
AssocItemId, HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
};
use hir_expand::{hygiene::Hygiene, name::Name};
use itertools::Itertools;
Expand Down Expand Up @@ -105,7 +105,7 @@ pub trait HirDisplay {
t: self,
max_size: None,
omit_verbose_types: false,
display_target: DisplayTarget::Diagnostics,
display_target: DisplayTarget::Diagnostics { module_id: None },
}
}

Expand All @@ -124,7 +124,27 @@ pub trait HirDisplay {
t: self,
max_size,
omit_verbose_types: true,
display_target: DisplayTarget::Diagnostics,
display_target: DisplayTarget::Diagnostics { module_id: None },
}
}

/// Returns a `Display`able type that is human-readable and tries to be succinct.
/// Use this for showing types to the user where space is constrained (e.g. doc popups)
fn display_truncated_at<'a>(
&'a self,
db: &'a dyn HirDatabase,
max_size: Option<usize>,
module_id: ModuleId,
) -> HirDisplayWrapper<'a, Self>
where
Self: Sized,
{
HirDisplayWrapper {
db,
t: self,
max_size,
omit_verbose_types: true,
display_target: DisplayTarget::Diagnostics { module_id: Some(module_id) },
}
}

Expand Down Expand Up @@ -228,7 +248,7 @@ pub enum DisplayTarget {
/// Display types for inlays, doc popups, autocompletion, etc...
/// Showing `{unknown}` or not qualifying paths is fine here.
/// There's no reason for this to fail.
Diagnostics,
Diagnostics { module_id: Option<ModuleId> },
/// Display types for inserting them in source files.
/// The generated code should compile, so paths need to be qualified.
SourceCode { module_id: ModuleId },
Expand Down Expand Up @@ -323,10 +343,41 @@ impl HirDisplay for ProjectionTy {
return write!(f, "{TYPE_HINT_TRUNCATION}");
}

let assoc_name = &f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name;
let trait_ref = self.trait_ref(f.db);
write!(f, "<")?;
fmt_trait_ref(&trait_ref, f, true)?;
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;

let trait_id = self.trait_(f.db);

let short_form = if let DisplayTarget::Diagnostics { module_id: Some(module) }
| DisplayTarget::SourceCode { module_id: module } = f.display_target
{
trait_ref.substitution.len(Interner) == 1
&& module.def_map(f.db.upcast())[module.local_id]
.scope
.entries()
.filter_map(|(_name, def)| def.types)
.filter_map(|(module_did, _vis)| match module_did {
ModuleDefId::TraitId(tr) => Some(tr),
_ => None,
})
.filter(|&tr| {
f.db.trait_data(tr).items.iter().any(|(name, item)| {
matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
})
})
.eq([trait_id])
} else {
false
};

if short_form {
trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
write!(f, "::{assoc_name}")?;
} else {
write!(f, "<")?;
fmt_trait_ref(&trait_ref, f, true)?;
write!(f, ">::{assoc_name}")?;
}
let proj_params_count =
self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
Expand Down Expand Up @@ -566,7 +617,7 @@ impl HirDisplay for Ty {
TyKind::Adt(AdtId(def_id), parameters) => {
f.start_location_link((*def_id).into());
match f.display_target {
DisplayTarget::Diagnostics | DisplayTarget::Test => {
DisplayTarget::Diagnostics { .. } | DisplayTarget::Test => {
let name = match *def_id {
hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
Expand Down
11 changes: 8 additions & 3 deletions crates/ide/src/inlay_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,15 @@ fn label_of_ty(
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
config: &InlayHintsConfig,
ty: hir::Type,
module: hir::Module,
) -> Option<InlayHintLabel> {
fn rec(
sema: &Semantics<'_, RootDatabase>,
famous_defs: &FamousDefs<'_, '_>,
mut max_length: Option<usize>,
ty: hir::Type,
label_builder: &mut InlayHintLabelBuilder<'_>,
module: hir::Module,
) {
let iter_item_type = hint_iterator(sema, famous_defs, &ty);
match iter_item_type {
Expand All @@ -263,11 +265,14 @@ fn label_of_ty(
max_length.map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len()));

label_builder.write_str(LABEL_START).unwrap();
rec(sema, famous_defs, max_length, ty, label_builder);
rec(sema, famous_defs, max_length, ty, label_builder, module);
label_builder.write_str(LABEL_END).unwrap();
}

None => {
let _ = ty.display_truncated(sema.db, max_length).write_to(label_builder);
let _ = ty
.display_truncated_at(sema.db, max_length, module.into())
.write_to(label_builder);
}
};
}
Expand All @@ -279,7 +284,7 @@ fn label_of_ty(
location_link_enabled: config.location_links,
result: InlayHintLabel::default(),
};
rec(sema, famous_defs, config.max_length, ty, &mut label_builder);
rec(sema, famous_defs, config.max_length, ty, &mut label_builder, module);
let r = label_builder.finish();
Some(r)
}
Expand Down
15 changes: 11 additions & 4 deletions crates/ide/src/inlay_hints/bind_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub(super) fn hints(
return None;
}

let label = label_of_ty(famous_defs, config, ty)?;
let label = label_of_ty(famous_defs, config, ty, sema.scope(pat.syntax()).unwrap().module())?;

if config.hide_named_constructor_hints
&& is_named_constructor(sema, pat, &label.to_string()).is_some()
Expand Down Expand Up @@ -388,13 +388,20 @@ fn main(a: SliceIter<'_, Container>) {
}
pub trait Foo {
type Bar: Default;
type Baz: Default;
}

pub fn quux<T: Foo>() -> T::Bar {
pub trait Overlapping {
type Baz;
}

pub fn quux<T: Foo>() -> (T::Bar, T::Baz) {
let x = Default::default();
//^ T::Bar
let y = Default::default();
//^ <T as Foo>::Bar
//^ <T as Foo>::Baz

y
(x, y)
}
"#,
);
Expand Down
7 changes: 6 additions & 1 deletion crates/ide/src/inlay_hints/chaining.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ pub(super) fn hints(
acc.push(InlayHint {
range: expr.syntax().text_range(),
kind: InlayKind::ChainingHint,
label: label_of_ty(famous_defs, config, ty)?,
label: label_of_ty(
famous_defs,
config,
ty,
sema.scope(expr.syntax()).unwrap().module(),
)?,
tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())),
});
}
Expand Down
9 changes: 7 additions & 2 deletions crates/ide/src/inlay_hints/closure_ret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub(super) fn hints(
let param_list = closure.param_list()?;

let closure = sema.descend_node_into_attributes(closure).pop()?;
let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted();
let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure.clone()))?.adjusted();
let callable = ty.as_callable(sema.db)?;
let ty = callable.return_type();
if ty.is_unit() {
Expand All @@ -42,7 +42,12 @@ pub(super) fn hints(
acc.push(InlayHint {
range: param_list.syntax().text_range(),
kind: InlayKind::ClosureReturnTypeHint,
label: label_of_ty(famous_defs, config, ty)?,
label: label_of_ty(
famous_defs,
config,
ty,
sema.scope(closure.syntax()).unwrap().module(),
)?,
tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())),
});
Some(())
Expand Down