Provide more suggestions on invalid equality where bounds

```
error: equality constraints are not yet supported in `where` clauses
  --> $DIR/equality-bound.rs:50:9
   |
LL |         IntoIterator::Item = A,
   |         ^^^^^^^^^^^^^^^^^^^^^^ not supported
   |
   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
   |
LL ~     fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self
LL |     where
LL ~
   |

error: equality constraints are not yet supported in `where` clauses
  --> $DIR/equality-bound.rs:63:9
   |
LL |         T::Item = A,
   |         ^^^^^^^^^^^ not supported
   |
   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
   |
LL ~     fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self
LL |     where
LL ~
   |
```

Fix #68982.
This commit is contained in:
Esteban Küber 2024-02-07 20:01:09 +00:00
parent 037f515caf
commit 0c1b2731f8
3 changed files with 212 additions and 6 deletions

View File

@ -1593,12 +1593,71 @@ fn deny_equality_constraints(
}
}
}
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
// Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
for bounds in generics.params.iter().map(|p| &p.bounds).chain(
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
WherePredicate::BoundPredicate(p) => Some(&p.bounds),
_ => None,
}),
) {
for bound in bounds {
if let GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound {
if full_path.segments[..full_path.segments.len() - 1]
.iter()
.map(|segment| segment.ident.name)
.zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name))
.all(|(a, b)| a == b)
{
let potential_assoc = full_path.segments.iter().last().unwrap();
// println!("asd");
if let [trait_segment] = &poly.trait_ref.path.segments[..] {
let assoc = pprust::path_to_string(&ast::Path::from_ident(
potential_assoc.ident,
));
let ty = pprust::ty_to_string(&predicate.rhs_ty);
let (args, span) = match &trait_segment.args {
Some(args) => match args.deref() {
ast::GenericArgs::AngleBracketed(args) => {
let Some(arg) = args.args.last() else {
continue;
};
(format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
}
_ => continue,
},
None => (
format!("<{assoc} = {ty}>"),
trait_segment.span().shrink_to_hi(),
),
};
err.assoc2 = Some(errors::AssociatedSuggestion2 {
span,
args,
predicate: predicate.span,
trait_segment: trait_segment.ident,
potential_assoc: potential_assoc.ident,
});
}
}
}
}
}
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
if let [potential_param, potential_assoc] = &full_path.segments[..] {
for param in &generics.params {
if param.ident == potential_param.ident {
for bound in &param.bounds {
for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
WherePredicate::BoundPredicate(p)
if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
&& let [segment] = &path.segments[..] =>
{
Some((segment.ident, &p.bounds))
}
_ => None,
}),
) {
if ident == potential_param.ident {
for bound in bounds {
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) =
bound
{

View File

@ -12,4 +12,60 @@ fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
panic!()
}
use std::iter::FromIterator;
struct X {}
impl FromIterator<bool> for X {
fn from_iter<T>(_: T) -> Self
where
T: IntoIterator,
IntoIterator::Item = A,
//~^ ERROR equality constraints are not yet supported in `where` clauses
//~| ERROR cannot find type `A` in this scope
{
todo!()
}
}
struct Y {}
impl FromIterator<bool> for Y {
fn from_iter<T>(_: T) -> Self
where
T: IntoIterator,
T::Item = A,
//~^ ERROR equality constraints are not yet supported in `where` clauses
//~| ERROR cannot find type `A` in this scope
{
todo!()
}
}
struct Z {}
impl FromIterator<bool> for Z {
fn from_iter<T: IntoIterator>(_: T) -> Self
where
IntoIterator::Item = A,
//~^ ERROR equality constraints are not yet supported in `where` clauses
//~| ERROR cannot find type `A` in this scope
{
todo!()
}
}
struct K {}
impl FromIterator<bool> for K {
fn from_iter<T: IntoIterator>(_: T) -> Self
where
T::Item = A,
//~^ ERROR equality constraints are not yet supported in `where` clauses
//~| ERROR cannot find type `A` in this scope
{
todo!()
}
}
fn main() {}

View File

@ -32,6 +32,96 @@ LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
error: equality constraints are not yet supported in `where` clauses
--> $DIR/equality-bound.rs:23:9
|
LL | IntoIterator::Item = A,
| ^^^^^^^^^^^^^^^^^^^^^^ not supported
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
|
LL ~ T: IntoIterator<Item = A>,
LL ~ ,
|
error: equality constraints are not yet supported in `where` clauses
--> $DIR/equality-bound.rs:37:9
|
LL | T::Item = A,
| ^^^^^^^^^^^ not supported
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
|
LL ~ T: IntoIterator<Item = A>,
LL ~ ,
|
error: equality constraints are not yet supported in `where` clauses
--> $DIR/equality-bound.rs:50:9
|
LL | IntoIterator::Item = A,
| ^^^^^^^^^^^^^^^^^^^^^^ not supported
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
|
LL ~ fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self
LL | where
LL ~ ,
|
error: equality constraints are not yet supported in `where` clauses
--> $DIR/equality-bound.rs:63:9
|
LL | T::Item = A,
| ^^^^^^^^^^^ not supported
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
|
LL ~ fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self
LL | where
LL ~ ,
|
error[E0412]: cannot find type `A` in this scope
--> $DIR/equality-bound.rs:23:30
|
LL | IntoIterator::Item = A,
| ^ help: a struct with a similar name exists: `K`
...
LL | struct K {}
| -------- similarly named struct `K` defined here
error[E0412]: cannot find type `A` in this scope
--> $DIR/equality-bound.rs:37:19
|
LL | T::Item = A,
| ^ help: a struct with a similar name exists: `K`
...
LL | struct K {}
| -------- similarly named struct `K` defined here
error[E0412]: cannot find type `A` in this scope
--> $DIR/equality-bound.rs:50:30
|
LL | IntoIterator::Item = A,
| ^ help: a struct with a similar name exists: `K`
...
LL | struct K {}
| -------- similarly named struct `K` defined here
error[E0412]: cannot find type `A` in this scope
--> $DIR/equality-bound.rs:63:19
|
LL | struct K {}
| -------- similarly named struct `K` defined here
...
LL | T::Item = A,
| ^ help: a struct with a similar name exists: `K`
error[E0433]: failed to resolve: use of undeclared type `I`
--> $DIR/equality-bound.rs:9:41
|
@ -41,6 +131,7 @@ LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
| use of undeclared type `I`
| help: a type parameter with a similar name exists: `J`
error: aborting due to 4 previous errors
error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0433`.
Some errors have detailed explanations: E0412, E0433.
For more information about an error, try `rustc --explain E0412`.