mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-19 16:44:21 +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
crates
|
@ -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() {
|
for (seg_idx, segment) in self.segments().iter().enumerate() {
|
||||||
if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
|
if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
|
||||||
write!(f, "::")?;
|
write!(f, "::")?;
|
||||||
|
@ -1840,15 +1859,12 @@ impl HirDisplay for Path {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "<")?;
|
|
||||||
let mut first = true;
|
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 {
|
if first {
|
||||||
first = false;
|
first = false;
|
||||||
if generic_args.has_self_type {
|
write!(f, "<")?;
|
||||||
// FIXME: Convert to `<Ty as Trait>` form.
|
|
||||||
write!(f, "Self = ")?;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
|
@ -1857,6 +1873,7 @@ impl HirDisplay for Path {
|
||||||
for binding in generic_args.bindings.iter() {
|
for binding in generic_args.bindings.iter() {
|
||||||
if first {
|
if first {
|
||||||
first = false;
|
first = false;
|
||||||
|
write!(f, "<")?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, ", ")?;
|
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(())
|
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]
|
#[test]
|
||||||
fn test_hover_function_pointer_show_identifiers() {
|
fn test_hover_function_pointer_show_identifiers() {
|
||||||
check(
|
check(
|
||||||
|
|
Loading…
Reference in a new issue