mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-14 17:07:26 +00:00
Display fully qualified associated types correctly
Currently they are formatted in the internal `Trait<Self = Type>::Assoc` forms where `hir_ty::TypeRef` is formatted, like hover.
This commit is contained in:
parent
af4ba46b40
commit
3bfe1d5d78
2 changed files with 78 additions and 7 deletions
|
@ -1809,6 +1809,25 @@ impl HirDisplay for Path {
|
|||
}
|
||||
}
|
||||
|
||||
// Convert trait's `Self` bound back to the surface syntax. Note there is no associated
|
||||
// trait, so there can only be one path segment that `has_self_type`. The `Self` type
|
||||
// itself can contain further qualified path through, which will be handled by recursive
|
||||
// `hir_fmt`s.
|
||||
//
|
||||
// `trait_mod::Trait<Self = type_mod::Type, Args>::Assoc`
|
||||
// =>
|
||||
// `<type_mod::Type as trait_mod::Trait<Args>>::Assoc`
|
||||
let trait_self_ty = self.segments().iter().find_map(|seg| {
|
||||
let generic_args = seg.args_and_bindings?;
|
||||
generic_args.has_self_type.then(|| &generic_args.args[0])
|
||||
});
|
||||
if let Some(ty) = trait_self_ty {
|
||||
write!(f, "<")?;
|
||||
ty.hir_fmt(f)?;
|
||||
write!(f, " as ")?;
|
||||
// Now format the path of the trait...
|
||||
}
|
||||
|
||||
for (seg_idx, segment) in self.segments().iter().enumerate() {
|
||||
if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
|
||||
write!(f, "::")?;
|
||||
|
@ -1840,15 +1859,12 @@ impl HirDisplay for Path {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
write!(f, "<")?;
|
||||
let mut first = true;
|
||||
for arg in generic_args.args.iter() {
|
||||
// Skip the `Self` bound if exists. It's handled outside the loop.
|
||||
for arg in &generic_args.args[generic_args.has_self_type as usize..] {
|
||||
if first {
|
||||
first = false;
|
||||
if generic_args.has_self_type {
|
||||
// FIXME: Convert to `<Ty as Trait>` form.
|
||||
write!(f, "Self = ")?;
|
||||
}
|
||||
write!(f, "<")?;
|
||||
} else {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
|
@ -1857,6 +1873,7 @@ impl HirDisplay for Path {
|
|||
for binding in generic_args.bindings.iter() {
|
||||
if first {
|
||||
first = false;
|
||||
write!(f, "<")?;
|
||||
} else {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
|
@ -1872,9 +1889,20 @@ impl HirDisplay for Path {
|
|||
}
|
||||
}
|
||||
}
|
||||
write!(f, ">")?;
|
||||
|
||||
// There may be no generic arguments to print, in case of a trait having only a
|
||||
// single `Self` bound which is converted to `<Ty as Trait>::Assoc`.
|
||||
if !first {
|
||||
write!(f, ">")?;
|
||||
}
|
||||
|
||||
// Current position: `<Ty as Trait<Args>|`
|
||||
if generic_args.has_self_type {
|
||||
write!(f, ">")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1556,6 +1556,49 @@ fn test_hover_function_show_types() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hover_function_associated_type_params() {
|
||||
check(
|
||||
r#"
|
||||
trait Foo { type Bar; }
|
||||
impl Foo for i32 { type Bar = i64; }
|
||||
fn foo(arg: <i32 as Foo>::Bar) {}
|
||||
fn main() { foo$0; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
*foo*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
fn foo(arg: <i32 as Foo>::Bar)
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
trait Foo<T> { type Bar<U>; }
|
||||
impl Foo<i64> for i32 { type Bar<U> = i32; }
|
||||
fn foo(arg: <<i32 as Foo<i64>>::Bar<i8> as Foo<i64>>::Bar<i8>) {}
|
||||
fn main() { foo$0; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
*foo*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
fn foo(arg: <<i32 as Foo<i64>>::Bar<i8> as Foo<i64>>::Bar<i8>)
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hover_function_pointer_show_identifiers() {
|
||||
check(
|
||||
|
|
Loading…
Reference in a new issue