about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-02-08 00:26:42 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-02-08 00:26:42 +0000
commit535c64336d6dcd588dd794d526047a4425e6e402 (patch)
tree43de1a62b3a8d0c7860959b2e6b62066ed83ef00
parent0c1b2731f8aabf994c3fffce16182404081c8f2c (diff)
downloadrust-535c64336d6dcd588dd794d526047a4425e6e402.tar.gz
rust-535c64336d6dcd588dd794d526047a4425e6e402.zip
Do not leave stray commas after applying suggestion
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs117
-rw-r--r--tests/ui/generic-associated-types/equality-bound.rs39
-rw-r--r--tests/ui/generic-associated-types/equality-bound.stderr116
3 files changed, 160 insertions, 112 deletions
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index ec54f1032c3..356b578d518 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1593,6 +1593,58 @@ fn deny_equality_constraints(
             }
         }
     }
+
+    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 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(
@@ -1608,37 +1660,9 @@ fn deny_equality_constraints(
                         .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()
                     {
-                        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,
-                            });
-                        }
+                        suggest(poly, potential_assoc, predicate);
                     }
                 }
             }
@@ -1658,37 +1682,8 @@ fn deny_equality_constraints(
             ) {
                 if ident == potential_param.ident {
                     for bound in bounds {
-                        if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) =
-                            bound
-                        {
-                            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 ast::GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound {
+                            suggest(poly, potential_assoc, predicate);
                         }
                     }
                 }
diff --git a/tests/ui/generic-associated-types/equality-bound.rs b/tests/ui/generic-associated-types/equality-bound.rs
index 63bb5dd3567..be05181f5d0 100644
--- a/tests/ui/generic-associated-types/equality-bound.rs
+++ b/tests/ui/generic-associated-types/equality-bound.rs
@@ -17,10 +17,7 @@ use std::iter::FromIterator;
 struct X {}
 
 impl FromIterator<bool> for X {
-    fn from_iter<T>(_: T) -> Self
-    where
-        T: IntoIterator,
-        IntoIterator::Item = A,
+    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
     {
@@ -31,10 +28,7 @@ impl FromIterator<bool> for X {
 struct Y {}
 
 impl FromIterator<bool> for Y {
-    fn from_iter<T>(_: T) -> Self
-    where
-        T: IntoIterator,
-        T::Item = A,
+    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
     {
@@ -45,9 +39,7 @@ impl FromIterator<bool> for Y {
 struct Z {}
 
 impl FromIterator<bool> for Z {
-    fn from_iter<T: IntoIterator>(_: T) -> Self
-    where
-        IntoIterator::Item = A,
+    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
     {
@@ -58,9 +50,7 @@ impl FromIterator<bool> for Z {
 struct K {}
 
 impl FromIterator<bool> for K {
-    fn from_iter<T: IntoIterator>(_: T) -> Self
-    where
-        T::Item = A,
+    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
     {
@@ -68,4 +58,25 @@ impl FromIterator<bool> for K {
     }
 }
 
+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() {}
diff --git a/tests/ui/generic-associated-types/equality-bound.stderr b/tests/ui/generic-associated-types/equality-bound.stderr
index 8e29d9092c5..a054c06caeb 100644
--- a/tests/ui/generic-associated-types/equality-bound.stderr
+++ b/tests/ui/generic-associated-types/equality-bound.stderr
@@ -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
@@ -33,94 +33,136 @@ 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
+  --> $DIR/equality-bound.rs:20:58
    |
-LL |         IntoIterator::Item = A,
-   |         ^^^^^^^^^^^^^^^^^^^^^^ not supported
+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 ~         T: IntoIterator<Item = A>,
-LL ~         ,
+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:37:9
+  --> $DIR/equality-bound.rs:31:58
    |
-LL |         T::Item = A,
-   |         ^^^^^^^^^^^ not supported
+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 ~         T: IntoIterator<Item = A>,
-LL ~         ,
+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:50:9
+  --> $DIR/equality-bound.rs:42:55
    |
-LL |         IntoIterator::Item = A,
-   |         ^^^^^^^^^^^^^^^^^^^^^^ not supported
+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<Item = A>>(_: T) -> Self
-LL |     where
-LL ~         ,
+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:63:9
+  --> $DIR/equality-bound.rs:53:55
    |
-LL |         T::Item = A,
-   |         ^^^^^^^^^^^ not supported
+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<Item = A>>(_: T) -> Self
-LL |     where
-LL ~         ,
+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:23:30
+  --> $DIR/equality-bound.rs:31:68
    |
-LL |         IntoIterator::Item = A,
-   |                              ^ help: a struct with a similar name exists: `K`
+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:37:19
+  --> $DIR/equality-bound.rs:42:76
    |
-LL |         T::Item = A,
-   |                   ^ help: a struct with a similar name exists: `K`
+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:50:30
+  --> $DIR/equality-bound.rs:53:65
    |
-LL |         IntoIterator::Item = A,
-   |                              ^ help: a struct with a similar name exists: `K`
+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:63:19
+  --> $DIR/equality-bound.rs:75:51
    |
 LL | struct K {}
    | -------- similarly named struct `K` defined here
 ...
-LL |         T::Item = A,
-   |                   ^ help: a struct with a similar name exists: `K`
+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
@@ -131,7 +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 12 previous errors
+error: aborting due to 16 previous errors
 
 Some errors have detailed explanations: E0412, E0433.
 For more information about an error, try `rustc --explain E0412`.