Skip to content

Commit 0341fcd

Browse files
committed
fix(suggestion): insert projection to associated types
1 parent 5e9d3d8 commit 0341fcd

File tree

5 files changed

+89
-29
lines changed

5 files changed

+89
-29
lines changed

compiler/rustc_hir_analysis/src/check/mod.rs

+39-28
Original file line numberDiff line numberDiff line change
@@ -320,41 +320,52 @@ fn bounds_from_generic_predicates<'tcx>(
320320
_ => {}
321321
}
322322
}
323-
let generics = if types.is_empty() {
324-
"".to_string()
325-
} else {
326-
format!(
327-
"<{}>",
328-
types
329-
.keys()
330-
.filter_map(|t| match t.kind() {
331-
ty::Param(_) => Some(t.to_string()),
332-
// Avoid suggesting the following:
333-
// fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
334-
_ => None,
335-
})
336-
.collect::<Vec<_>>()
337-
.join(", ")
338-
)
339-
};
323+
340324
let mut where_clauses = vec![];
325+
let mut types_str = vec![];
341326
for (ty, bounds) in types {
342-
where_clauses
343-
.extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
344-
}
345-
for projection in &projections {
346-
let p = projection.skip_binder();
347-
// FIXME: this is not currently supported syntax, we should be looking at the `types` and
348-
// insert the associated types where they correspond, but for now let's be "lazy" and
349-
// propose this instead of the following valid resugaring:
350-
// `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
351-
where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.def_id), p.term));
327+
if let ty::Param(_) = ty.kind() {
328+
let mut bounds_str = vec![];
329+
for bound in bounds {
330+
let mut projections_str = vec![];
331+
for projection in &projections {
332+
let p = projection.skip_binder();
333+
let alias_ty = p.projection_ty;
334+
if bound == tcx.parent(alias_ty.def_id) && alias_ty.self_ty() == ty {
335+
let name = tcx.item_name(alias_ty.def_id);
336+
projections_str.push(format!("{} = {}", name, p.term));
337+
}
338+
}
339+
let bound_def_path = tcx.def_path_str(bound);
340+
if projections_str.is_empty() {
341+
where_clauses.push(format!("{}: {}", ty, bound_def_path));
342+
} else {
343+
bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", ")));
344+
}
345+
}
346+
if bounds_str.is_empty() {
347+
types_str.push(ty.to_string());
348+
} else {
349+
types_str.push(format!("{}: {}", ty, bounds_str.join(" + ")));
350+
}
351+
} else {
352+
// Avoid suggesting the following:
353+
// fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
354+
where_clauses.extend(
355+
bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))),
356+
);
357+
}
352358
}
359+
360+
let generics =
361+
if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) };
362+
353363
let where_clauses = if where_clauses.is_empty() {
354-
String::new()
364+
"".to_string()
355365
} else {
356366
format!(" where {}", where_clauses.join(", "))
357367
};
368+
358369
(generics, where_clauses)
359370
}
360371

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
pub trait TraitE {
2+
type I3;
3+
}
4+
5+
pub trait TraitD {
6+
type I3;
7+
}
8+
9+
pub trait TraitC {
10+
type I1;
11+
type I2;
12+
}
13+
14+
pub trait TraitB {
15+
type Item;
16+
}
17+
18+
pub trait TraitA<G1, G2, G3> {
19+
fn baz<
20+
U: TraitC<I1 = G1, I2 = G2> + TraitD<I3 = G3> + TraitE,
21+
V: TraitD<I3 = G1>
22+
>(_: U, _: V) -> Self
23+
where
24+
U: TraitB,
25+
<U as TraitB>::Item: Copy;
26+
}

tests/ui/suggestions/issue-98562.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// aux-build:extern-issue-98562.rs
2+
3+
extern crate extern_issue_98562;
4+
use extern_issue_98562::TraitA;
5+
6+
struct X;
7+
impl TraitA<u8, u16, u32> for X {
8+
//~^ ERROR not all trait items implemented
9+
}
10+
//~^ HELP implement the missing item: `fn baz<U: TraitC<I1 = u8, I2 = u16> + TraitD<I3 = u32>, V: TraitD<I3 = u8>>(_: U, _: V) -> Self where U: TraitE, U: TraitB, <U as TraitB>::Item: Copy { todo!() }`
11+
12+
fn main() {}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0046]: not all trait items implemented, missing: `baz`
2+
--> $DIR/issue-98562.rs:7:1
3+
|
4+
LL | impl TraitA<u8, u16, u32> for X {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `baz` in implementation
6+
|
7+
= help: implement the missing item: `fn baz<U: TraitC<I1 = u8, I2 = u16> + TraitD<I3 = u32>, V: TraitD<I3 = u8>>(_: U, _: V) -> Self where U: TraitE, U: TraitB, <U as TraitB>::Item: Copy { todo!() }`
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0046`.

tests/ui/suggestions/missing-assoc-fn.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ error[E0046]: not all trait items implemented, missing: `from_iter`
2828
LL | impl FromIterator<()> for X {
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_iter` in implementation
3030
|
31-
= help: implement the missing item: `fn from_iter<T>(_: T) -> Self where T: IntoIterator, std::iter::IntoIterator::Item = () { todo!() }`
31+
= help: implement the missing item: `fn from_iter<T: IntoIterator<Item = ()>>(_: T) -> Self { todo!() }`
3232

3333
error: aborting due to 3 previous errors
3434

0 commit comments

Comments
 (0)