Skip to content

Commit 1b39691

Browse files
authored
Rollup merge of #120751 - estebank:issue-68982, r=nnethercote
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 <#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 ~ | 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 ~ | ``` Fix #68982.
2 parents 020e846 + 535c643 commit 1b39691

File tree

3 files changed

+293
-39
lines changed

3 files changed

+293
-39
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

+89-35
Original file line numberDiff line numberDiff line change
@@ -1593,44 +1593,98 @@ fn deny_equality_constraints(
15931593
}
15941594
}
15951595
}
1596-
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1597-
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1598-
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 {
1602-
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) =
1603-
bound
1596+
1597+
let mut suggest =
1598+
|poly: &PolyTraitRef, potential_assoc: &PathSegment, predicate: &WhereEqPredicate| {
1599+
if let [trait_segment] = &poly.trait_ref.path.segments[..] {
1600+
let assoc = pprust::path_to_string(&ast::Path::from_ident(potential_assoc.ident));
1601+
let ty = pprust::ty_to_string(&predicate.rhs_ty);
1602+
let (args, span) = match &trait_segment.args {
1603+
Some(args) => match args.deref() {
1604+
ast::GenericArgs::AngleBracketed(args) => {
1605+
let Some(arg) = args.args.last() else {
1606+
return;
1607+
};
1608+
(format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
1609+
}
1610+
_ => return,
1611+
},
1612+
None => (format!("<{assoc} = {ty}>"), trait_segment.span().shrink_to_hi()),
1613+
};
1614+
let removal_span = if generics.where_clause.predicates.len() == 1 {
1615+
// We're removing th eonly where bound left, remove the whole thing.
1616+
generics.where_clause.span
1617+
} else {
1618+
let mut span = predicate.span;
1619+
let mut prev: Option<Span> = None;
1620+
let mut preds = generics.where_clause.predicates.iter().peekable();
1621+
// Find the predicate that shouldn't have been in the where bound list.
1622+
while let Some(pred) = preds.next() {
1623+
if let WherePredicate::EqPredicate(pred) = pred
1624+
&& pred.span == predicate.span
16041625
{
1605-
if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
1606-
let assoc = pprust::path_to_string(&ast::Path::from_ident(
1607-
potential_assoc.ident,
1608-
));
1609-
let ty = pprust::ty_to_string(&predicate.rhs_ty);
1610-
let (args, span) = match &trait_segment.args {
1611-
Some(args) => match args.deref() {
1612-
ast::GenericArgs::AngleBracketed(args) => {
1613-
let Some(arg) = args.args.last() else {
1614-
continue;
1615-
};
1616-
(format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
1617-
}
1618-
_ => continue,
1619-
},
1620-
None => (
1621-
format!("<{assoc} = {ty}>"),
1622-
trait_segment.span().shrink_to_hi(),
1623-
),
1624-
};
1625-
err.assoc2 = Some(errors::AssociatedSuggestion2 {
1626-
span,
1627-
args,
1628-
predicate: predicate.span,
1629-
trait_segment: trait_segment.ident,
1630-
potential_assoc: potential_assoc.ident,
1631-
});
1626+
if let Some(next) = preds.peek() {
1627+
// This is the first predicate, remove the trailing comma as well.
1628+
span = span.with_hi(next.span().lo());
1629+
} else if let Some(prev) = prev {
1630+
// Remove the previous comma as well.
1631+
span = span.with_lo(prev.hi());
16321632
}
16331633
}
1634+
prev = Some(pred.span());
1635+
}
1636+
span
1637+
};
1638+
err.assoc2 = Some(errors::AssociatedSuggestion2 {
1639+
span,
1640+
args,
1641+
predicate: removal_span,
1642+
trait_segment: trait_segment.ident,
1643+
potential_assoc: potential_assoc.ident,
1644+
});
1645+
}
1646+
};
1647+
1648+
if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
1649+
// Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1650+
for bounds in generics.params.iter().map(|p| &p.bounds).chain(
1651+
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
1652+
WherePredicate::BoundPredicate(p) => Some(&p.bounds),
1653+
_ => None,
1654+
}),
1655+
) {
1656+
for bound in bounds {
1657+
if let GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound {
1658+
if full_path.segments[..full_path.segments.len() - 1]
1659+
.iter()
1660+
.map(|segment| segment.ident.name)
1661+
.zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name))
1662+
.all(|(a, b)| a == b)
1663+
&& let Some(potential_assoc) = full_path.segments.iter().last()
1664+
{
1665+
suggest(poly, potential_assoc, predicate);
1666+
}
1667+
}
1668+
}
1669+
}
1670+
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1671+
if let [potential_param, potential_assoc] = &full_path.segments[..] {
1672+
for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain(
1673+
generics.where_clause.predicates.iter().filter_map(|pred| match pred {
1674+
WherePredicate::BoundPredicate(p)
1675+
if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind
1676+
&& let [segment] = &path.segments[..] =>
1677+
{
1678+
Some((segment.ident, &p.bounds))
1679+
}
1680+
_ => None,
1681+
}),
1682+
) {
1683+
if ident == potential_param.ident {
1684+
for bound in bounds {
1685+
if let ast::GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound {
1686+
suggest(poly, potential_assoc, predicate);
1687+
}
16341688
}
16351689
}
16361690
}

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

+67
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,71 @@ 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 where T: IntoIterator, IntoIterator::Item = A,
21+
//~^ ERROR equality constraints are not yet supported in `where` clauses
22+
//~| ERROR cannot find type `A` in this scope
23+
{
24+
todo!()
25+
}
26+
}
27+
28+
struct Y {}
29+
30+
impl FromIterator<bool> for Y {
31+
fn from_iter<T>(_: T) -> Self where T: IntoIterator, T::Item = A,
32+
//~^ ERROR equality constraints are not yet supported in `where` clauses
33+
//~| ERROR cannot find type `A` in this scope
34+
{
35+
todo!()
36+
}
37+
}
38+
39+
struct Z {}
40+
41+
impl FromIterator<bool> for Z {
42+
fn from_iter<T: IntoIterator>(_: T) -> Self where IntoIterator::Item = A,
43+
//~^ ERROR equality constraints are not yet supported in `where` clauses
44+
//~| ERROR cannot find type `A` in this scope
45+
{
46+
todo!()
47+
}
48+
}
49+
50+
struct K {}
51+
52+
impl FromIterator<bool> for K {
53+
fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = A,
54+
//~^ ERROR equality constraints are not yet supported in `where` clauses
55+
//~| ERROR cannot find type `A` in this scope
56+
{
57+
todo!()
58+
}
59+
}
60+
61+
struct L {}
62+
63+
impl FromIterator<bool> for L {
64+
fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
65+
//~^ ERROR equality constraints are not yet supported in `where` clauses
66+
//~| ERROR cannot find type `A` in this scope
67+
{
68+
todo!()
69+
}
70+
}
71+
72+
struct M {}
73+
74+
impl FromIterator<bool> for M {
75+
fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
76+
//~^ ERROR equality constraints are not yet supported in `where` clauses
77+
//~| ERROR cannot find type `A` in this scope
78+
{
79+
todo!()
80+
}
81+
}
1582
fn main() {}

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

+137-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
88
help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
99
|
1010
LL - fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
11-
LL + fn sum<I: Iterator<Item = (), Item = i32>>(i: I) -> i32 where {
11+
LL + fn sum<I: Iterator<Item = (), Item = i32>>(i: I) -> i32 {
1212
|
1313

1414
error: equality constraints are not yet supported in `where` clauses
@@ -21,7 +21,7 @@ LL | fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
2121
help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
2222
|
2323
LL - fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
24-
LL + fn sum2<I: Iterator<Item = i32>>(i: I) -> i32 where {
24+
LL + fn sum2<I: Iterator<Item = i32>>(i: I) -> i32 {
2525
|
2626

2727
error: equality constraints are not yet supported in `where` clauses
@@ -32,6 +32,138 @@ 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:20:58
37+
|
38+
LL | fn from_iter<T>(_: T) -> Self where T: IntoIterator, 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 - fn from_iter<T>(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A,
45+
LL + fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
46+
|
47+
48+
error: equality constraints are not yet supported in `where` clauses
49+
--> $DIR/equality-bound.rs:31:58
50+
|
51+
LL | fn from_iter<T>(_: T) -> Self where T: IntoIterator, 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 - fn from_iter<T>(_: T) -> Self where T: IntoIterator, T::Item = A,
58+
LL + fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
59+
|
60+
61+
error: equality constraints are not yet supported in `where` clauses
62+
--> $DIR/equality-bound.rs:42:55
63+
|
64+
LL | fn from_iter<T: IntoIterator>(_: T) -> Self where 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>(_: T) -> Self where IntoIterator::Item = A,
71+
LL + fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self
72+
|
73+
74+
error: equality constraints are not yet supported in `where` clauses
75+
--> $DIR/equality-bound.rs:53:55
76+
|
77+
LL | fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = A,
78+
| ^^^^^^^^^^^ not supported
79+
|
80+
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
81+
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
82+
|
83+
LL - fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = A,
84+
LL + fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self
85+
|
86+
87+
error: equality constraints are not yet supported in `where` clauses
88+
--> $DIR/equality-bound.rs:64:41
89+
|
90+
LL | fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
91+
| ^^^^^^^^^^^^^^^^^^^^^^ not supported
92+
|
93+
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
94+
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
95+
|
96+
LL - fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
97+
LL + fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
98+
|
99+
100+
error: equality constraints are not yet supported in `where` clauses
101+
--> $DIR/equality-bound.rs:75:41
102+
|
103+
LL | fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
104+
| ^^^^^^^^^^^ not supported
105+
|
106+
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
107+
help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax
108+
|
109+
LL - fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
110+
LL + fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
111+
|
112+
113+
error[E0412]: cannot find type `A` in this scope
114+
--> $DIR/equality-bound.rs:20:79
115+
|
116+
LL | fn from_iter<T>(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A,
117+
| ^ help: a struct with a similar name exists: `K`
118+
...
119+
LL | struct K {}
120+
| -------- similarly named struct `K` defined here
121+
122+
error[E0412]: cannot find type `A` in this scope
123+
--> $DIR/equality-bound.rs:31:68
124+
|
125+
LL | fn from_iter<T>(_: T) -> Self where T: IntoIterator, T::Item = A,
126+
| ^ help: a struct with a similar name exists: `K`
127+
...
128+
LL | struct K {}
129+
| -------- similarly named struct `K` defined here
130+
131+
error[E0412]: cannot find type `A` in this scope
132+
--> $DIR/equality-bound.rs:42:76
133+
|
134+
LL | fn from_iter<T: IntoIterator>(_: T) -> Self where IntoIterator::Item = A,
135+
| ^ help: a struct with a similar name exists: `K`
136+
...
137+
LL | struct K {}
138+
| -------- similarly named struct `K` defined here
139+
140+
error[E0412]: cannot find type `A` in this scope
141+
--> $DIR/equality-bound.rs:53:65
142+
|
143+
LL | struct K {}
144+
| -------- similarly named struct `K` defined here
145+
...
146+
LL | fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = A,
147+
| ^ help: a struct with a similar name exists: `K`
148+
149+
error[E0412]: cannot find type `A` in this scope
150+
--> $DIR/equality-bound.rs:64:62
151+
|
152+
LL | struct K {}
153+
| -------- similarly named struct `K` defined here
154+
...
155+
LL | fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
156+
| ^ help: a struct with a similar name exists: `K`
157+
158+
error[E0412]: cannot find type `A` in this scope
159+
--> $DIR/equality-bound.rs:75:51
160+
|
161+
LL | struct K {}
162+
| -------- similarly named struct `K` defined here
163+
...
164+
LL | fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
165+
| ^ help: a struct with a similar name exists: `K`
166+
35167
error[E0433]: failed to resolve: use of undeclared type `I`
36168
--> $DIR/equality-bound.rs:9:41
37169
|
@@ -41,6 +173,7 @@ LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
41173
| use of undeclared type `I`
42174
| help: a type parameter with a similar name exists: `J`
43175

44-
error: aborting due to 4 previous errors
176+
error: aborting due to 16 previous errors
45177

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

0 commit comments

Comments
 (0)