Skip to content

Commit

Permalink
Provide more suggestions on invalid equality where bounds
Browse files Browse the repository at this point in the history
```
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 <#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 <#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.
  • Loading branch information
estebank committed Feb 7, 2024
1 parent 037f515 commit 0c1b273
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 6 deletions.
67 changes: 63 additions & 4 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
56 changes: 56 additions & 0 deletions tests/ui/generic-associated-types/equality-bound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
95 changes: 93 additions & 2 deletions tests/ui/generic-associated-types/equality-bound.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand All @@ -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`.

0 comments on commit 0c1b273

Please sign in to comment.