mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
fix(suggestion): insert projection to associated types
This commit is contained in:
parent
b8536c1aa1
commit
b83dfb5c5a
@ -329,41 +329,52 @@ fn bounds_from_generic_predicates<'tcx>(
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let generics = if types.is_empty() {
|
||||
"".to_string()
|
||||
} else {
|
||||
format!(
|
||||
"<{}>",
|
||||
types
|
||||
.keys()
|
||||
.filter_map(|t| match t.kind() {
|
||||
ty::Param(_) => Some(t.to_string()),
|
||||
// Avoid suggesting the following:
|
||||
// fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
};
|
||||
|
||||
let mut where_clauses = vec![];
|
||||
let mut types_str = vec![];
|
||||
for (ty, bounds) in types {
|
||||
where_clauses
|
||||
.extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))));
|
||||
}
|
||||
for projection in &projections {
|
||||
let p = projection.skip_binder();
|
||||
// FIXME: this is not currently supported syntax, we should be looking at the `types` and
|
||||
// insert the associated types where they correspond, but for now let's be "lazy" and
|
||||
// propose this instead of the following valid resugaring:
|
||||
// `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
|
||||
where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.def_id), p.term));
|
||||
if let ty::Param(_) = ty.kind() {
|
||||
let mut bounds_str = vec![];
|
||||
for bound in bounds {
|
||||
let mut projections_str = vec![];
|
||||
for projection in &projections {
|
||||
let p = projection.skip_binder();
|
||||
let alias_ty = p.projection_ty;
|
||||
if bound == tcx.parent(alias_ty.def_id) && alias_ty.self_ty() == ty {
|
||||
let name = tcx.item_name(alias_ty.def_id);
|
||||
projections_str.push(format!("{} = {}", name, p.term));
|
||||
}
|
||||
}
|
||||
let bound_def_path = tcx.def_path_str(bound);
|
||||
if projections_str.is_empty() {
|
||||
where_clauses.push(format!("{}: {}", ty, bound_def_path));
|
||||
} else {
|
||||
bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", ")));
|
||||
}
|
||||
}
|
||||
if bounds_str.is_empty() {
|
||||
types_str.push(ty.to_string());
|
||||
} else {
|
||||
types_str.push(format!("{}: {}", ty, bounds_str.join(" + ")));
|
||||
}
|
||||
} else {
|
||||
// Avoid suggesting the following:
|
||||
// fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
|
||||
where_clauses.extend(
|
||||
bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let generics =
|
||||
if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) };
|
||||
|
||||
let where_clauses = if where_clauses.is_empty() {
|
||||
String::new()
|
||||
"".to_string()
|
||||
} else {
|
||||
format!(" where {}", where_clauses.join(", "))
|
||||
};
|
||||
|
||||
(generics, where_clauses)
|
||||
}
|
||||
|
||||
|
26
tests/ui/suggestions/auxiliary/extern-issue-98562.rs
Normal file
26
tests/ui/suggestions/auxiliary/extern-issue-98562.rs
Normal file
@ -0,0 +1,26 @@
|
||||
pub trait TraitE {
|
||||
type I3;
|
||||
}
|
||||
|
||||
pub trait TraitD {
|
||||
type I3;
|
||||
}
|
||||
|
||||
pub trait TraitC {
|
||||
type I1;
|
||||
type I2;
|
||||
}
|
||||
|
||||
pub trait TraitB {
|
||||
type Item;
|
||||
}
|
||||
|
||||
pub trait TraitA<G1, G2, G3> {
|
||||
fn baz<
|
||||
U: TraitC<I1 = G1, I2 = G2> + TraitD<I3 = G3> + TraitE,
|
||||
V: TraitD<I3 = G1>
|
||||
>(_: U, _: V) -> Self
|
||||
where
|
||||
U: TraitB,
|
||||
<U as TraitB>::Item: Copy;
|
||||
}
|
12
tests/ui/suggestions/issue-98562.rs
Normal file
12
tests/ui/suggestions/issue-98562.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// aux-build:extern-issue-98562.rs
|
||||
|
||||
extern crate extern_issue_98562;
|
||||
use extern_issue_98562::TraitA;
|
||||
|
||||
struct X;
|
||||
impl TraitA<u8, u16, u32> for X {
|
||||
//~^ ERROR not all trait items implemented
|
||||
}
|
||||
//~^ 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!() }`
|
||||
|
||||
fn main() {}
|
11
tests/ui/suggestions/issue-98562.stderr
Normal file
11
tests/ui/suggestions/issue-98562.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0046]: not all trait items implemented, missing: `baz`
|
||||
--> $DIR/issue-98562.rs:7:1
|
||||
|
|
||||
LL | impl TraitA<u8, u16, u32> for X {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `baz` in implementation
|
||||
|
|
||||
= 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!() }`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0046`.
|
@ -28,7 +28,7 @@ error[E0046]: not all trait items implemented, missing: `from_iter`
|
||||
LL | impl FromIterator<()> for X {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_iter` in implementation
|
||||
|
|
||||
= help: implement the missing item: `fn from_iter<T>(_: T) -> Self where T: IntoIterator, std::iter::IntoIterator::Item = () { todo!() }`
|
||||
= help: implement the missing item: `fn from_iter<T: IntoIterator<Item = ()>>(_: T) -> Self { todo!() }`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user