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, ¶meters); - 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::>(); - 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::>(); + 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> = 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 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, 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 { + const LABEL_START: &str = "impl "; + const LABEL_ITERATOR: &str = "Iterator"; + const LABEL_MIDDLE: &str = " { - let _ = ty.display_truncated(sema.db, max_length).write_to(label_builder); - } - }; + 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 { +) -> 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>", + "impl ", + InlayHintLabelPart { + text: "Iterator", + linked_location: Some( + FileRange { + file_id: FileId( + 1, + ), + range: 2248..2256, + }, + ), + tooltip: "", + }, + ">", ], }, 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", + "impl ", + InlayHintLabelPart { + text: "Iterator", + linked_location: Some( + FileRange { + file_id: FileId( + 1, + ), + range: 2248..2256, + }, + ), + tooltip: "", + }, + "", ], }, InlayHint { range: 174..224, kind: Chaining, label: [ - "impl Iterator", + "impl ", + InlayHintLabelPart { + text: "Iterator", + linked_location: Some( + FileRange { + file_id: FileId( + 1, + ), + range: 2248..2256, + }, + ), + tooltip: "", + }, + "", ], }, InlayHint { range: 174..206, kind: Chaining, label: [ - "impl Iterator", + "impl ", + InlayHintLabelPart { + text: "Iterator", + linked_location: Some( + FileRange { + file_id: FileId( + 1, + ), + range: 2248..2256, + }, + ), + tooltip: "", + }, + "", ], }, InlayHint {