diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 66e813eed8b4..8abf88048912 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -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; @@ -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 }, } } @@ -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, + 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) }, } } @@ -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 }, /// Display types for inserting them in source files. /// The generated code should compile, so paths need to be qualified. SourceCode { module_id: ModuleId }, @@ -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]; @@ -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(), diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 86d25e2f5ad0..cd6433967cbf 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -245,6 +245,7 @@ fn label_of_ty( famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, ty: hir::Type, + module: hir::Module, ) -> Option { fn rec( sema: &Semantics<'_, RootDatabase>, @@ -252,6 +253,7 @@ fn label_of_ty( mut max_length: Option, ty: hir::Type, label_builder: &mut InlayHintLabelBuilder<'_>, + module: hir::Module, ) { let iter_item_type = hint_iterator(sema, famous_defs, &ty); match iter_item_type { @@ -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); } }; } @@ -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) } diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs index adec19c765a1..f27a83395f29 100644 --- a/crates/ide/src/inlay_hints/bind_pat.rs +++ b/crates/ide/src/inlay_hints/bind_pat.rs @@ -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() @@ -388,13 +388,20 @@ fn main(a: SliceIter<'_, Container>) { } pub trait Foo { type Bar: Default; + type Baz: Default; } - pub fn quux() -> T::Bar { + pub trait Overlapping { + type Baz; + } + + pub fn quux() -> (T::Bar, T::Baz) { + let x = Default::default(); + //^ T::Bar let y = Default::default(); - //^ ::Bar + //^ ::Baz - y + (x, y) } "#, ); diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index 8810d5d34dbd..8ed29c8bd981 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -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())), }); } diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs index d9929beaac0c..c72b023bbea5 100644 --- a/crates/ide/src/inlay_hints/closure_ret.rs +++ b/crates/ide/src/inlay_hints/closure_ret.rs @@ -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() { @@ -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(())