about summary refs log tree commit diff
diff options
context:
space:
mode:
authorjackh726 <jack.huey@umassmed.edu>2021-07-25 22:12:34 -0400
committerjackh726 <jack.huey@umassmed.edu>2021-08-13 17:07:56 -0400
commit22fc7d6e5aac46b760d1aafdc9d0f891ce8117ff (patch)
tree39df87062109f9ecc2293994e091d9e51dc3f69c
parent2fc3c69e5419292e92663a5f1e39203478925661 (diff)
downloadrust-22fc7d6e5aac46b760d1aafdc9d0f891ce8117ff.tar.gz
rust-22fc7d6e5aac46b760d1aafdc9d0f891ce8117ff.zip
Point to where clause for GATs
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs98
-rw-r--r--compiler/rustc_infer/src/lib.rs1
-rw-r--r--src/test/ui/generic-associated-types/issue-84931.rs22
-rw-r--r--src/test/ui/generic-associated-types/issue-84931.stderr11
-rw-r--r--src/test/ui/generic-associated-types/issue-86483.stderr7
-rw-r--r--src/test/ui/generic-associated-types/issue-86787.rs40
-rw-r--r--src/test/ui/generic-associated-types/issue-86787.stderr29
7 files changed, 200 insertions, 8 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index d5e1c061bf0..50048534aae 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2259,9 +2259,99 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 }
             };
 
-        let mut err = match *sub {
-            ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
-            | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }) => {
+        #[derive(Debug)]
+        enum SubOrigin<'hir> {
+            GAT(&'hir hir::Generics<'hir>),
+            Impl(&'hir hir::Generics<'hir>),
+            Trait(&'hir hir::Generics<'hir>),
+            Fn(&'hir hir::Generics<'hir>),
+            Unknown,
+        }
+        let sub_origin = 'origin: {
+            match *sub {
+                ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => {
+                    let node = self.tcx.hir().get_if_local(def_id).unwrap();
+                    match node {
+                        Node::GenericParam(param) => {
+                            for h in self.tcx.hir().parent_iter(param.hir_id) {
+                                break 'origin match h.1 {
+                                    Node::ImplItem(hir::ImplItem {
+                                        kind: hir::ImplItemKind::TyAlias(..),
+                                        generics,
+                                        ..
+                                    }) => SubOrigin::GAT(generics),
+                                    Node::ImplItem(hir::ImplItem {
+                                        kind: hir::ImplItemKind::Fn(..),
+                                        generics,
+                                        ..
+                                    }) => SubOrigin::Fn(generics),
+                                    Node::TraitItem(hir::TraitItem {
+                                        kind: hir::TraitItemKind::Type(..),
+                                        generics,
+                                        ..
+                                    }) => SubOrigin::GAT(generics),
+                                    Node::TraitItem(hir::TraitItem {
+                                        kind: hir::TraitItemKind::Fn(..),
+                                        generics,
+                                        ..
+                                    }) => SubOrigin::Fn(generics),
+                                    Node::Item(hir::Item {
+                                        kind: hir::ItemKind::Trait(_, _, generics, _, _),
+                                        ..
+                                    }) => SubOrigin::Trait(generics),
+                                    Node::Item(hir::Item {
+                                        kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
+                                        ..
+                                    }) => SubOrigin::Impl(generics),
+                                    Node::Item(hir::Item {
+                                        kind: hir::ItemKind::Fn(_, generics, _),
+                                        ..
+                                    }) => SubOrigin::Fn(generics),
+                                    _ => continue,
+                                };
+                            }
+                        }
+                        _ => {}
+                    }
+                }
+                _ => {}
+            }
+            SubOrigin::Unknown
+        };
+        debug!(?sub_origin);
+
+        let mut err = match (*sub, sub_origin) {
+            // In the case of GATs, we have to be careful. If we a type parameter `T` on an impl,
+            // but a lifetime `'a` on an associated type, then we might need to suggest adding
+            // `where T: 'a`. Importantly, this is on the GAT span, not on the `T` declaration.
+            (ty::ReEarlyBound(ty::EarlyBoundRegion { name: _, .. }), SubOrigin::GAT(generics)) => {
+                // Does the required lifetime have a nice name we can print?
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0309,
+                    "{} may not live long enough",
+                    labeled_user_string
+                );
+                let pred = format!("{}: {}", bound_kind, sub);
+                let suggestion = format!(
+                    "{} {}",
+                    if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
+                    pred,
+                );
+                err.span_suggestion(
+                    generics.where_clause.tail_span_for_suggestion(),
+                    "consider adding a where clause".into(),
+                    suggestion,
+                    Applicability::MaybeIncorrect,
+                );
+                err
+            }
+            (
+                ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
+                | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }),
+                _,
+            ) => {
                 // Does the required lifetime have a nice name we can print?
                 let mut err = struct_span_err!(
                     self.tcx.sess,
@@ -2278,7 +2368,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 err
             }
 
-            ty::ReStatic => {
+            (ty::ReStatic, _) => {
                 // Does the required lifetime have a nice name we can print?
                 let mut err = struct_span_err!(
                     self.tcx.sess,
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index ee358c52c2f..ba7155f63e4 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -22,6 +22,7 @@
 #![feature(in_band_lifetimes)]
 #![feature(control_flow_enum)]
 #![feature(min_specialization)]
+#![feature(label_break_value)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
diff --git a/src/test/ui/generic-associated-types/issue-84931.rs b/src/test/ui/generic-associated-types/issue-84931.rs
new file mode 100644
index 00000000000..9e247de1632
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-84931.rs
@@ -0,0 +1,22 @@
+#![feature(generic_associated_types)]
+// check-fail
+
+trait StreamingIter {
+    type Item<'a> where Self: 'a;
+    fn next<'a>(&'a mut self) -> Option<Self::Item::<'a>>;
+}
+
+struct StreamingSliceIter<'a, T> {
+    idx: usize,
+    data: &'a mut [T],
+}
+
+impl<'b, T: 'b> StreamingIter for StreamingSliceIter<'b, T> {
+    type Item<'a> = &'a mut T;
+    //~^ the parameter type
+    fn next(&mut self) -> Option<&mut T> {
+        loop {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-84931.stderr b/src/test/ui/generic-associated-types/issue-84931.stderr
new file mode 100644
index 00000000000..47decb70ae7
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-84931.stderr
@@ -0,0 +1,11 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/issue-84931.rs:15:21
+   |
+LL |     type Item<'a> = &'a mut T;
+   |                  -  ^^^^^^^^^ ...so that the reference type `&'a mut T` does not outlive the data it points at
+   |                  |
+   |                  help: consider adding a where clause: `where T: 'a`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/generic-associated-types/issue-86483.stderr b/src/test/ui/generic-associated-types/issue-86483.stderr
index f5b92beb3b2..d6978794e1e 100644
--- a/src/test/ui/generic-associated-types/issue-86483.stderr
+++ b/src/test/ui/generic-associated-types/issue-86483.stderr
@@ -37,11 +37,10 @@ LL |     for<'a> T: 'a,
 error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/issue-86483.rs:9:32
    |
-LL | pub trait IceIce<T>
-   |                  - help: consider adding an explicit lifetime bound...: `T: 'v`
-...
 LL |     type Ice<'v>: IntoIterator<Item = &'v T>;
-   |                                ^^^^^^^^^^^^ ...so that the reference type `&'v T` does not outlive the data it points at
+   |                                ^^^^^^^^^^^^ - help: consider adding a where clause: `where T: 'v`
+   |                                |
+   |                                ...so that the reference type `&'v T` does not outlive the data it points at
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/generic-associated-types/issue-86787.rs b/src/test/ui/generic-associated-types/issue-86787.rs
new file mode 100644
index 00000000000..57d478a9ef1
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-86787.rs
@@ -0,0 +1,40 @@
+#![feature(generic_associated_types)]
+// check-fail
+
+enum Either<L, R> {
+    Left(L),
+    Right(R),
+}
+
+pub trait HasChildrenOf {
+    type T;
+    type TRef<'a>;
+
+    fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>>;
+    fn take_children(self) -> Vec<Self::T>;
+}
+
+impl<Left, Right> HasChildrenOf for Either<Left, Right>
+where
+    Left: HasChildrenOf,
+    Right: HasChildrenOf,
+{
+    type T = Either<Left::T, Right::T>;
+    type TRef<'a>
+    //~^ the associated type
+    //~^^ the associated type
+    where
+    <Left as HasChildrenOf>::T: 'a,
+    <Right as HasChildrenOf>::T: 'a
+    = Either<&'a Left::T, &'a Right::T>;
+
+    fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>> {
+        todo!()
+    }
+
+    fn take_children(self) -> Vec<Self::T> {
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr
new file mode 100644
index 00000000000..04cd84b0801
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-86787.stderr
@@ -0,0 +1,29 @@
+error[E0309]: the associated type `<Left as HasChildrenOf>::T` may not live long enough
+  --> $DIR/issue-86787.rs:23:5
+   |
+LL | /     type TRef<'a>
+LL | |
+LL | |
+LL | |     where
+LL | |     <Left as HasChildrenOf>::T: 'a,
+LL | |     <Right as HasChildrenOf>::T: 'a
+   | |                                    - help: consider adding a where clause: `, <Left as HasChildrenOf>::T: 'a`
+LL | |     = Either<&'a Left::T, &'a Right::T>;
+   | |________________________________________^ ...so that the type `<Left as HasChildrenOf>::T` will meet its required lifetime bounds
+
+error[E0309]: the associated type `<Right as HasChildrenOf>::T` may not live long enough
+  --> $DIR/issue-86787.rs:23:5
+   |
+LL | /     type TRef<'a>
+LL | |
+LL | |
+LL | |     where
+LL | |     <Left as HasChildrenOf>::T: 'a,
+LL | |     <Right as HasChildrenOf>::T: 'a
+   | |                                    - help: consider adding a where clause: `, <Right as HasChildrenOf>::T: 'a`
+LL | |     = Either<&'a Left::T, &'a Right::T>;
+   | |________________________________________^ ...so that the type `<Right as HasChildrenOf>::T` will meet its required lifetime bounds
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.