Skip to content

Commit 0c1b273

Browse files
committed
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 rust-lang#20041 <rust-lang#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 rust-lang#20041 <rust-lang#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 rust-lang#68982.
1 parent 037f515 commit 0c1b273

File tree

3 files changed

+212
-6
lines changed

3 files changed

+212
-6
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,12 +1593,71 @@ fn deny_equality_constraints(
15931593
}
15941594
}
15951595
}
1596-
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
15971596
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1597+
// Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1598+
for bounds in generics.params.iter().map(|p| &p.bounds).chain(
1599+
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
1600+
WherePredicate::BoundPredicate(p) => Some(&p.bounds),
1601+
_ => None,
1602+
}),
1603+
) {
1604+
for bound in bounds {
1605+
if let GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound {
1606+
if full_path.segments[..full_path.segments.len() - 1]
1607+
.iter()
1608+
.map(|segment| segment.ident.name)
1609+
.zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name))
1610+
.all(|(a, b)| a == b)
1611+
{
1612+
let potential_assoc = full_path.segments.iter().last().unwrap();
1613+
// println!("asd");
1614+
if let [trait_segment] = &poly.trait_ref.path.segments[..] {
1615+
let assoc = pprust::path_to_string(&ast::Path::from_ident(
1616+
potential_assoc.ident,
1617+
));
1618+
let ty = pprust::ty_to_string(&predicate.rhs_ty);
1619+
let (args, span) = match &trait_segment.args {
1620+
Some(args) => match args.deref() {
1621+
ast::GenericArgs::AngleBracketed(args) => {
1622+
let Some(arg) = args.args.last() else {
1623+
continue;
1624+
};
1625+
(format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
1626+
}
1627+
_ => continue,
1628+
},
1629+
None => (
1630+
format!("<{assoc} = {ty}>"),
1631+
trait_segment.span().shrink_to_hi(),
1632+
),
1633+
};
1634+
err.assoc2 = Some(errors::AssociatedSuggestion2 {
1635+
span,
1636+
args,
1637+
predicate: predicate.span,
1638+
trait_segment: trait_segment.ident,
1639+
potential_assoc: potential_assoc.ident,
1640+
});
1641+
}
1642+
}
1643+
}
1644+
}
1645+
}
1646+
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
15981647
if let [potential_param, potential_assoc] = &full_path.segments[..] {
1599-
for param in &generics.params {
1600-
if param.ident == potential_param.ident {
1601-
for bound in &param.bounds {
1648+
for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
1649+
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
1650+
WherePredicate::BoundPredicate(p)
1651+
if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
1652+
&& let [segment] = &path.segments[..] =>
1653+
{
1654+
Some((segment.ident, &p.bounds))
1655+
}
1656+
_ => None,
1657+
}),
1658+
) {
1659+
if ident == potential_param.ident {
1660+
for bound in bounds {
16021661
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) =
16031662
bound
16041663
{

tests/ui/generic-associated-types/equality-bound.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,60 @@ fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
1212
panic!()
1313
}
1414

15+
use std::iter::FromIterator;
16+
17+
struct X {}
18+
19+
impl FromIterator<bool> for X {
20+
fn from_iter<T>(_: T) -> Self
21+
where
22+
T: IntoIterator,
23+
IntoIterator::Item = A,
24+
//~^ ERROR equality constraints are not yet supported in `where` clauses
25+
//~| ERROR cannot find type `A` in this scope
26+
{
27+
todo!()
28+
}
29+
}
30+
31+
struct Y {}
32+
33+
impl FromIterator<bool> for Y {
34+
fn from_iter<T>(_: T) -> Self
35+
where
36+
T: IntoIterator,
37+
T::Item = A,
38+
//~^ ERROR equality constraints are not yet supported in `where` clauses
39+
//~| ERROR cannot find type `A` in this scope
40+
{
41+
todo!()
42+
}
43+
}
44+
45+
struct Z {}
46+
47+
impl FromIterator<bool> for Z {
48+
fn from_iter<T: IntoIterator>(_: T) -> Self
49+
where
50+
IntoIterator::Item = A,
51+
//~^ ERROR equality constraints are not yet supported in `where` clauses
52+
//~| ERROR cannot find type `A` in this scope
53+
{
54+
todo!()
55+
}
56+
}
57+
58+
struct K {}
59+
60+
impl FromIterator<bool> for K {
61+
fn from_iter<T: IntoIterator>(_: T) -> Self
62+
where
63+
T::Item = A,
64+
//~^ ERROR equality constraints are not yet supported in `where` clauses
65+
//~| ERROR cannot find type `A` in this scope
66+
{
67+
todo!()
68+
}
69+
}
70+
1571
fn main() {}

tests/ui/generic-associated-types/equality-bound.stderr

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,96 @@ LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
3232
|
3333
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
3434

35+
error: equality constraints are not yet supported in `where` clauses
36+
--> $DIR/equality-bound.rs:23:9
37+
|
38+
LL | IntoIterator::Item = A,
39+
| ^^^^^^^^^^^^^^^^^^^^^^ not supported
40+
|
41+
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
42+
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
43+
|
44+
LL ~ T: IntoIterator<Item = A>,
45+
LL ~ ,
46+
|
47+
48+
error: equality constraints are not yet supported in `where` clauses
49+
--> $DIR/equality-bound.rs:37:9
50+
|
51+
LL | T::Item = A,
52+
| ^^^^^^^^^^^ not supported
53+
|
54+
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
55+
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
56+
|
57+
LL ~ T: IntoIterator<Item = A>,
58+
LL ~ ,
59+
|
60+
61+
error: equality constraints are not yet supported in `where` clauses
62+
--> $DIR/equality-bound.rs:50:9
63+
|
64+
LL | IntoIterator::Item = A,
65+
| ^^^^^^^^^^^^^^^^^^^^^^ not supported
66+
|
67+
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
68+
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
69+
|
70+
LL ~ fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self
71+
LL | where
72+
LL ~ ,
73+
|
74+
75+
error: equality constraints are not yet supported in `where` clauses
76+
--> $DIR/equality-bound.rs:63:9
77+
|
78+
LL | T::Item = A,
79+
| ^^^^^^^^^^^ not supported
80+
|
81+
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
82+
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
83+
|
84+
LL ~ fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self
85+
LL | where
86+
LL ~ ,
87+
|
88+
89+
error[E0412]: cannot find type `A` in this scope
90+
--> $DIR/equality-bound.rs:23:30
91+
|
92+
LL | IntoIterator::Item = A,
93+
| ^ help: a struct with a similar name exists: `K`
94+
...
95+
LL | struct K {}
96+
| -------- similarly named struct `K` defined here
97+
98+
error[E0412]: cannot find type `A` in this scope
99+
--> $DIR/equality-bound.rs:37:19
100+
|
101+
LL | T::Item = A,
102+
| ^ help: a struct with a similar name exists: `K`
103+
...
104+
LL | struct K {}
105+
| -------- similarly named struct `K` defined here
106+
107+
error[E0412]: cannot find type `A` in this scope
108+
--> $DIR/equality-bound.rs:50:30
109+
|
110+
LL | IntoIterator::Item = A,
111+
| ^ help: a struct with a similar name exists: `K`
112+
...
113+
LL | struct K {}
114+
| -------- similarly named struct `K` defined here
115+
116+
error[E0412]: cannot find type `A` in this scope
117+
--> $DIR/equality-bound.rs:63:19
118+
|
119+
LL | struct K {}
120+
| -------- similarly named struct `K` defined here
121+
...
122+
LL | T::Item = A,
123+
| ^ help: a struct with a similar name exists: `K`
124+
35125
error[E0433]: failed to resolve: use of undeclared type `I`
36126
--> $DIR/equality-bound.rs:9:41
37127
|
@@ -41,6 +131,7 @@ LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
41131
| use of undeclared type `I`
42132
| help: a type parameter with a similar name exists: `J`
43133

44-
error: aborting due to 4 previous errors
134+
error: aborting due to 12 previous errors
45135

46-
For more information about this error, try `rustc --explain E0433`.
136+
Some errors have detailed explanations: E0412, E0433.
137+
For more information about an error, try `rustc --explain E0412`.

0 commit comments

Comments
 (0)