about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-10-10 23:27:28 +0000
committerbors <bors@rust-lang.org>2020-10-10 23:27:28 +0000
commit08764ad1638d49ee8303a8e5b1a9e439cbbc87f6 (patch)
tree770af02a1069537634eb478c8af07cccf9c9f755 /src
parentb1af43bc63bc7417938df056f7f25d456cc11b0e (diff)
parent4ae8f6ec7c75b3098ee3f8897254f5b8d12d75dc (diff)
downloadrust-08764ad1638d49ee8303a8e5b1a9e439cbbc87f6.tar.gz
rust-08764ad1638d49ee8303a8e5b1a9e439cbbc87f6.zip
Auto merge of #77087 - estebank:issue-45817, r=matthewjasper
Provide structured suggestions when finding structs when expecting a trait

When finding an ADT in a trait object definition provide some solutions. Fix #45817.
Given `<Param as Trait>::Assoc: Ty` suggest `Param: Trait<Assoc = Ty>`. Fix #75829.
Diffstat (limited to 'src')
-rw-r--r--src/test/ui/traits/assoc_type_bound_with_struct.rs19
-rw-r--r--src/test/ui/traits/assoc_type_bound_with_struct.stderr83
-rw-r--r--src/test/ui/traits/trait-bounds-not-on-struct.rs33
-rw-r--r--src/test/ui/traits/trait-bounds-not-on-struct.stderr165
4 files changed, 292 insertions, 8 deletions
diff --git a/src/test/ui/traits/assoc_type_bound_with_struct.rs b/src/test/ui/traits/assoc_type_bound_with_struct.rs
new file mode 100644
index 00000000000..c66009fe24c
--- /dev/null
+++ b/src/test/ui/traits/assoc_type_bound_with_struct.rs
@@ -0,0 +1,19 @@
+trait Bar {
+    type Baz;
+}
+
+struct Foo<T> where T: Bar, <T as Bar>::Baz: String { //~ ERROR expected trait, found struct
+    t: T,
+}
+
+struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String { //~ ERROR expected trait, found struct
+    t: &'a T,
+}
+
+fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String { //~ ERROR expected trait, found struct
+}
+
+fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { //~ ERROR expected trait, found
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/assoc_type_bound_with_struct.stderr b/src/test/ui/traits/assoc_type_bound_with_struct.stderr
new file mode 100644
index 00000000000..7cf872eb6ac
--- /dev/null
+++ b/src/test/ui/traits/assoc_type_bound_with_struct.stderr
@@ -0,0 +1,83 @@
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:5:46
+   |
+LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: String {
+   |                                              ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | struct Foo<T> where T: Bar, T: Bar<Baz = String> {
+   |                             ^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: ToString {
+   |                                              ^^^^^^^^
+
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:9:54
+   |
+LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String {
+   |                                                      ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | struct Qux<'a, T> where T: Bar, &'a T: Bar<Baz = String> {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: ToString {
+   |                                                      ^^^^^^^^
+
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:13:45
+   |
+LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String {
+   |                                             ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | fn foo<T: Bar>(_: T) where T: Bar<Baz = String> {
+   |                            ^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: ToString {
+   |                                             ^^^^^^^^
+
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:16:57
+   |
+LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String {
+   |                                                         ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | fn qux<'a, T: Bar>(_: &'a T) where &'a T: Bar<Baz = String> {
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: ToString {
+   |                                                         ^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0404`.
diff --git a/src/test/ui/traits/trait-bounds-not-on-struct.rs b/src/test/ui/traits/trait-bounds-not-on-struct.rs
index c6e93e75525..8633e9d7a4c 100644
--- a/src/test/ui/traits/trait-bounds-not-on-struct.rs
+++ b/src/test/ui/traits/trait-bounds-not-on-struct.rs
@@ -1,9 +1,38 @@
+// We don't need those errors. Ideally we would silence them, but to do so we need to move the
+// lint from being an early-lint during parsing to a late-lint, because it needs to be aware of
+// the types involved.
 #![allow(bare_trait_objects)]
 
 struct Foo;
 
 fn foo(_x: Box<Foo + Send>) { } //~ ERROR expected trait, found struct `Foo`
 
-type A<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
+type TypeAlias<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
 
-fn main() { }
+struct A;
+fn a() -> A + 'static { //~ ERROR expected trait, found
+    A
+}
+fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) { //~ ERROR expected trait, found
+    panic!()
+}
+fn c() -> 'static + A { //~ ERROR expected trait, found
+    A
+}
+fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) { //~ ERROR expected trait, found
+    panic!()
+}
+fn e() -> 'static + A + 'static { //~ ERROR expected trait, found
+//~^ ERROR only a single explicit lifetime bound is permitted
+    A
+}
+fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) { //~ ERROR expected trait, found
+//~^ ERROR only a single explicit lifetime bound is permitted
+    panic!()
+}
+struct Traitor;
+trait Trait {}
+fn g() -> Traitor + 'static { //~ ERROR expected trait, found struct `Traitor`
+    A
+}
+fn main() {}
diff --git a/src/test/ui/traits/trait-bounds-not-on-struct.stderr b/src/test/ui/traits/trait-bounds-not-on-struct.stderr
index a649a4eee55..0f97e3bdf18 100644
--- a/src/test/ui/traits/trait-bounds-not-on-struct.stderr
+++ b/src/test/ui/traits/trait-bounds-not-on-struct.stderr
@@ -1,15 +1,168 @@
+error[E0226]: only a single explicit lifetime bound is permitted
+  --> $DIR/trait-bounds-not-on-struct.rs:25:25
+   |
+LL | fn e() -> 'static + A + 'static {
+   |                         ^^^^^^^
+
+error[E0226]: only a single explicit lifetime bound is permitted
+  --> $DIR/trait-bounds-not-on-struct.rs:29:53
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
+   |                                                     ^^
+
 error[E0404]: expected trait, found struct `Foo`
-  --> $DIR/trait-bounds-not-on-struct.rs:5:16
+  --> $DIR/trait-bounds-not-on-struct.rs:8:16
    |
 LL | fn foo(_x: Box<Foo + Send>) { }
    |                ^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:8:22
+   |
+LL | fn foo(_x: Box<Foo + Send>) { }
+   |                ---   ^^^^ ...because of this bound
+   |                |
+   |                expected this type to be a trait...
 
 error[E0404]: expected trait, found struct `Vec`
-  --> $DIR/trait-bounds-not-on-struct.rs:7:21
+  --> $DIR/trait-bounds-not-on-struct.rs:10:29
+   |
+LL | type TypeAlias<T> = Box<dyn Vec<T>>;
+   |                             ^^^^^^ not a trait
+
+error[E0404]: expected trait, found struct `A`
+  --> $DIR/trait-bounds-not-on-struct.rs:13:11
+   |
+LL | fn a() -> A + 'static {
+   |           ^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:13:15
+   |
+LL | fn a() -> A + 'static {
+   |           -   ^^^^^^^ ...because of this bound
+   |           |
+   |           expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn a() -> A {
+   |           --
+
+error[E0404]: expected trait, found enum `Result`
+  --> $DIR/trait-bounds-not-on-struct.rs:16:34
+   |
+LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) {
+   |                                  ^^^^^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:16:48
+   |
+LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) {
+   |                                  -----------   ^^ ...because of this bound
+   |                                  |
+   |                                  expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
+   |                                            --
+
+error[E0404]: expected trait, found struct `A`
+  --> $DIR/trait-bounds-not-on-struct.rs:19:21
+   |
+LL | fn c() -> 'static + A {
+   |                     ^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:19:11
+   |
+LL | fn c() -> 'static + A {
+   |           ^^^^^^^   - expected this type to be a trait...
+   |           |
+   |           ...because of this bound
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn c() -> A {
+   |          --
+
+error[E0404]: expected trait, found enum `Result`
+  --> $DIR/trait-bounds-not-on-struct.rs:22:39
+   |
+LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) {
+   |                                       ^^^^^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:22:34
+   |
+LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) {
+   |                                  ^^   ----------- expected this type to be a trait...
+   |                                  |
+   |                                  ...because of this bound
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn d<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
+   |                                 --
+
+error[E0404]: expected trait, found struct `A`
+  --> $DIR/trait-bounds-not-on-struct.rs:25:21
+   |
+LL | fn e() -> 'static + A + 'static {
+   |                     ^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:25:11
+   |
+LL | fn e() -> 'static + A + 'static {
+   |           ^^^^^^^   -   ^^^^^^^ ...because of these bounds
+   |                     |
+   |                     expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn e() -> A {
+   |          ---
+
+error[E0404]: expected trait, found enum `Result`
+  --> $DIR/trait-bounds-not-on-struct.rs:29:39
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
+   |                                       ^^^^^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:29:34
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
+   |                                  ^^   -----------   ^^ ...because of these bounds
+   |                                       |
+   |                                       expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
+   |                                 --         --
+
+error[E0404]: expected trait, found struct `Traitor`
+  --> $DIR/trait-bounds-not-on-struct.rs:35:11
+   |
+LL | trait Trait {}
+   | ----------- similarly named trait `Trait` defined here
+LL | fn g() -> Traitor + 'static {
+   |           ^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:35:21
+   |
+LL | fn g() -> Traitor + 'static {
+   |           -------   ^^^^^^^ ...because of this bound
+   |           |
+   |           expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn g() -> Traitor {
+   |                 --
+help: a trait with a similar name exists
    |
-LL | type A<T> = Box<dyn Vec<T>>;
-   |                     ^^^^^^ not a trait
+LL | fn g() -> Trait + 'static {
+   |           ^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 11 previous errors
 
-For more information about this error, try `rustc --explain E0404`.
+Some errors have detailed explanations: E0226, E0404.
+For more information about an error, try `rustc --explain E0226`.