about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-01-14 12:50:26 +0000
committerbors <bors@rust-lang.org>2023-01-14 12:50:26 +0000
commit6673e515b770350a97b42e2518f64908f2db16b3 (patch)
treee9db5a7fc80a6cb461d85969caf936bc2a678b01
parentce6955c10e579f936dee9905dff223d816061299 (diff)
parent27ba598dfe293b7ec9c07015c86cb8eeb4f6a24d (diff)
downloadrust-6673e515b770350a97b42e2518f64908f2db16b3.tar.gz
rust-6673e515b770350a97b42e2518f64908f2db16b3.zip
Auto merge of #13948 - Veykril:inlay-hints, r=Veykril
Make inlay hint location links work for more types
-rw-r--r--crates/hir-ty/src/display.rs182
-rw-r--r--crates/hir-ty/src/lower.rs13
-rw-r--r--crates/hir/src/display.rs2
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/ide/src/inlay_hints.rs49
-rw-r--r--crates/ide/src/inlay_hints/bind_pat.rs28
-rw-r--r--crates/ide/src/inlay_hints/chaining.rs45
7 files changed, 221 insertions, 100 deletions
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index f9642aa7475..3a96e53d719 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -325,7 +325,7 @@ impl HirDisplay for ProjectionTy {
 
         let trait_ref = self.trait_ref(f.db);
         write!(f, "<")?;
-        fmt_trait_ref(&trait_ref, f, true)?;
+        fmt_trait_ref(f, &trait_ref, true)?;
         write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
         let proj_params_count =
             self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
@@ -383,7 +383,10 @@ impl HirDisplay for BoundVar {
 }
 
 impl HirDisplay for Ty {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+    fn hir_fmt(
+        &self,
+        f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>,
+    ) -> Result<(), HirDisplayError> {
         if f.should_truncate() {
             return write!(f, "{TYPE_HINT_TRUNCATION}");
         }
@@ -434,7 +437,7 @@ impl HirDisplay for Ty {
                     bounds.iter().any(|bound| {
                         if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
                             let trait_ = trait_ref.hir_trait_id();
-                            fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
+                            fn_traits(db.upcast(), trait_).any(|it| it == trait_)
                         } else {
                             false
                         }
@@ -450,12 +453,11 @@ impl HirDisplay for Ty {
                         substitution: parameters,
                     }))
                     | TyKind::OpaqueType(opaque_ty_id, parameters) => {
-                        let impl_trait_id =
-                            f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
+                        let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
                         if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
-                            let datas =
-                                f.db.return_type_impl_traits(func)
-                                    .expect("impl trait id without data");
+                            let datas = db
+                                .return_type_impl_traits(func)
+                                .expect("impl trait id without data");
                             let data = (*datas)
                                 .as_ref()
                                 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
@@ -465,7 +467,7 @@ impl HirDisplay for Ty {
                             // Don't count Sized but count when it absent
                             // (i.e. when explicit ?Sized bound is set).
                             let default_sized = SizedByDefault::Sized {
-                                anchor: func.lookup(f.db.upcast()).module(f.db.upcast()).krate(),
+                                anchor: func.lookup(db.upcast()).module(db.upcast()).krate(),
                             };
                             let sized_bounds = bounds
                                 .skip_binders()
@@ -476,7 +478,7 @@ impl HirDisplay for Ty {
                                         WhereClause::Implemented(trait_ref)
                                             if default_sized.is_sized_trait(
                                                 trait_ref.hir_trait_id(),
-                                                f.db.upcast(),
+                                                db.upcast(),
                                             ),
                                     )
                                 })
@@ -524,19 +526,19 @@ impl HirDisplay for Ty {
                 sig.hir_fmt(f)?;
             }
             TyKind::FnDef(def, parameters) => {
-                let def = from_chalk(f.db, *def);
-                let sig = f.db.callable_item_signature(def).substitute(Interner, parameters);
+                let def = from_chalk(db, *def);
+                let sig = db.callable_item_signature(def).substitute(Interner, parameters);
+                f.start_location_link(def.into());
                 match def {
-                    CallableDefId::FunctionId(ff) => {
-                        write!(f, "fn {}", f.db.function_data(ff).name)?
-                    }
-                    CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
+                    CallableDefId::FunctionId(ff) => write!(f, "fn {}", db.function_data(ff).name)?,
+                    CallableDefId::StructId(s) => write!(f, "{}", db.struct_data(s).name)?,
                     CallableDefId::EnumVariantId(e) => {
-                        write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
+                        write!(f, "{}", db.enum_data(e.parent).variants[e.local_id].name)?
                     }
                 };
+                f.end_location_link();
                 if parameters.len(Interner) > 0 {
-                    let generics = generics(f.db.upcast(), def.into());
+                    let generics = generics(db.upcast(), def.into());
                     let (parent_params, self_param, type_params, const_params, _impl_trait_params) =
                         generics.provenance_split();
                     let total_len = parent_params + self_param + type_params + const_params;
@@ -568,15 +570,15 @@ impl HirDisplay for Ty {
                 match f.display_target {
                     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(),
-                            hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
+                            hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(),
+                            hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(),
+                            hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(),
                         };
                         write!(f, "{name}")?;
                     }
                     DisplayTarget::SourceCode { module_id } => {
                         if let Some(path) = find_path::find_path(
-                            f.db.upcast(),
+                            db.upcast(),
                             ItemInNs::Types((*def_id).into()),
                             module_id,
                             false,
@@ -596,8 +598,8 @@ impl HirDisplay for Ty {
                         || f.omit_verbose_types()
                     {
                         match self
-                            .as_generic_def(f.db)
-                            .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
+                            .as_generic_def(db)
+                            .map(|generic_def_id| db.generic_defaults(generic_def_id))
                             .filter(|defaults| !defaults.is_empty())
                         {
                             None => parameters.as_slice(Interner),
@@ -669,16 +671,23 @@ impl HirDisplay for Ty {
             }
             TyKind::AssociatedType(assoc_type_id, parameters) => {
                 let type_alias = from_assoc_type_id(*assoc_type_id);
-                let trait_ = match type_alias.lookup(f.db.upcast()).container {
+                let trait_ = match type_alias.lookup(db.upcast()).container {
                     ItemContainerId::TraitId(it) => it,
                     _ => panic!("not an associated type"),
                 };
-                let trait_ = f.db.trait_data(trait_);
-                let type_alias_data = f.db.type_alias_data(type_alias);
+                let trait_data = db.trait_data(trait_);
+                let type_alias_data = db.type_alias_data(type_alias);
 
                 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
                 if f.display_target.is_test() {
-                    write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
+                    f.start_location_link(trait_.into());
+                    write!(f, "{}", trait_data.name)?;
+                    f.end_location_link();
+                    write!(f, "::")?;
+
+                    f.start_location_link(type_alias.into());
+                    write!(f, "{}", type_alias_data.name)?;
+                    f.end_location_link();
                     // Note that the generic args for the associated type come before those for the
                     // trait (including the self type).
                     // FIXME: reconsider the generic args order upon formatting?
@@ -697,25 +706,28 @@ impl HirDisplay for Ty {
                 }
             }
             TyKind::Foreign(type_alias) => {
-                let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
+                let alias = from_foreign_def_id(*type_alias);
+                let type_alias = db.type_alias_data(alias);
+                f.start_location_link(alias.into());
                 write!(f, "{}", type_alias.name)?;
+                f.end_location_link();
             }
             TyKind::OpaqueType(opaque_ty_id, parameters) => {
-                let impl_trait_id = f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
+                let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
                 match impl_trait_id {
                     ImplTraitId::ReturnTypeImplTrait(func, idx) => {
                         let datas =
-                            f.db.return_type_impl_traits(func).expect("impl trait id without data");
+                            db.return_type_impl_traits(func).expect("impl trait id without data");
                         let data = (*datas)
                             .as_ref()
                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
                         let bounds = data.substitute(Interner, &parameters);
-                        let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
+                        let krate = func.lookup(db.upcast()).module(db.upcast()).krate();
                         write_bounds_like_dyn_trait_with_prefix(
+                            f,
                             "impl",
                             bounds.skip_binders(),
                             SizedByDefault::Sized { anchor: krate },
-                            f,
                         )?;
                         // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
                     }
@@ -732,7 +744,7 @@ impl HirDisplay for Ty {
                         DisplaySourceCodeError::Closure,
                     ));
                 }
-                let sig = substs.at(Interner, 0).assert_ty_ref(Interner).callable_sig(f.db);
+                let sig = substs.at(Interner, 0).assert_ty_ref(Interner).callable_sig(db);
                 if let Some(sig) = sig {
                     if sig.params().is_empty() {
                         write!(f, "||")?;
@@ -751,8 +763,8 @@ impl HirDisplay for Ty {
                 }
             }
             TyKind::Placeholder(idx) => {
-                let id = from_placeholder_idx(f.db, *idx);
-                let generics = generics(f.db.upcast(), id.parent);
+                let id = from_placeholder_idx(db, *idx);
+                let generics = generics(db.upcast(), id.parent);
                 let param_data = &generics.params.type_or_consts[id.local_id];
                 match param_data {
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
@@ -760,28 +772,28 @@ impl HirDisplay for Ty {
                             write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))?
                         }
                         TypeParamProvenance::ArgumentImplTrait => {
-                            let substs = generics.placeholder_subst(f.db);
-                            let bounds =
-                                f.db.generic_predicates(id.parent)
-                                    .iter()
-                                    .map(|pred| pred.clone().substitute(Interner, &substs))
-                                    .filter(|wc| match &wc.skip_binders() {
-                                        WhereClause::Implemented(tr) => {
-                                            &tr.self_type_parameter(Interner) == self
-                                        }
-                                        WhereClause::AliasEq(AliasEq {
-                                            alias: AliasTy::Projection(proj),
-                                            ty: _,
-                                        }) => &proj.self_type_parameter(f.db) == self,
-                                        _ => false,
-                                    })
-                                    .collect::<Vec<_>>();
-                            let krate = id.parent.module(f.db.upcast()).krate();
+                            let substs = generics.placeholder_subst(db);
+                            let bounds = db
+                                .generic_predicates(id.parent)
+                                .iter()
+                                .map(|pred| pred.clone().substitute(Interner, &substs))
+                                .filter(|wc| match &wc.skip_binders() {
+                                    WhereClause::Implemented(tr) => {
+                                        &tr.self_type_parameter(Interner) == self
+                                    }
+                                    WhereClause::AliasEq(AliasEq {
+                                        alias: AliasTy::Projection(proj),
+                                        ty: _,
+                                    }) => &proj.self_type_parameter(db) == self,
+                                    _ => false,
+                                })
+                                .collect::<Vec<_>>();
+                            let krate = id.parent.module(db.upcast()).krate();
                             write_bounds_like_dyn_trait_with_prefix(
+                                f,
                                 "impl",
                                 &bounds,
                                 SizedByDefault::Sized { anchor: krate },
-                                f,
                             )?;
                         }
                     },
@@ -803,29 +815,29 @@ impl HirDisplay for Ty {
                 bounds.extend(auto_traits);
 
                 write_bounds_like_dyn_trait_with_prefix(
+                    f,
                     "dyn",
                     &bounds,
                     SizedByDefault::NotSized,
-                    f,
                 )?;
             }
             TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
             TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
-                let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
+                let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
                 match impl_trait_id {
                     ImplTraitId::ReturnTypeImplTrait(func, idx) => {
                         let datas =
-                            f.db.return_type_impl_traits(func).expect("impl trait id without data");
+                            db.return_type_impl_traits(func).expect("impl trait id without data");
                         let data = (*datas)
                             .as_ref()
                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
                         let bounds = data.substitute(Interner, &opaque_ty.substitution);
-                        let krate = func.lookup(f.db.upcast()).module(f.db.upcast()).krate();
+                        let krate = func.lookup(db.upcast()).module(db.upcast()).krate();
                         write_bounds_like_dyn_trait_with_prefix(
+                            f,
                             "impl",
                             bounds.skip_binders(),
                             SizedByDefault::Sized { anchor: krate },
-                            f,
                         )?;
                     }
                     ImplTraitId::AsyncBlockTypeImplTrait(..) => {
@@ -848,7 +860,6 @@ impl HirDisplay for Ty {
                         DisplaySourceCodeError::Generator,
                     ));
                 }
-
                 let subst = subst.as_slice(Interner);
                 let a: Option<SmallVec<[&Ty; 3]>> = subst
                     .get(subst.len() - 3..)
@@ -923,26 +934,26 @@ impl SizedByDefault {
 }
 
 pub fn write_bounds_like_dyn_trait_with_prefix(
+    f: &mut HirFormatter<'_>,
     prefix: &str,
     predicates: &[QuantifiedWhereClause],
     default_sized: SizedByDefault,
-    f: &mut HirFormatter<'_>,
 ) -> Result<(), HirDisplayError> {
     write!(f, "{prefix}")?;
     if !predicates.is_empty()
         || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
     {
         write!(f, " ")?;
-        write_bounds_like_dyn_trait(predicates, default_sized, f)
+        write_bounds_like_dyn_trait(f, predicates, default_sized)
     } else {
         Ok(())
     }
 }
 
 fn write_bounds_like_dyn_trait(
+    f: &mut HirFormatter<'_>,
     predicates: &[QuantifiedWhereClause],
     default_sized: SizedByDefault,
-    f: &mut HirFormatter<'_>,
 ) -> Result<(), HirDisplayError> {
     // Note: This code is written to produce nice results (i.e.
     // corresponding to surface Rust) for types that can occur in
@@ -978,7 +989,9 @@ fn write_bounds_like_dyn_trait(
                 // We assume that the self type is ^0.0 (i.e. the
                 // existential) here, which is the only thing that's
                 // possible in actual Rust, and hence don't print it
+                f.start_location_link(trait_.into());
                 write!(f, "{}", f.db.trait_data(trait_).name)?;
+                f.end_location_link();
                 if let [_, params @ ..] = &*trait_ref.substitution.as_slice(Interner) {
                     if is_fn_trait {
                         if let Some(args) =
@@ -1015,7 +1028,9 @@ fn write_bounds_like_dyn_trait(
                 if let AliasTy::Projection(proj) = alias {
                     let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
                     let type_alias = f.db.type_alias_data(assoc_ty_id);
+                    f.start_location_link(assoc_ty_id.into());
                     write!(f, "{}", type_alias.name)?;
+                    f.end_location_link();
 
                     let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
                     if proj_arg_count > 0 {
@@ -1040,19 +1055,34 @@ fn write_bounds_like_dyn_trait(
     if angle_open {
         write!(f, ">")?;
     }
-    if matches!(default_sized, SizedByDefault::Sized { .. }) {
+    if let SizedByDefault::Sized { anchor } = default_sized {
+        let sized_trait =
+            f.db.lang_item(anchor, SmolStr::new_inline("sized"))
+                .and_then(|lang_item| lang_item.as_trait());
         if !is_sized {
-            write!(f, "{}?Sized", if first { "" } else { " + " })?;
+            if !first {
+                write!(f, " + ")?;
+            }
+            if let Some(sized_trait) = sized_trait {
+                f.start_location_link(sized_trait.into());
+            }
+            write!(f, "?Sized")?;
         } else if first {
+            if let Some(sized_trait) = sized_trait {
+                f.start_location_link(sized_trait.into());
+            }
             write!(f, "Sized")?;
         }
+        if let Some(_) = sized_trait {
+            f.end_location_link();
+        }
     }
     Ok(())
 }
 
 fn fmt_trait_ref(
-    tr: &TraitRef,
     f: &mut HirFormatter<'_>,
+    tr: &TraitRef,
     use_as: bool,
 ) -> Result<(), HirDisplayError> {
     if f.should_truncate() {
@@ -1065,7 +1095,10 @@ fn fmt_trait_ref(
     } else {
         write!(f, ": ")?;
     }
-    write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
+    let trait_ = tr.hir_trait_id();
+    f.start_location_link(trait_.into());
+    write!(f, "{}", f.db.trait_data(trait_).name)?;
+    f.end_location_link();
     if tr.substitution.len(Interner) > 1 {
         write!(f, "<")?;
         f.write_joined(&tr.substitution.as_slice(Interner)[1..], ", ")?;
@@ -1076,7 +1109,7 @@ fn fmt_trait_ref(
 
 impl HirDisplay for TraitRef {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        fmt_trait_ref(self, f, false)
+        fmt_trait_ref(f, self, false)
     }
 }
 
@@ -1090,12 +1123,13 @@ impl HirDisplay for WhereClause {
             WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
             WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
                 write!(f, "<")?;
-                fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
-                write!(
-                    f,
-                    ">::{} = ",
-                    f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name,
-                )?;
+                fmt_trait_ref(f, &projection_ty.trait_ref(f.db), true)?;
+                write!(f, ">::",)?;
+                let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
+                f.start_location_link(type_alias.into());
+                write!(f, "{}", f.db.type_alias_data(type_alias).name,)?;
+                f.end_location_link();
+                write!(f, " = ")?;
                 ty.hir_fmt(f)?;
             }
             WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 6a58546982d..24973afb9ce 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -30,8 +30,8 @@ use hir_def::{
         ConstScalarOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
     },
     AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
-    HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
-    TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
+    HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, StructId,
+    TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
 };
 use hir_expand::{name::Name, ExpandResult};
 use intern::Interned;
@@ -1704,6 +1704,15 @@ pub enum CallableDefId {
     EnumVariantId(EnumVariantId),
 }
 impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
+impl From<CallableDefId> for ModuleDefId {
+    fn from(def: CallableDefId) -> ModuleDefId {
+        match def {
+            CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f),
+            CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)),
+            CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e),
+        }
+    }
+}
 
 impl CallableDefId {
     pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 5a4b2f33449..55d3b609768 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -270,7 +270,7 @@ impl HirDisplay for TypeParam {
         let has_only_not_sized_bound = predicates.is_empty();
         if !has_only_sized_bound || has_only_not_sized_bound {
             let default_sized = SizedByDefault::Sized { anchor: krate };
-            write_bounds_like_dyn_trait_with_prefix(":", &predicates, default_sized, f)?;
+            write_bounds_like_dyn_trait_with_prefix(f, ":", &predicates, default_sized)?;
         }
         Ok(())
     }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 2fc2673bd22..3865175b6dc 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -127,7 +127,7 @@ pub use {
         ExpandResult, HirFileId, InFile, MacroFile, Origin,
     },
     hir_ty::{
-        display::{HirDisplay, HirWrite},
+        display::{HirDisplay, HirDisplayError, HirWrite},
         PointerCast, Safety,
     },
 };
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 861bf1c66cb..7d33d1eac06 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -4,7 +4,9 @@ use std::{
 };
 
 use either::Either;
-use hir::{known, HasVisibility, HirDisplay, HirWrite, ModuleDef, ModuleDefId, Semantics};
+use hir::{
+    known, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef, ModuleDefId, Semantics,
+};
 use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
 use itertools::Itertools;
 use smallvec::{smallvec, SmallVec};
@@ -297,24 +299,35 @@ fn label_of_ty(
         mut max_length: Option<usize>,
         ty: hir::Type,
         label_builder: &mut InlayHintLabelBuilder<'_>,
-    ) {
+    ) -> Result<(), HirDisplayError> {
         let iter_item_type = hint_iterator(sema, famous_defs, &ty);
         match iter_item_type {
-            Some(ty) => {
-                const LABEL_START: &str = "impl Iterator<Item = ";
+            Some((iter_trait, ty)) => {
+                const LABEL_START: &str = "impl ";
+                const LABEL_ITERATOR: &str = "Iterator";
+                const LABEL_MIDDLE: &str = "<Item = ";
                 const LABEL_END: &str = ">";
 
-                max_length =
-                    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);
-                label_builder.write_str(LABEL_END).unwrap();
-            }
-            None => {
-                let _ = ty.display_truncated(sema.db, max_length).write_to(label_builder);
+                max_length = max_length.map(|len| {
+                    len.saturating_sub(
+                        LABEL_START.len()
+                            + LABEL_ITERATOR.len()
+                            + LABEL_MIDDLE.len()
+                            + LABEL_END.len(),
+                    )
+                });
+
+                label_builder.write_str(LABEL_START)?;
+                label_builder.start_location_link(ModuleDef::from(iter_trait).into());
+                label_builder.write_str(LABEL_ITERATOR)?;
+                label_builder.end_location_link();
+                label_builder.write_str(LABEL_MIDDLE)?;
+                rec(sema, famous_defs, max_length, ty, label_builder)?;
+                label_builder.write_str(LABEL_END)?;
+                Ok(())
             }
-        };
+            None => ty.display_truncated(sema.db, max_length).write_to(label_builder),
+        }
     }
 
     let mut label_builder = InlayHintLabelBuilder {
@@ -324,7 +337,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);
+    let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder);
     let r = label_builder.finish();
     Some(r)
 }
@@ -430,12 +443,12 @@ fn hints(
     };
 }
 
-/// Checks if the type is an Iterator from std::iter and returns its item type.
+/// Checks if the type is an Iterator from std::iter and returns the iterator trait and the item type of the concrete iterator.
 fn hint_iterator(
     sema: &Semantics<'_, RootDatabase>,
     famous_defs: &FamousDefs<'_, '_>,
     ty: &hir::Type,
-) -> Option<hir::Type> {
+) -> Option<(hir::Trait, hir::Type)> {
     let db = sema.db;
     let strukt = ty.strip_references().as_adt()?;
     let krate = strukt.module(db).krate();
@@ -458,7 +471,7 @@ fn hint_iterator(
             _ => None,
         })?;
         if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {
-            return Some(ty);
+            return Some((iter_trait, ty));
         }
     }
 
diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs
index 5227c651ff4..9c9e3c4bdae 100644
--- a/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/crates/ide/src/inlay_hints/bind_pat.rs
@@ -318,7 +318,33 @@ fn main(a: SliceIter<'_, Container>) {
                         range: 484..554,
                         kind: Chaining,
                         label: [
-                            "impl Iterator<Item = impl Iterator<Item = &&str>>",
+                            "impl ",
+                            InlayHintLabelPart {
+                                text: "Iterator",
+                                linked_location: Some(
+                                    FileRange {
+                                        file_id: FileId(
+                                            1,
+                                        ),
+                                        range: 2248..2256,
+                                    },
+                                ),
+                                tooltip: "",
+                            },
+                            "<Item = impl ",
+                            InlayHintLabelPart {
+                                text: "Iterator",
+                                linked_location: Some(
+                                    FileRange {
+                                        file_id: FileId(
+                                            1,
+                                        ),
+                                        range: 2248..2256,
+                                    },
+                                ),
+                                tooltip: "",
+                            },
+                            "<Item = &&str>>",
                         ],
                     },
                     InlayHint {
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index e0045a53d74..66fb53ecebc 100644
--- a/crates/ide/src/inlay_hints/chaining.rs
+++ b/crates/ide/src/inlay_hints/chaining.rs
@@ -408,21 +408,60 @@ fn main() {
                         range: 174..241,
                         kind: Chaining,
                         label: [
-                            "impl Iterator<Item = ()>",
+                            "impl ",
+                            InlayHintLabelPart {
+                                text: "Iterator",
+                                linked_location: Some(
+                                    FileRange {
+                                        file_id: FileId(
+                                            1,
+                                        ),
+                                        range: 2248..2256,
+                                    },
+                                ),
+                                tooltip: "",
+                            },
+                            "<Item = ()>",
                         ],
                     },
                     InlayHint {
                         range: 174..224,
                         kind: Chaining,
                         label: [
-                            "impl Iterator<Item = ()>",
+                            "impl ",
+                            InlayHintLabelPart {
+                                text: "Iterator",
+                                linked_location: Some(
+                                    FileRange {
+                                        file_id: FileId(
+                                            1,
+                                        ),
+                                        range: 2248..2256,
+                                    },
+                                ),
+                                tooltip: "",
+                            },
+                            "<Item = ()>",
                         ],
                     },
                     InlayHint {
                         range: 174..206,
                         kind: Chaining,
                         label: [
-                            "impl Iterator<Item = ()>",
+                            "impl ",
+                            InlayHintLabelPart {
+                                text: "Iterator",
+                                linked_location: Some(
+                                    FileRange {
+                                        file_id: FileId(
+                                            1,
+                                        ),
+                                        range: 2248..2256,
+                                    },
+                                ),
+                                tooltip: "",
+                            },
+                            "<Item = ()>",
                         ],
                     },
                     InlayHint {