Skip to content

Commit 0ed9d1c

Browse files
authored
Merge pull request rust-lang#18925 from Veykril/push-mtxxvpowwtrt
feat: Render type parameter projection target bounds in inlays
2 parents a12c80d + eed2b5c commit 0ed9d1c

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

src/tools/rust-analyzer/crates/hir-ty/src/display.rs

+47-2
Original file line numberDiff line numberDiff line change
@@ -471,10 +471,55 @@ impl HirDisplay for ProjectionTy {
471471
if f.should_truncate() {
472472
return write!(f, "{TYPE_HINT_TRUNCATION}");
473473
}
474-
475474
let trait_ref = self.trait_ref(f.db);
475+
let self_ty = trait_ref.self_type_parameter(Interner);
476+
477+
// if we are projection on a type parameter, check if the projection target has bounds
478+
// itself, if so, we render them directly as `impl Bound` instead of the less useful
479+
// `<Param as Trait>::Assoc`
480+
if !f.display_target.is_source_code() {
481+
if let TyKind::Placeholder(idx) = self_ty.kind(Interner) {
482+
let db = f.db;
483+
let id = from_placeholder_idx(db, *idx);
484+
let generics = generics(db.upcast(), id.parent);
485+
486+
let substs = generics.placeholder_subst(db);
487+
let bounds = db
488+
.generic_predicates(id.parent)
489+
.iter()
490+
.map(|pred| pred.clone().substitute(Interner, &substs))
491+
.filter(|wc| match wc.skip_binders() {
492+
WhereClause::Implemented(tr) => {
493+
match tr.self_type_parameter(Interner).kind(Interner) {
494+
TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
495+
_ => false,
496+
}
497+
}
498+
WhereClause::TypeOutlives(t) => match t.ty.kind(Interner) {
499+
TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
500+
_ => false,
501+
},
502+
// We shouldn't be here if these exist
503+
WhereClause::AliasEq(_) => false,
504+
WhereClause::LifetimeOutlives(_) => false,
505+
})
506+
.collect::<Vec<_>>();
507+
if !bounds.is_empty() {
508+
return write_bounds_like_dyn_trait_with_prefix(
509+
f,
510+
"impl",
511+
Either::Left(
512+
&TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner),
513+
),
514+
&bounds,
515+
SizedByDefault::NotSized,
516+
);
517+
};
518+
}
519+
}
520+
476521
write!(f, "<")?;
477-
trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
522+
self_ty.hir_fmt(f)?;
478523
write!(f, " as ")?;
479524
trait_ref.hir_fmt(f)?;
480525
write!(

src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs

+41
Original file line numberDiff line numberDiff line change
@@ -1164,4 +1164,45 @@ fn main() {
11641164
}"#,
11651165
);
11661166
}
1167+
1168+
#[test]
1169+
fn collapses_nested_impl_projections() {
1170+
check_types(
1171+
r#"
1172+
//- minicore: sized
1173+
trait T {
1174+
type Assoc;
1175+
fn f(self) -> Self::Assoc;
1176+
}
1177+
1178+
trait T2 {}
1179+
trait T3<T> {}
1180+
1181+
fn f(it: impl T<Assoc: T2>) {
1182+
let l = it.f();
1183+
// ^ impl T2
1184+
}
1185+
1186+
fn f2<G: T<Assoc: T2 + 'static>>(it: G) {
1187+
let l = it.f();
1188+
//^ impl T2 + 'static
1189+
}
1190+
1191+
fn f3<G: T>(it: G) where <G as T>::Assoc: T2 {
1192+
let l = it.f();
1193+
//^ impl T2
1194+
}
1195+
1196+
fn f4<G: T<Assoc: T2 + T3<()>>>(it: G) {
1197+
let l = it.f();
1198+
//^ impl T2 + T3<()>
1199+
}
1200+
1201+
fn f5<G: T<Assoc = ()>>(it: G) {
1202+
let l = it.f();
1203+
//^ ()
1204+
}
1205+
"#,
1206+
);
1207+
}
11671208
}

0 commit comments

Comments
 (0)