about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-10-09 15:54:23 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-10-15 13:55:44 -0700
commitbc744bca9063cd9145fceed4ba7ef14cab0ecdd6 (patch)
treef1d4115c2884417e23b667ddeed976e4942000ef /src
parent5cc99eed04005108797fbba82eaf8ef7918051db (diff)
downloadrust-bc744bca9063cd9145fceed4ba7ef14cab0ecdd6.tar.gz
rust-bc744bca9063cd9145fceed4ba7ef14cab0ecdd6.zip
Suggest associated bound restrictions in `impl`s
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/mod.rs6
-rw-r--r--src/librustc/traits/error_reporting.rs18
-rw-r--r--src/test/ui/issues/issue-38821.stderr5
-rw-r--r--src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs25
-rw-r--r--src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr43
5 files changed, 95 insertions, 2 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 7350f89018b..fa0f620530d 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -669,6 +669,12 @@ impl WhereClause {
             Some(self.span)
         }
     }
+
+    /// The `WhereClause` under normal circumstances points at either the predicates or the empty
+    /// space where the `where` clause should be. Only of use for diagnostic suggestions.
+    pub fn span_for_predicates_or_empty_place(&self) -> Span {
+        self.span
+    }
 }
 
 /// A single predicate in a where-clause.
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 2ac691b47ac..91106d35a7e 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1044,6 +1044,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     }
                     return;
                 }
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Impl(_, _, _, generics, ..), ..
+                }) if projection.is_some() => {
+                    err.span_suggestion(
+                        generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(),
+                        "consider further restricting the associated type",
+                        format!(
+                            "{} {}", if generics.where_clause.predicates.is_empty() {
+                                " where"
+                            } else {
+                                " ,"
+                            },
+                            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, .. }) |
diff --git a/src/test/ui/issues/issue-38821.stderr b/src/test/ui/issues/issue-38821.stderr
index dbd204ec299..3e2af7c44e4 100644
--- a/src/test/ui/issues/issue-38821.stderr
+++ b/src/test/ui/issues/issue-38821.stderr
@@ -2,9 +2,10 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:17
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |                 ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |                 ^^^^- help: consider further restricting the associated type: `, <Col as Expression>::SqlType: NotNull`
+   |                 |
+   |                 the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
-   = help: consider adding a `where <Col as Expression>::SqlType: NotNull` bound
    = note: required because of the requirements on the impl of `IntoNullable` for `<Col as Expression>::SqlType`
 
 error: aborting due to previous error
diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs
new file mode 100644
index 00000000000..265ccb3125c
--- /dev/null
+++ b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs
@@ -0,0 +1,25 @@
+// Running rustfix would cause the same suggestion to be applied multiple times, which results in
+// invalid code.
+
+trait Parent {
+    type Ty;
+    type Assoc: Child<Self::Ty>;
+}
+
+trait Child<T> {}
+
+struct ChildWrapper<T>(T);
+
+impl<A, T> Child<A> for ChildWrapper<T> where T: Child<A> {}
+
+struct ParentWrapper<T>(T);
+
+impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
+    //~^ ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+    //~| ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+    type Ty = A;
+    type Assoc = ChildWrapper<T::Assoc>;
+    //~^ ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr
new file mode 100644
index 00000000000..bdea8ab97e5
--- /dev/null
+++ b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr
@@ -0,0 +1,43 @@
+error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+  --> $DIR/missing-assoc-type-bound-restriction.rs:17:1
+   |
+LL |   trait Parent {
+   |   ------------ required by `Parent`
+...
+LL |   impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
+   |   ^                                                     - help: consider further restricting the associated type: `where <T as Parent>::Assoc: Child<A>`
+   |  _|
+   | |
+LL | |
+LL | |
+LL | |     type Ty = A;
+LL | |     type Assoc = ChildWrapper<T::Assoc>;
+LL | |
+LL | | }
+   | |_^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
+
+error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+  --> $DIR/missing-assoc-type-bound-restriction.rs:17:28
+   |
+LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
+   |                            ^^^^^^                     - help: consider further restricting the associated type: `where <T as Parent>::Assoc: Child<A>`
+   |                            |
+   |                            the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
+   |
+   = note: required because of the requirements on the impl of `Child<A>` for `ChildWrapper<<T as Parent>::Assoc>`
+
+error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+  --> $DIR/missing-assoc-type-bound-restriction.rs:21:5
+   |
+LL | trait Parent {
+   | ------------ required by `Parent`
+...
+LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
+   |                                                       - help: consider further restricting the associated type: `where <T as Parent>::Assoc: Child<A>`
+...
+LL |     type Assoc = ChildWrapper<T::Assoc>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.