Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 6918eb6

Browse files
committed
Auto merge of rust-lang#15416 - oxalica:fix/hover-assoc-type, r=lowr
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. There is no test of `TypeRef::hir_fmt` in crate `hir-ty` (verified by replacing it with a `panic!()`), most tests are about inference and printing the real `Ty` instead of `TypeRef`. So I added the test in `ide::hover`.
2 parents af4ba46 + 3bfe1d5 commit 6918eb6

File tree

2 files changed

+78
-7
lines changed

2 files changed

+78
-7
lines changed

crates/hir-ty/src/display.rs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,25 @@ impl HirDisplay for Path {
18091809
}
18101810
}
18111811

1812+
// Convert trait's `Self` bound back to the surface syntax. Note there is no associated
1813+
// trait, so there can only be one path segment that `has_self_type`. The `Self` type
1814+
// itself can contain further qualified path through, which will be handled by recursive
1815+
// `hir_fmt`s.
1816+
//
1817+
// `trait_mod::Trait<Self = type_mod::Type, Args>::Assoc`
1818+
// =>
1819+
// `<type_mod::Type as trait_mod::Trait<Args>>::Assoc`
1820+
let trait_self_ty = self.segments().iter().find_map(|seg| {
1821+
let generic_args = seg.args_and_bindings?;
1822+
generic_args.has_self_type.then(|| &generic_args.args[0])
1823+
});
1824+
if let Some(ty) = trait_self_ty {
1825+
write!(f, "<")?;
1826+
ty.hir_fmt(f)?;
1827+
write!(f, " as ")?;
1828+
// Now format the path of the trait...
1829+
}
1830+
18121831
for (seg_idx, segment) in self.segments().iter().enumerate() {
18131832
if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
18141833
write!(f, "::")?;
@@ -1840,15 +1859,12 @@ impl HirDisplay for Path {
18401859
return Ok(());
18411860
}
18421861

1843-
write!(f, "<")?;
18441862
let mut first = true;
1845-
for arg in generic_args.args.iter() {
1863+
// Skip the `Self` bound if exists. It's handled outside the loop.
1864+
for arg in &generic_args.args[generic_args.has_self_type as usize..] {
18461865
if first {
18471866
first = false;
1848-
if generic_args.has_self_type {
1849-
// FIXME: Convert to `<Ty as Trait>` form.
1850-
write!(f, "Self = ")?;
1851-
}
1867+
write!(f, "<")?;
18521868
} else {
18531869
write!(f, ", ")?;
18541870
}
@@ -1857,6 +1873,7 @@ impl HirDisplay for Path {
18571873
for binding in generic_args.bindings.iter() {
18581874
if first {
18591875
first = false;
1876+
write!(f, "<")?;
18601877
} else {
18611878
write!(f, ", ")?;
18621879
}
@@ -1872,9 +1889,20 @@ impl HirDisplay for Path {
18721889
}
18731890
}
18741891
}
1875-
write!(f, ">")?;
1892+
1893+
// There may be no generic arguments to print, in case of a trait having only a
1894+
// single `Self` bound which is converted to `<Ty as Trait>::Assoc`.
1895+
if !first {
1896+
write!(f, ">")?;
1897+
}
1898+
1899+
// Current position: `<Ty as Trait<Args>|`
1900+
if generic_args.has_self_type {
1901+
write!(f, ">")?;
1902+
}
18761903
}
18771904
}
1905+
18781906
Ok(())
18791907
}
18801908
}

crates/ide/src/hover/tests.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,6 +1556,49 @@ fn test_hover_function_show_types() {
15561556
);
15571557
}
15581558

1559+
#[test]
1560+
fn test_hover_function_associated_type_params() {
1561+
check(
1562+
r#"
1563+
trait Foo { type Bar; }
1564+
impl Foo for i32 { type Bar = i64; }
1565+
fn foo(arg: <i32 as Foo>::Bar) {}
1566+
fn main() { foo$0; }
1567+
"#,
1568+
expect![[r#"
1569+
*foo*
1570+
1571+
```rust
1572+
test
1573+
```
1574+
1575+
```rust
1576+
fn foo(arg: <i32 as Foo>::Bar)
1577+
```
1578+
"#]],
1579+
);
1580+
1581+
check(
1582+
r#"
1583+
trait Foo<T> { type Bar<U>; }
1584+
impl Foo<i64> for i32 { type Bar<U> = i32; }
1585+
fn foo(arg: <<i32 as Foo<i64>>::Bar<i8> as Foo<i64>>::Bar<i8>) {}
1586+
fn main() { foo$0; }
1587+
"#,
1588+
expect![[r#"
1589+
*foo*
1590+
1591+
```rust
1592+
test
1593+
```
1594+
1595+
```rust
1596+
fn foo(arg: <<i32 as Foo<i64>>::Bar<i8> as Foo<i64>>::Bar<i8>)
1597+
```
1598+
"#]],
1599+
);
1600+
}
1601+
15591602
#[test]
15601603
fn test_hover_function_pointer_show_identifiers() {
15611604
check(

0 commit comments

Comments
 (0)