From 0c1b2731f8aabf994c3fffce16182404081c8f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 7 Feb 2024 20:01:09 +0000 Subject: [PATCH] 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 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) -> 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 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) -> Self LL | where LL ~ | ``` Fix #68982. --- .../rustc_ast_passes/src/ast_validation.rs | 67 ++++++++++++- .../equality-bound.rs | 56 +++++++++++ .../equality-bound.stderr | 95 ++++++++++++++++++- 3 files changed, 212 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 9ea5d1ed5fa..ec54f1032c3 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1593,12 +1593,71 @@ fn deny_equality_constraints( } } } - // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo`. if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind { + // Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo`. + 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`. 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 { + 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 { diff --git a/tests/ui/generic-associated-types/equality-bound.rs b/tests/ui/generic-associated-types/equality-bound.rs index fcc2da8014f..63bb5dd3567 100644 --- a/tests/ui/generic-associated-types/equality-bound.rs +++ b/tests/ui/generic-associated-types/equality-bound.rs @@ -12,4 +12,60 @@ fn sum3(i: J) -> i32 where I::Item = i32 { panic!() } +use std::iter::FromIterator; + +struct X {} + +impl FromIterator for X { + fn from_iter(_: 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 for Y { + fn from_iter(_: 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 for Z { + fn from_iter(_: 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 for K { + fn from_iter(_: 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() {} diff --git a/tests/ui/generic-associated-types/equality-bound.stderr b/tests/ui/generic-associated-types/equality-bound.stderr index b21ff30a27d..8e29d9092c5 100644 --- a/tests/ui/generic-associated-types/equality-bound.stderr +++ b/tests/ui/generic-associated-types/equality-bound.stderr @@ -32,6 +32,96 @@ LL | fn sum3(i: J) -> i32 where I::Item = i32 { | = note: see issue #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 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, +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 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, +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 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) -> 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 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) -> 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(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`.