mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
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 <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 ~ | 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 ~ | ``` Fix #68982.
This commit is contained in:
commit
1b396913a9
@ -1593,44 +1593,98 @@ 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 {
|
||||
if let [potential_param, potential_assoc] = &full_path.segments[..] {
|
||||
for param in &generics.params {
|
||||
if param.ident == potential_param.ident {
|
||||
for bound in ¶m.bounds {
|
||||
if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) =
|
||||
bound
|
||||
|
||||
let mut suggest =
|
||||
|poly: &PolyTraitRef, potential_assoc: &PathSegment, predicate: &WhereEqPredicate| {
|
||||
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 {
|
||||
return;
|
||||
};
|
||||
(format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
|
||||
}
|
||||
_ => return,
|
||||
},
|
||||
None => (format!("<{assoc} = {ty}>"), trait_segment.span().shrink_to_hi()),
|
||||
};
|
||||
let removal_span = if generics.where_clause.predicates.len() == 1 {
|
||||
// We're removing th eonly where bound left, remove the whole thing.
|
||||
generics.where_clause.span
|
||||
} else {
|
||||
let mut span = predicate.span;
|
||||
let mut prev: Option<Span> = None;
|
||||
let mut preds = generics.where_clause.predicates.iter().peekable();
|
||||
// Find the predicate that shouldn't have been in the where bound list.
|
||||
while let Some(pred) = preds.next() {
|
||||
if let WherePredicate::EqPredicate(pred) = pred
|
||||
&& pred.span == predicate.span
|
||||
{
|
||||
if let [trait_segment] = &trait_ref.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,
|
||||
});
|
||||
if let Some(next) = preds.peek() {
|
||||
// This is the first predicate, remove the trailing comma as well.
|
||||
span = span.with_hi(next.span().lo());
|
||||
} else if let Some(prev) = prev {
|
||||
// Remove the previous comma as well.
|
||||
span = span.with_lo(prev.hi());
|
||||
}
|
||||
}
|
||||
prev = Some(pred.span());
|
||||
}
|
||||
span
|
||||
};
|
||||
err.assoc2 = Some(errors::AssociatedSuggestion2 {
|
||||
span,
|
||||
args,
|
||||
predicate: removal_span,
|
||||
trait_segment: trait_segment.ident,
|
||||
potential_assoc: potential_assoc.ident,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
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 Some(potential_assoc) = full_path.segments.iter().last()
|
||||
{
|
||||
suggest(poly, potential_assoc, predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
|
||||
if let [potential_param, potential_assoc] = &full_path.segments[..] {
|
||||
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(poly, TraitBoundModifiers::NONE) = bound {
|
||||
suggest(poly, potential_assoc, predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,4 +12,71 @@ 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!()
|
||||
}
|
||||
}
|
||||
|
||||
struct L {}
|
||||
|
||||
impl FromIterator<bool> for L {
|
||||
fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
|
||||
//~^ ERROR equality constraints are not yet supported in `where` clauses
|
||||
//~| ERROR cannot find type `A` in this scope
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
struct M {}
|
||||
|
||||
impl FromIterator<bool> for M {
|
||||
fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
|
||||
//~^ ERROR equality constraints are not yet supported in `where` clauses
|
||||
//~| ERROR cannot find type `A` in this scope
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
fn main() {}
|
||||
|
@ -8,7 +8,7 @@ LL | fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
|
||||
help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
|
||||
|
|
||||
LL - fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
|
||||
LL + fn sum<I: Iterator<Item = (), Item = i32>>(i: I) -> i32 where {
|
||||
LL + fn sum<I: Iterator<Item = (), Item = i32>>(i: I) -> i32 {
|
||||
|
|
||||
|
||||
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 {
|
||||
help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
|
||||
|
|
||||
LL - fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
|
||||
LL + fn sum2<I: Iterator<Item = i32>>(i: I) -> i32 where {
|
||||
LL + fn sum2<I: Iterator<Item = i32>>(i: I) -> i32 {
|
||||
|
|
||||
|
||||
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 {
|
||||
|
|
||||
= 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:20:58
|
||||
|
|
||||
LL | fn from_iter<T>(_: T) -> Self where T: IntoIterator, 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>(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A,
|
||||
LL + fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
|
||||
|
|
||||
|
||||
error: equality constraints are not yet supported in `where` clauses
|
||||
--> $DIR/equality-bound.rs:31:58
|
||||
|
|
||||
LL | fn from_iter<T>(_: T) -> Self where T: IntoIterator, 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>(_: T) -> Self where T: IntoIterator, T::Item = A,
|
||||
LL + fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
|
||||
|
|
||||
|
||||
error: equality constraints are not yet supported in `where` clauses
|
||||
--> $DIR/equality-bound.rs:42:55
|
||||
|
|
||||
LL | fn from_iter<T: IntoIterator>(_: T) -> Self where 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>(_: T) -> Self where IntoIterator::Item = A,
|
||||
LL + fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self
|
||||
|
|
||||
|
||||
error: equality constraints are not yet supported in `where` clauses
|
||||
--> $DIR/equality-bound.rs:53:55
|
||||
|
|
||||
LL | fn from_iter<T: IntoIterator>(_: T) -> Self where 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>(_: T) -> Self where T::Item = A,
|
||||
LL + fn from_iter<T: IntoIterator<Item = A>>(_: T) -> Self
|
||||
|
|
||||
|
||||
error: equality constraints are not yet supported in `where` clauses
|
||||
--> $DIR/equality-bound.rs:64:41
|
||||
|
|
||||
LL | fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ 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>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
|
||||
LL + fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
|
||||
|
|
||||
|
||||
error: equality constraints are not yet supported in `where` clauses
|
||||
--> $DIR/equality-bound.rs:75:41
|
||||
|
|
||||
LL | fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
|
||||
| ^^^^^^^^^^^ 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>(_: T) -> Self where T::Item = A, T: IntoIterator,
|
||||
LL + fn from_iter<T>(_: T) -> Self where T: IntoIterator<Item = A>,
|
||||
|
|
||||
|
||||
error[E0412]: cannot find type `A` in this scope
|
||||
--> $DIR/equality-bound.rs:20:79
|
||||
|
|
||||
LL | fn from_iter<T>(_: T) -> Self where T: IntoIterator, 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:31:68
|
||||
|
|
||||
LL | fn from_iter<T>(_: T) -> Self where T: IntoIterator, 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:42:76
|
||||
|
|
||||
LL | fn from_iter<T: IntoIterator>(_: T) -> Self where 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:53:65
|
||||
|
|
||||
LL | struct K {}
|
||||
| -------- similarly named struct `K` defined here
|
||||
...
|
||||
LL | fn from_iter<T: IntoIterator>(_: T) -> Self where T::Item = A,
|
||||
| ^ help: a struct with a similar name exists: `K`
|
||||
|
||||
error[E0412]: cannot find type `A` in this scope
|
||||
--> $DIR/equality-bound.rs:64:62
|
||||
|
|
||||
LL | struct K {}
|
||||
| -------- similarly named struct `K` defined here
|
||||
...
|
||||
LL | fn from_iter<T>(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator,
|
||||
| ^ help: a struct with a similar name exists: `K`
|
||||
|
||||
error[E0412]: cannot find type `A` in this scope
|
||||
--> $DIR/equality-bound.rs:75:51
|
||||
|
|
||||
LL | struct K {}
|
||||
| -------- similarly named struct `K` defined here
|
||||
...
|
||||
LL | fn from_iter<T>(_: T) -> Self where T::Item = A, T: IntoIterator,
|
||||
| ^ 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 +173,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 16 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`.
|
||||
|
Loading…
Reference in New Issue
Block a user