about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-10-09 15:07:22 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-10-15 13:55:44 -0700
commit5cc99eed04005108797fbba82eaf8ef7918051db (patch)
treee62d586e89316a4253ed97bddcefadf27f0e6ab5
parentdaa8491648d742085bf071169624d99d542a044f (diff)
downloadrust-5cc99eed04005108797fbba82eaf8ef7918051db.tar.gz
rust-5cc99eed04005108797fbba82eaf8ef7918051db.zip
Handle missing projection restriction
-rw-r--r--src/librustc/traits/error_reporting.rs49
-rw-r--r--src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr18
-rw-r--r--src/test/ui/associated-types/associated-types-bound-failure.fixed29
-rw-r--r--src/test/ui/associated-types/associated-types-bound-failure.rs2
-rw-r--r--src/test/ui/associated-types/associated-types-bound-failure.stderr7
-rw-r--r--src/test/ui/associated-types/associated-types-unsized.fixed14
-rw-r--r--src/test/ui/associated-types/associated-types-unsized.rs3
-rw-r--r--src/test/ui/associated-types/associated-types-unsized.stderr5
-rw-r--r--src/test/ui/issues/issue-22872.stderr3
-rw-r--r--src/test/ui/issues/issue-42312.stderr5
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed17
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs2
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr5
13 files changed, 134 insertions, 25 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 77d4e10d4f4..2ac691b47ac 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -975,11 +975,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             trait_ref.self_ty(),
             trait_ref.self_ty().kind,
         );
-        let param_ty = if let ty::Param(param_ty) = &trait_ref.self_ty().kind {
-            param_ty
-        } else {
-            err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate()));
-            return;
+        let (param_ty, projection) = match &trait_ref.self_ty().kind {
+            ty::Param(param_ty) => (Some(param_ty), None),
+            ty::Projection(projection) => (None, Some(projection)),
+            _ => {
+                err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate()));
+                return;
+            }
         };
 
         let mut hir_id = body_id;
@@ -996,7 +998,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 hir::Node::ImplItem(hir::ImplItem {
                     generics,
                     kind: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, _), ..
-                }) if param_ty.name.as_str() == "Self" => {
+                }) if param_ty.map(|p| p.name.as_str() == "Self").unwrap_or(false) => {
                     if !generics.where_clause.predicates.is_empty() {
                         err.span_suggestion(
                             generics.where_clause.span().unwrap().shrink_to_hi(),
@@ -1014,6 +1016,34 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     }
                     return;
                 }
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Fn(decl, _, generics, _), ..
+                }) |
+                hir::Node::TraitItem(hir::TraitItem {
+                    generics,
+                    kind: hir::TraitItemKind::Method(hir::MethodSig { decl, .. }, _), ..
+                }) |
+                hir::Node::ImplItem(hir::ImplItem {
+                    generics,
+                    kind: hir::ImplItemKind::Method(hir::MethodSig { decl, .. }, _), ..
+                }) if projection.is_some() => {
+                    if !generics.where_clause.predicates.is_empty() {
+                        err.span_suggestion(
+                            generics.where_clause.span().unwrap().shrink_to_hi(),
+                            "consider further restricting the associated type",
+                            format!(", {}", trait_ref.to_predicate()),
+                            Applicability::MachineApplicable,
+                        );
+                    } else {
+                        err.span_suggestion(
+                            decl.output.span().shrink_to_hi(),
+                            "consider further restricting the associated type",
+                            format!(" where {}", trait_ref.to_predicate()),
+                            Applicability::MachineApplicable,
+                        );
+                    }
+                    return;
+                }
                 hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(_, generics), span, .. }) |
                 hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics), span, .. }) |
                 hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(_, generics), span, .. }) |
@@ -1036,9 +1066,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), span, ..
                 }) |
                 hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) |
-                hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) => {
+                hir::Node::ImplItem(hir::ImplItem { generics, span, .. })
+                if param_ty.is_some() => {
                     let restrict_msg = "consider further restricting this bound";
-                    let param_name = param_ty.name.as_str();
+                    let param_name = param_ty.unwrap().name.as_str();
                     for param in &generics.params {
                         if param_name == param.name.ident().as_str() {
                             if param_name.starts_with("impl ") {
@@ -1064,7 +1095,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                         generics.where_clause.span().unwrap().shrink_to_hi(),
                                         &format!(
                                             "consider further restricting type parameter `{}`",
-                                            param_ty,
+                                            param_name,
                                         ),
                                         format!(", {}", trait_ref.to_predicate()),
                                         Applicability::MachineApplicable,
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
index 06e8230aa15..1795fb5aceb 100644
--- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
@@ -9,7 +9,10 @@ LL | impl Case1 for S1 {
 error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
    |
-LL | / fn assume_case1<T: Case1>() {
+LL |   fn assume_case1<T: Case1>() {
+   |   ^                           - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator`
+   |  _|
+   | |
 LL | |
 LL | |
 LL | |
@@ -19,7 +22,6 @@ LL | | }
    | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
-   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator` bound
 
 error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
@@ -27,7 +29,10 @@ error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent be
 LL |   trait Case1 {
    |   ----------- required by `Case1`
 ...
-LL | / fn assume_case1<T: Case1>() {
+LL |   fn assume_case1<T: Case1>() {
+   |   ^                           - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send`
+   |  _|
+   | |
 LL | |
 LL | |
 LL | |
@@ -37,7 +42,6 @@ LL | | }
    | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
-   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send` bound
 
 error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
@@ -45,7 +49,10 @@ error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared
 LL |   trait Case1 {
    |   ----------- required by `Case1`
 ...
-LL | / fn assume_case1<T: Case1>() {
+LL |   fn assume_case1<T: Case1>() {
+   |   ^                           - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync`
+   |  _|
+   | |
 LL | |
 LL | |
 LL | |
@@ -55,7 +62,6 @@ LL | | }
    | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
-   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync` bound
 
 error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
diff --git a/src/test/ui/associated-types/associated-types-bound-failure.fixed b/src/test/ui/associated-types/associated-types-bound-failure.fixed
new file mode 100644
index 00000000000..68ee38d16b3
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-bound-failure.fixed
@@ -0,0 +1,29 @@
+// run-rustfix
+// Test equality constraints on associated types in a where clause.
+#![allow(dead_code)]
+
+pub trait ToInt {
+    fn to_int(&self) -> isize;
+}
+
+pub trait GetToInt
+{
+    type R;
+
+    fn get(&self) -> <Self as GetToInt>::R;
+}
+
+fn foo<G>(g: G) -> isize
+    where G : GetToInt, <G as GetToInt>::R: ToInt
+{
+    ToInt::to_int(&g.get()) //~ ERROR E0277
+}
+
+fn bar<G : GetToInt>(g: G) -> isize
+    where G::R : ToInt
+{
+    ToInt::to_int(&g.get()) // OK
+}
+
+pub fn main() {
+}
diff --git a/src/test/ui/associated-types/associated-types-bound-failure.rs b/src/test/ui/associated-types/associated-types-bound-failure.rs
index 883ac363b44..31e073cc7a8 100644
--- a/src/test/ui/associated-types/associated-types-bound-failure.rs
+++ b/src/test/ui/associated-types/associated-types-bound-failure.rs
@@ -1,4 +1,6 @@
+// run-rustfix
 // Test equality constraints on associated types in a where clause.
+#![allow(dead_code)]
 
 pub trait ToInt {
     fn to_int(&self) -> isize;
diff --git a/src/test/ui/associated-types/associated-types-bound-failure.stderr b/src/test/ui/associated-types/associated-types-bound-failure.stderr
index 85acf134d51..c420c86a275 100644
--- a/src/test/ui/associated-types/associated-types-bound-failure.stderr
+++ b/src/test/ui/associated-types/associated-types-bound-failure.stderr
@@ -1,13 +1,14 @@
 error[E0277]: the trait bound `<G as GetToInt>::R: ToInt` is not satisfied
-  --> $DIR/associated-types-bound-failure.rs:17:19
+  --> $DIR/associated-types-bound-failure.rs:19:19
    |
 LL |     fn to_int(&self) -> isize;
    |     -------------------------- required by `ToInt::to_int`
 ...
+LL |     where G : GetToInt
+   |                       - help: consider further restricting the associated type: `, <G as GetToInt>::R: ToInt`
+LL | {
 LL |     ToInt::to_int(&g.get())
    |                   ^^^^^^^^ the trait `ToInt` is not implemented for `<G as GetToInt>::R`
-   |
-   = help: consider adding a `where <G as GetToInt>::R: ToInt` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-unsized.fixed b/src/test/ui/associated-types/associated-types-unsized.fixed
new file mode 100644
index 00000000000..385de541e56
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-unsized.fixed
@@ -0,0 +1,14 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
+trait Get {
+    type Value: ?Sized;
+    fn get(&self) -> <Self as Get>::Value;
+}
+
+fn foo<T:Get>(t: T)  where <T as Get>::Value: std::marker::Sized{
+    let x = t.get(); //~ ERROR the size for values of type
+}
+
+fn main() {
+}
diff --git a/src/test/ui/associated-types/associated-types-unsized.rs b/src/test/ui/associated-types/associated-types-unsized.rs
index a9bc24e44d1..bdba4c7ff16 100644
--- a/src/test/ui/associated-types/associated-types-unsized.rs
+++ b/src/test/ui/associated-types/associated-types-unsized.rs
@@ -1,3 +1,6 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
 trait Get {
     type Value: ?Sized;
     fn get(&self) -> <Self as Get>::Value;
diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr
index b5db9743932..18595721bce 100644
--- a/src/test/ui/associated-types/associated-types-unsized.stderr
+++ b/src/test/ui/associated-types/associated-types-unsized.stderr
@@ -1,12 +1,13 @@
 error[E0277]: the size for values of type `<T as Get>::Value` cannot be known at compilation time
-  --> $DIR/associated-types-unsized.rs:7:9
+  --> $DIR/associated-types-unsized.rs:10:9
    |
+LL | fn foo<T:Get>(t: T) {
+   |                     - help: consider further restricting the associated type: `where <T as Get>::Value: std::marker::Sized`
 LL |     let x = t.get();
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `<T as Get>::Value`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where <T as Get>::Value: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr
index fc5de23752b..283a5e04a8b 100644
--- a/src/test/ui/issues/issue-22872.stderr
+++ b/src/test/ui/issues/issue-22872.stderr
@@ -1,11 +1,12 @@
 error[E0277]: `<P as Process<'_>>::Item` is not an iterator
   --> $DIR/issue-22872.rs:20:40
    |
+LL | fn push_process<P>(process: P) where P: Process<'static> {
+   |                                                         - help: consider further restricting the associated type: `, <P as Process<'_>>::Item: std::iter::Iterator`
 LL |     let _: Box<dyn for<'b> Wrap<'b>> = Box::new(Wrapper(process));
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<P as Process<'_>>::Item` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `<P as Process<'_>>::Item`
-   = help: consider adding a `where <P as Process<'_>>::Item: std::iter::Iterator` bound
    = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper<P>`
    = note: required for the cast to the object type `dyn for<'b> Wrap<'b>`
 
diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr
index bfdc4272fb3..6688203147e 100644
--- a/src/test/ui/issues/issue-42312.stderr
+++ b/src/test/ui/issues/issue-42312.stderr
@@ -2,11 +2,12 @@ error[E0277]: the size for values of type `<Self as std::ops::Deref>::Target` ca
   --> $DIR/issue-42312.rs:4:29
    |
 LL |     fn baz(_: Self::Target) where Self: Deref {}
-   |                             ^ doesn't have a size known at compile-time
+   |                             ^                - help: consider further restricting the associated type: `, <Self as std::ops::Deref>::Target: std::marker::Sized`
+   |                             |
+   |                             doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `<Self as std::ops::Deref>::Target`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where <Self as std::ops::Deref>::Target: std::marker::Sized` bound
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed
new file mode 100644
index 00000000000..757d8b8a235
--- /dev/null
+++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed
@@ -0,0 +1,17 @@
+// run-rustfix
+// Test that we do not consider associated types to be sendable without
+// some applicable trait bound (and we don't ICE).
+#![allow(dead_code)]
+
+trait Trait {
+    type AssocType;
+    fn dummy(&self) { }
+}
+fn bar<T:Trait+Send>()  where <T as Trait>::AssocType: std::marker::Send{
+    is_send::<T::AssocType>(); //~ ERROR E0277
+}
+
+fn is_send<T:Send>() {
+}
+
+fn main() { }
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs
index d6483539386..bafc1657737 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs
+++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs
@@ -1,5 +1,7 @@
+// run-rustfix
 // Test that we do not consider associated types to be sendable without
 // some applicable trait bound (and we don't ICE).
+#![allow(dead_code)]
 
 trait Trait {
     type AssocType;
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
index b842d0ae1a2..dd6dcbe2ef5 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
+++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
@@ -1,6 +1,8 @@
 error[E0277]: `<T as Trait>::AssocType` cannot be sent between threads safely
-  --> $DIR/typeck-default-trait-impl-assoc-type.rs:9:5
+  --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5
    |
+LL | fn bar<T:Trait+Send>() {
+   |                        - help: consider further restricting the associated type: `where <T as Trait>::AssocType: std::marker::Send`
 LL |     is_send::<T::AssocType>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^ `<T as Trait>::AssocType` cannot be sent between threads safely
 ...
@@ -8,7 +10,6 @@ LL | fn is_send<T:Send>() {
    |    -------   ---- required by this bound in `is_send`
    |
    = help: the trait `std::marker::Send` is not implemented for `<T as Trait>::AssocType`
-   = help: consider adding a `where <T as Trait>::AssocType: std::marker::Send` bound
 
 error: aborting due to previous error