mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-29 02:52:11 +00:00
Merge pull request #18925 from Veykril/push-mtxxvpowwtrt
feat: Render type parameter projection target bounds in inlays
This commit is contained in:
commit
9384ceeef8
2 changed files with 88 additions and 2 deletions
|
|
@ -471,10 +471,55 @@ impl HirDisplay for ProjectionTy {
|
||||||
if f.should_truncate() {
|
if f.should_truncate() {
|
||||||
return write!(f, "{TYPE_HINT_TRUNCATION}");
|
return write!(f, "{TYPE_HINT_TRUNCATION}");
|
||||||
}
|
}
|
||||||
|
|
||||||
let trait_ref = self.trait_ref(f.db);
|
let trait_ref = self.trait_ref(f.db);
|
||||||
|
let self_ty = trait_ref.self_type_parameter(Interner);
|
||||||
|
|
||||||
|
// if we are projection on a type parameter, check if the projection target has bounds
|
||||||
|
// itself, if so, we render them directly as `impl Bound` instead of the less useful
|
||||||
|
// `<Param as Trait>::Assoc`
|
||||||
|
if !f.display_target.is_source_code() {
|
||||||
|
if let TyKind::Placeholder(idx) = self_ty.kind(Interner) {
|
||||||
|
let db = f.db;
|
||||||
|
let id = from_placeholder_idx(db, *idx);
|
||||||
|
let generics = generics(db.upcast(), id.parent);
|
||||||
|
|
||||||
|
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) => {
|
||||||
|
match tr.self_type_parameter(Interner).kind(Interner) {
|
||||||
|
TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WhereClause::TypeOutlives(t) => match t.ty.kind(Interner) {
|
||||||
|
TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
// We shouldn't be here if these exist
|
||||||
|
WhereClause::AliasEq(_) => false,
|
||||||
|
WhereClause::LifetimeOutlives(_) => false,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if !bounds.is_empty() {
|
||||||
|
return write_bounds_like_dyn_trait_with_prefix(
|
||||||
|
f,
|
||||||
|
"impl",
|
||||||
|
Either::Left(
|
||||||
|
&TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner),
|
||||||
|
),
|
||||||
|
&bounds,
|
||||||
|
SizedByDefault::NotSized,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
|
self_ty.hir_fmt(f)?;
|
||||||
write!(f, " as ")?;
|
write!(f, " as ")?;
|
||||||
trait_ref.hir_fmt(f)?;
|
trait_ref.hir_fmt(f)?;
|
||||||
write!(
|
write!(
|
||||||
|
|
|
||||||
|
|
@ -1164,4 +1164,45 @@ fn main() {
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn collapses_nested_impl_projections() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
//- minicore: sized
|
||||||
|
trait T {
|
||||||
|
type Assoc;
|
||||||
|
fn f(self) -> Self::Assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait T2 {}
|
||||||
|
trait T3<T> {}
|
||||||
|
|
||||||
|
fn f(it: impl T<Assoc: T2>) {
|
||||||
|
let l = it.f();
|
||||||
|
// ^ impl T2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f2<G: T<Assoc: T2 + 'static>>(it: G) {
|
||||||
|
let l = it.f();
|
||||||
|
//^ impl T2 + 'static
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f3<G: T>(it: G) where <G as T>::Assoc: T2 {
|
||||||
|
let l = it.f();
|
||||||
|
//^ impl T2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f4<G: T<Assoc: T2 + T3<()>>>(it: G) {
|
||||||
|
let l = it.f();
|
||||||
|
//^ impl T2 + T3<()>
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f5<G: T<Assoc = ()>>(it: G) {
|
||||||
|
let l = it.f();
|
||||||
|
//^ ()
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue