mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-27 20:35:09 +00:00
Make inlay hint location links work for more types
This commit is contained in:
parent
f2444b2a40
commit
27ba598dfe
7 changed files with 220 additions and 99 deletions
crates
hir-ty/src
hir/src
ide/src
|
@ -325,7 +325,7 @@ impl HirDisplay for ProjectionTy {
|
||||||
|
|
||||||
let trait_ref = self.trait_ref(f.db);
|
let trait_ref = self.trait_ref(f.db);
|
||||||
write!(f, "<")?;
|
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)?;
|
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
|
||||||
let proj_params_count =
|
let proj_params_count =
|
||||||
self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
|
self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
|
||||||
|
@ -383,7 +383,10 @@ impl HirDisplay for BoundVar {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HirDisplay for Ty {
|
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() {
|
if f.should_truncate() {
|
||||||
return write!(f, "{TYPE_HINT_TRUNCATION}");
|
return write!(f, "{TYPE_HINT_TRUNCATION}");
|
||||||
}
|
}
|
||||||
|
@ -434,7 +437,7 @@ impl HirDisplay for Ty {
|
||||||
bounds.iter().any(|bound| {
|
bounds.iter().any(|bound| {
|
||||||
if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
|
if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
|
||||||
let trait_ = trait_ref.hir_trait_id();
|
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 {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -450,11 +453,10 @@ impl HirDisplay for Ty {
|
||||||
substitution: parameters,
|
substitution: parameters,
|
||||||
}))
|
}))
|
||||||
| TyKind::OpaqueType(opaque_ty_id, parameters) => {
|
| TyKind::OpaqueType(opaque_ty_id, parameters) => {
|
||||||
let impl_trait_id =
|
let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
|
||||||
f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
|
|
||||||
if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
|
if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
|
||||||
let datas =
|
let datas = db
|
||||||
f.db.return_type_impl_traits(func)
|
.return_type_impl_traits(func)
|
||||||
.expect("impl trait id without data");
|
.expect("impl trait id without data");
|
||||||
let data = (*datas)
|
let data = (*datas)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -465,7 +467,7 @@ impl HirDisplay for Ty {
|
||||||
// Don't count Sized but count when it absent
|
// Don't count Sized but count when it absent
|
||||||
// (i.e. when explicit ?Sized bound is set).
|
// (i.e. when explicit ?Sized bound is set).
|
||||||
let default_sized = SizedByDefault::Sized {
|
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
|
let sized_bounds = bounds
|
||||||
.skip_binders()
|
.skip_binders()
|
||||||
|
@ -476,7 +478,7 @@ impl HirDisplay for Ty {
|
||||||
WhereClause::Implemented(trait_ref)
|
WhereClause::Implemented(trait_ref)
|
||||||
if default_sized.is_sized_trait(
|
if default_sized.is_sized_trait(
|
||||||
trait_ref.hir_trait_id(),
|
trait_ref.hir_trait_id(),
|
||||||
f.db.upcast(),
|
db.upcast(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -524,19 +526,19 @@ impl HirDisplay for Ty {
|
||||||
sig.hir_fmt(f)?;
|
sig.hir_fmt(f)?;
|
||||||
}
|
}
|
||||||
TyKind::FnDef(def, parameters) => {
|
TyKind::FnDef(def, parameters) => {
|
||||||
let def = from_chalk(f.db, *def);
|
let def = from_chalk(db, *def);
|
||||||
let sig = f.db.callable_item_signature(def).substitute(Interner, parameters);
|
let sig = db.callable_item_signature(def).substitute(Interner, parameters);
|
||||||
|
f.start_location_link(def.into());
|
||||||
match def {
|
match def {
|
||||||
CallableDefId::FunctionId(ff) => {
|
CallableDefId::FunctionId(ff) => write!(f, "fn {}", db.function_data(ff).name)?,
|
||||||
write!(f, "fn {}", f.db.function_data(ff).name)?
|
CallableDefId::StructId(s) => write!(f, "{}", db.struct_data(s).name)?,
|
||||||
}
|
|
||||||
CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
|
|
||||||
CallableDefId::EnumVariantId(e) => {
|
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 {
|
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) =
|
let (parent_params, self_param, type_params, const_params, _impl_trait_params) =
|
||||||
generics.provenance_split();
|
generics.provenance_split();
|
||||||
let total_len = parent_params + self_param + type_params + const_params;
|
let total_len = parent_params + self_param + type_params + const_params;
|
||||||
|
@ -568,15 +570,15 @@ impl HirDisplay for Ty {
|
||||||
match f.display_target {
|
match f.display_target {
|
||||||
DisplayTarget::Diagnostics | DisplayTarget::Test => {
|
DisplayTarget::Diagnostics | DisplayTarget::Test => {
|
||||||
let name = match *def_id {
|
let name = match *def_id {
|
||||||
hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
|
hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(),
|
||||||
hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
|
hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(),
|
||||||
hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
|
hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(),
|
||||||
};
|
};
|
||||||
write!(f, "{name}")?;
|
write!(f, "{name}")?;
|
||||||
}
|
}
|
||||||
DisplayTarget::SourceCode { module_id } => {
|
DisplayTarget::SourceCode { module_id } => {
|
||||||
if let Some(path) = find_path::find_path(
|
if let Some(path) = find_path::find_path(
|
||||||
f.db.upcast(),
|
db.upcast(),
|
||||||
ItemInNs::Types((*def_id).into()),
|
ItemInNs::Types((*def_id).into()),
|
||||||
module_id,
|
module_id,
|
||||||
false,
|
false,
|
||||||
|
@ -596,8 +598,8 @@ impl HirDisplay for Ty {
|
||||||
|| f.omit_verbose_types()
|
|| f.omit_verbose_types()
|
||||||
{
|
{
|
||||||
match self
|
match self
|
||||||
.as_generic_def(f.db)
|
.as_generic_def(db)
|
||||||
.map(|generic_def_id| f.db.generic_defaults(generic_def_id))
|
.map(|generic_def_id| db.generic_defaults(generic_def_id))
|
||||||
.filter(|defaults| !defaults.is_empty())
|
.filter(|defaults| !defaults.is_empty())
|
||||||
{
|
{
|
||||||
None => parameters.as_slice(Interner),
|
None => parameters.as_slice(Interner),
|
||||||
|
@ -669,16 +671,23 @@ impl HirDisplay for Ty {
|
||||||
}
|
}
|
||||||
TyKind::AssociatedType(assoc_type_id, parameters) => {
|
TyKind::AssociatedType(assoc_type_id, parameters) => {
|
||||||
let type_alias = from_assoc_type_id(*assoc_type_id);
|
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,
|
ItemContainerId::TraitId(it) => it,
|
||||||
_ => panic!("not an associated type"),
|
_ => panic!("not an associated type"),
|
||||||
};
|
};
|
||||||
let trait_ = f.db.trait_data(trait_);
|
let trait_data = db.trait_data(trait_);
|
||||||
let type_alias_data = f.db.type_alias_data(type_alias);
|
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)
|
// 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() {
|
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
|
// Note that the generic args for the associated type come before those for the
|
||||||
// trait (including the self type).
|
// trait (including the self type).
|
||||||
// FIXME: reconsider the generic args order upon formatting?
|
// FIXME: reconsider the generic args order upon formatting?
|
||||||
|
@ -697,25 +706,28 @@ impl HirDisplay for Ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TyKind::Foreign(type_alias) => {
|
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)?;
|
write!(f, "{}", type_alias.name)?;
|
||||||
|
f.end_location_link();
|
||||||
}
|
}
|
||||||
TyKind::OpaqueType(opaque_ty_id, 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());
|
||||||
match impl_trait_id {
|
match impl_trait_id {
|
||||||
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
|
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
|
||||||
let datas =
|
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)
|
let data = (*datas)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
||||||
let bounds = data.substitute(Interner, ¶meters);
|
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(
|
write_bounds_like_dyn_trait_with_prefix(
|
||||||
|
f,
|
||||||
"impl",
|
"impl",
|
||||||
bounds.skip_binders(),
|
bounds.skip_binders(),
|
||||||
SizedByDefault::Sized { anchor: krate },
|
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
|
// 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,
|
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 let Some(sig) = sig {
|
||||||
if sig.params().is_empty() {
|
if sig.params().is_empty() {
|
||||||
write!(f, "||")?;
|
write!(f, "||")?;
|
||||||
|
@ -751,8 +763,8 @@ impl HirDisplay for Ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TyKind::Placeholder(idx) => {
|
TyKind::Placeholder(idx) => {
|
||||||
let id = from_placeholder_idx(f.db, *idx);
|
let id = from_placeholder_idx(db, *idx);
|
||||||
let generics = generics(f.db.upcast(), id.parent);
|
let generics = generics(db.upcast(), id.parent);
|
||||||
let param_data = &generics.params.type_or_consts[id.local_id];
|
let param_data = &generics.params.type_or_consts[id.local_id];
|
||||||
match param_data {
|
match param_data {
|
||||||
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
|
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
|
||||||
|
@ -760,9 +772,9 @@ impl HirDisplay for Ty {
|
||||||
write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))?
|
write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))?
|
||||||
}
|
}
|
||||||
TypeParamProvenance::ArgumentImplTrait => {
|
TypeParamProvenance::ArgumentImplTrait => {
|
||||||
let substs = generics.placeholder_subst(f.db);
|
let substs = generics.placeholder_subst(db);
|
||||||
let bounds =
|
let bounds = db
|
||||||
f.db.generic_predicates(id.parent)
|
.generic_predicates(id.parent)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pred| pred.clone().substitute(Interner, &substs))
|
.map(|pred| pred.clone().substitute(Interner, &substs))
|
||||||
.filter(|wc| match &wc.skip_binders() {
|
.filter(|wc| match &wc.skip_binders() {
|
||||||
|
@ -772,16 +784,16 @@ impl HirDisplay for Ty {
|
||||||
WhereClause::AliasEq(AliasEq {
|
WhereClause::AliasEq(AliasEq {
|
||||||
alias: AliasTy::Projection(proj),
|
alias: AliasTy::Projection(proj),
|
||||||
ty: _,
|
ty: _,
|
||||||
}) => &proj.self_type_parameter(f.db) == self,
|
}) => &proj.self_type_parameter(db) == self,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let krate = id.parent.module(f.db.upcast()).krate();
|
let krate = id.parent.module(db.upcast()).krate();
|
||||||
write_bounds_like_dyn_trait_with_prefix(
|
write_bounds_like_dyn_trait_with_prefix(
|
||||||
|
f,
|
||||||
"impl",
|
"impl",
|
||||||
&bounds,
|
&bounds,
|
||||||
SizedByDefault::Sized { anchor: krate },
|
SizedByDefault::Sized { anchor: krate },
|
||||||
f,
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -803,29 +815,29 @@ impl HirDisplay for Ty {
|
||||||
bounds.extend(auto_traits);
|
bounds.extend(auto_traits);
|
||||||
|
|
||||||
write_bounds_like_dyn_trait_with_prefix(
|
write_bounds_like_dyn_trait_with_prefix(
|
||||||
|
f,
|
||||||
"dyn",
|
"dyn",
|
||||||
&bounds,
|
&bounds,
|
||||||
SizedByDefault::NotSized,
|
SizedByDefault::NotSized,
|
||||||
f,
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
|
TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
|
||||||
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
|
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 {
|
match impl_trait_id {
|
||||||
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
|
ImplTraitId::ReturnTypeImplTrait(func, idx) => {
|
||||||
let datas =
|
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)
|
let data = (*datas)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
||||||
let bounds = data.substitute(Interner, &opaque_ty.substitution);
|
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(
|
write_bounds_like_dyn_trait_with_prefix(
|
||||||
|
f,
|
||||||
"impl",
|
"impl",
|
||||||
bounds.skip_binders(),
|
bounds.skip_binders(),
|
||||||
SizedByDefault::Sized { anchor: krate },
|
SizedByDefault::Sized { anchor: krate },
|
||||||
f,
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
|
||||||
|
@ -848,7 +860,6 @@ impl HirDisplay for Ty {
|
||||||
DisplaySourceCodeError::Generator,
|
DisplaySourceCodeError::Generator,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let subst = subst.as_slice(Interner);
|
let subst = subst.as_slice(Interner);
|
||||||
let a: Option<SmallVec<[&Ty; 3]>> = subst
|
let a: Option<SmallVec<[&Ty; 3]>> = subst
|
||||||
.get(subst.len() - 3..)
|
.get(subst.len() - 3..)
|
||||||
|
@ -923,26 +934,26 @@ impl SizedByDefault {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_bounds_like_dyn_trait_with_prefix(
|
pub fn write_bounds_like_dyn_trait_with_prefix(
|
||||||
|
f: &mut HirFormatter<'_>,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
predicates: &[QuantifiedWhereClause],
|
predicates: &[QuantifiedWhereClause],
|
||||||
default_sized: SizedByDefault,
|
default_sized: SizedByDefault,
|
||||||
f: &mut HirFormatter<'_>,
|
|
||||||
) -> Result<(), HirDisplayError> {
|
) -> Result<(), HirDisplayError> {
|
||||||
write!(f, "{prefix}")?;
|
write!(f, "{prefix}")?;
|
||||||
if !predicates.is_empty()
|
if !predicates.is_empty()
|
||||||
|| predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
|
|| predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
|
||||||
{
|
{
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
write_bounds_like_dyn_trait(predicates, default_sized, f)
|
write_bounds_like_dyn_trait(f, predicates, default_sized)
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bounds_like_dyn_trait(
|
fn write_bounds_like_dyn_trait(
|
||||||
|
f: &mut HirFormatter<'_>,
|
||||||
predicates: &[QuantifiedWhereClause],
|
predicates: &[QuantifiedWhereClause],
|
||||||
default_sized: SizedByDefault,
|
default_sized: SizedByDefault,
|
||||||
f: &mut HirFormatter<'_>,
|
|
||||||
) -> Result<(), HirDisplayError> {
|
) -> Result<(), HirDisplayError> {
|
||||||
// Note: This code is written to produce nice results (i.e.
|
// Note: This code is written to produce nice results (i.e.
|
||||||
// corresponding to surface Rust) for types that can occur in
|
// 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
|
// We assume that the self type is ^0.0 (i.e. the
|
||||||
// existential) here, which is the only thing that's
|
// existential) here, which is the only thing that's
|
||||||
// possible in actual Rust, and hence don't print it
|
// possible in actual Rust, and hence don't print it
|
||||||
|
f.start_location_link(trait_.into());
|
||||||
write!(f, "{}", f.db.trait_data(trait_).name)?;
|
write!(f, "{}", f.db.trait_data(trait_).name)?;
|
||||||
|
f.end_location_link();
|
||||||
if let [_, params @ ..] = &*trait_ref.substitution.as_slice(Interner) {
|
if let [_, params @ ..] = &*trait_ref.substitution.as_slice(Interner) {
|
||||||
if is_fn_trait {
|
if is_fn_trait {
|
||||||
if let Some(args) =
|
if let Some(args) =
|
||||||
|
@ -1015,7 +1028,9 @@ fn write_bounds_like_dyn_trait(
|
||||||
if let AliasTy::Projection(proj) = alias {
|
if let AliasTy::Projection(proj) = alias {
|
||||||
let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
|
let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
|
||||||
let type_alias = f.db.type_alias_data(assoc_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)?;
|
write!(f, "{}", type_alias.name)?;
|
||||||
|
f.end_location_link();
|
||||||
|
|
||||||
let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
|
let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
|
||||||
if proj_arg_count > 0 {
|
if proj_arg_count > 0 {
|
||||||
|
@ -1040,19 +1055,34 @@ fn write_bounds_like_dyn_trait(
|
||||||
if angle_open {
|
if angle_open {
|
||||||
write!(f, ">")?;
|
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 {
|
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 {
|
} else if first {
|
||||||
|
if let Some(sized_trait) = sized_trait {
|
||||||
|
f.start_location_link(sized_trait.into());
|
||||||
|
}
|
||||||
write!(f, "Sized")?;
|
write!(f, "Sized")?;
|
||||||
}
|
}
|
||||||
|
if let Some(_) = sized_trait {
|
||||||
|
f.end_location_link();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_trait_ref(
|
fn fmt_trait_ref(
|
||||||
tr: &TraitRef,
|
|
||||||
f: &mut HirFormatter<'_>,
|
f: &mut HirFormatter<'_>,
|
||||||
|
tr: &TraitRef,
|
||||||
use_as: bool,
|
use_as: bool,
|
||||||
) -> Result<(), HirDisplayError> {
|
) -> Result<(), HirDisplayError> {
|
||||||
if f.should_truncate() {
|
if f.should_truncate() {
|
||||||
|
@ -1065,7 +1095,10 @@ fn fmt_trait_ref(
|
||||||
} else {
|
} else {
|
||||||
write!(f, ": ")?;
|
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 {
|
if tr.substitution.len(Interner) > 1 {
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
f.write_joined(&tr.substitution.as_slice(Interner)[1..], ", ")?;
|
f.write_joined(&tr.substitution.as_slice(Interner)[1..], ", ")?;
|
||||||
|
@ -1076,7 +1109,7 @@ fn fmt_trait_ref(
|
||||||
|
|
||||||
impl HirDisplay for TraitRef {
|
impl HirDisplay for TraitRef {
|
||||||
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
|
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::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
|
||||||
WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
|
WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
|
fmt_trait_ref(f, &projection_ty.trait_ref(f.db), true)?;
|
||||||
write!(
|
write!(f, ">::",)?;
|
||||||
f,
|
let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
|
||||||
">::{} = ",
|
f.start_location_link(type_alias.into());
|
||||||
f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name,
|
write!(f, "{}", f.db.type_alias_data(type_alias).name,)?;
|
||||||
)?;
|
f.end_location_link();
|
||||||
|
write!(f, " = ")?;
|
||||||
ty.hir_fmt(f)?;
|
ty.hir_fmt(f)?;
|
||||||
}
|
}
|
||||||
WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
|
WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
|
||||||
|
|
|
@ -30,8 +30,8 @@ use hir_def::{
|
||||||
ConstScalarOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
|
ConstScalarOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
|
||||||
},
|
},
|
||||||
AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
|
AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
|
||||||
HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
|
HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, StructId,
|
||||||
TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
|
TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
|
||||||
};
|
};
|
||||||
use hir_expand::{name::Name, ExpandResult};
|
use hir_expand::{name::Name, ExpandResult};
|
||||||
use intern::Interned;
|
use intern::Interned;
|
||||||
|
@ -1704,6 +1704,15 @@ pub enum CallableDefId {
|
||||||
EnumVariantId(EnumVariantId),
|
EnumVariantId(EnumVariantId),
|
||||||
}
|
}
|
||||||
impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
|
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 {
|
impl CallableDefId {
|
||||||
pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
|
pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
|
||||||
|
|
|
@ -270,7 +270,7 @@ impl HirDisplay for TypeParam {
|
||||||
let has_only_not_sized_bound = predicates.is_empty();
|
let has_only_not_sized_bound = predicates.is_empty();
|
||||||
if !has_only_sized_bound || has_only_not_sized_bound {
|
if !has_only_sized_bound || has_only_not_sized_bound {
|
||||||
let default_sized = SizedByDefault::Sized { anchor: krate };
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ pub use {
|
||||||
ExpandResult, HirFileId, InFile, MacroFile, Origin,
|
ExpandResult, HirFileId, InFile, MacroFile, Origin,
|
||||||
},
|
},
|
||||||
hir_ty::{
|
hir_ty::{
|
||||||
display::{HirDisplay, HirWrite},
|
display::{HirDisplay, HirDisplayError, HirWrite},
|
||||||
PointerCast, Safety,
|
PointerCast, Safety,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,9 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use either::Either;
|
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 ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
@ -297,24 +299,35 @@ fn label_of_ty(
|
||||||
mut max_length: Option<usize>,
|
mut max_length: Option<usize>,
|
||||||
ty: hir::Type,
|
ty: hir::Type,
|
||||||
label_builder: &mut InlayHintLabelBuilder<'_>,
|
label_builder: &mut InlayHintLabelBuilder<'_>,
|
||||||
) {
|
) -> Result<(), HirDisplayError> {
|
||||||
let iter_item_type = hint_iterator(sema, famous_defs, &ty);
|
let iter_item_type = hint_iterator(sema, famous_defs, &ty);
|
||||||
match iter_item_type {
|
match iter_item_type {
|
||||||
Some(ty) => {
|
Some((iter_trait, ty)) => {
|
||||||
const LABEL_START: &str = "impl Iterator<Item = ";
|
const LABEL_START: &str = "impl ";
|
||||||
|
const LABEL_ITERATOR: &str = "Iterator";
|
||||||
|
const LABEL_MIDDLE: &str = "<Item = ";
|
||||||
const LABEL_END: &str = ">";
|
const LABEL_END: &str = ">";
|
||||||
|
|
||||||
max_length =
|
max_length = max_length.map(|len| {
|
||||||
max_length.map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len()));
|
len.saturating_sub(
|
||||||
|
LABEL_START.len()
|
||||||
|
+ LABEL_ITERATOR.len()
|
||||||
|
+ LABEL_MIDDLE.len()
|
||||||
|
+ LABEL_END.len(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
label_builder.write_str(LABEL_START).unwrap();
|
label_builder.write_str(LABEL_START)?;
|
||||||
rec(sema, famous_defs, max_length, ty, label_builder);
|
label_builder.start_location_link(ModuleDef::from(iter_trait).into());
|
||||||
label_builder.write_str(LABEL_END).unwrap();
|
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 => {
|
None => ty.display_truncated(sema.db, max_length).write_to(label_builder),
|
||||||
let _ = ty.display_truncated(sema.db, max_length).write_to(label_builder);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut label_builder = InlayHintLabelBuilder {
|
let mut label_builder = InlayHintLabelBuilder {
|
||||||
|
@ -324,7 +337,7 @@ fn label_of_ty(
|
||||||
location_link_enabled: config.location_links,
|
location_link_enabled: config.location_links,
|
||||||
result: InlayHintLabel::default(),
|
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();
|
let r = label_builder.finish();
|
||||||
Some(r)
|
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(
|
fn hint_iterator(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
famous_defs: &FamousDefs<'_, '_>,
|
famous_defs: &FamousDefs<'_, '_>,
|
||||||
ty: &hir::Type,
|
ty: &hir::Type,
|
||||||
) -> Option<hir::Type> {
|
) -> Option<(hir::Trait, hir::Type)> {
|
||||||
let db = sema.db;
|
let db = sema.db;
|
||||||
let strukt = ty.strip_references().as_adt()?;
|
let strukt = ty.strip_references().as_adt()?;
|
||||||
let krate = strukt.module(db).krate();
|
let krate = strukt.module(db).krate();
|
||||||
|
@ -458,7 +471,7 @@ fn hint_iterator(
|
||||||
_ => None,
|
_ => None,
|
||||||
})?;
|
})?;
|
||||||
if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {
|
if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {
|
||||||
return Some(ty);
|
return Some((iter_trait, ty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -318,7 +318,33 @@ fn main(a: SliceIter<'_, Container>) {
|
||||||
range: 484..554,
|
range: 484..554,
|
||||||
kind: Chaining,
|
kind: Chaining,
|
||||||
label: [
|
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 {
|
InlayHint {
|
||||||
|
|
|
@ -408,21 +408,60 @@ fn main() {
|
||||||
range: 174..241,
|
range: 174..241,
|
||||||
kind: Chaining,
|
kind: Chaining,
|
||||||
label: [
|
label: [
|
||||||
"impl Iterator<Item = ()>",
|
"impl ",
|
||||||
|
InlayHintLabelPart {
|
||||||
|
text: "Iterator",
|
||||||
|
linked_location: Some(
|
||||||
|
FileRange {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
range: 2248..2256,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
tooltip: "",
|
||||||
|
},
|
||||||
|
"<Item = ()>",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
InlayHint {
|
InlayHint {
|
||||||
range: 174..224,
|
range: 174..224,
|
||||||
kind: Chaining,
|
kind: Chaining,
|
||||||
label: [
|
label: [
|
||||||
"impl Iterator<Item = ()>",
|
"impl ",
|
||||||
|
InlayHintLabelPart {
|
||||||
|
text: "Iterator",
|
||||||
|
linked_location: Some(
|
||||||
|
FileRange {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
range: 2248..2256,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
tooltip: "",
|
||||||
|
},
|
||||||
|
"<Item = ()>",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
InlayHint {
|
InlayHint {
|
||||||
range: 174..206,
|
range: 174..206,
|
||||||
kind: Chaining,
|
kind: Chaining,
|
||||||
label: [
|
label: [
|
||||||
"impl Iterator<Item = ()>",
|
"impl ",
|
||||||
|
InlayHintLabelPart {
|
||||||
|
text: "Iterator",
|
||||||
|
linked_location: Some(
|
||||||
|
FileRange {
|
||||||
|
file_id: FileId(
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
range: 2248..2256,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
tooltip: "",
|
||||||
|
},
|
||||||
|
"<Item = ()>",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
InlayHint {
|
InlayHint {
|
||||||
|
|
Loading…
Reference in a new issue