about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-11-09 07:18:29 +0100
committerGitHub <noreply@github.com>2019-11-09 07:18:29 +0100
commit666f9f9aa0c193715c68e068880f9c5ce75506c5 (patch)
treeb8ebe526e6df851fa0c1436d8a7228b9bd706ba1
parentaaceeded9ee7a05d5bea960ae6fdf3b7af8d2163 (diff)
parent9534b5863f0a6e41c6566795995219bd06ec4bf9 (diff)
downloadrust-666f9f9aa0c193715c68e068880f9c5ce75506c5.tar.gz
rust-666f9f9aa0c193715c68e068880f9c5ce75506c5.zip
Rollup merge of #65994 - estebank:where-bound, r=nikomatsakis
Point at where clauses where the associated item was restricted

CC #57663.
r? @nikomatsakis
-rw-r--r--src/librustc/traits/error_reporting.rs9
-rw-r--r--src/librustc/traits/mod.rs9
-rw-r--r--src/librustc/traits/structural_impls.rs2
-rw-r--r--src/librustc/ty/wf.rs101
-rw-r--r--src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs16
-rw-r--r--src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr28
6 files changed, 147 insertions, 18 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 54c01034221..23c4ec062ea 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -2287,11 +2287,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     );
                 }
             }
-            ObligationCauseCode::AssocTypeBound(impl_span, orig) => {
-                err.span_label(orig, "associated type defined here");
-                if let Some(sp) = impl_span {
+            ObligationCauseCode::AssocTypeBound(ref data) => {
+                err.span_label(data.original, "associated type defined here");
+                if let Some(sp) = data.impl_span {
                     err.span_label(sp, "in this `impl` item");
                 }
+                for sp in &data.bounds {
+                    err.span_label(*sp, "restricted in this bound");
+                }
             }
         }
     }
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index b8275299562..a29d8c66d81 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -276,7 +276,14 @@ pub enum ObligationCauseCode<'tcx> {
     /// #[feature(trivial_bounds)] is not enabled
     TrivialBound,
 
-    AssocTypeBound(/*impl*/ Option<Span>, /*original*/ Span),
+    AssocTypeBound(Box<AssocTypeBoundData>),
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct AssocTypeBoundData {
+    pub impl_span: Option<Span>,
+    pub original: Span,
+    pub bounds: Vec<Span>,
 }
 
 // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 109e884f8bd..59f2bb37548 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -549,7 +549,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
             super::MethodReceiver => Some(super::MethodReceiver),
             super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
             super::TrivialBound => Some(super::TrivialBound),
-            super::AssocTypeBound(impl_sp, sp) => Some(super::AssocTypeBound(impl_sp, sp)),
+            super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())),
         }
     }
 }
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 4ea01bf9647..f9e7a8030a6 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -2,9 +2,10 @@ use crate::hir;
 use crate::hir::def_id::DefId;
 use crate::infer::InferCtxt;
 use crate::ty::subst::SubstsRef;
-use crate::traits;
+use crate::traits::{self, AssocTypeBoundData};
 use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use std::iter::once;
+use syntax::symbol::{kw, Ident};
 use syntax_pos::Span;
 use crate::middle::lang_items;
 use crate::mir::interpret::ConstValue;
@@ -176,6 +177,23 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
             pred: &ty::Predicate<'_>,
             trait_assoc_items: ty::AssocItemsIterator<'_>,
         | {
+            let trait_item = tcx.hir().as_local_hir_id(trait_ref.def_id).and_then(|trait_id| {
+                tcx.hir().find(trait_id)
+            });
+            let (trait_name, trait_generics) = match trait_item {
+                Some(hir::Node::Item(hir::Item {
+                    ident,
+                    kind: hir::ItemKind::Trait(.., generics, _, _),
+                    ..
+                })) |
+                Some(hir::Node::Item(hir::Item {
+                    ident,
+                    kind: hir::ItemKind::TraitAlias(generics, _),
+                    ..
+                })) => (Some(ident), Some(generics)),
+                _ => (None, None),
+            };
+
             let item_span = item.map(|i| tcx.sess.source_map().def_span(i.span));
             match pred {
                 ty::Predicate::Projection(proj) => {
@@ -226,10 +244,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                             item.ident == trait_assoc_item.ident
                         }).next() {
                             cause.span = impl_item.span;
-                            cause.code = traits::AssocTypeBound(
-                                item_span,
-                                trait_assoc_item.ident.span,
-                            );
+                            cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
+                                impl_span: item_span,
+                                original: trait_assoc_item.ident.span,
+                                bounds: vec![],
+                            }));
                         }
                     }
                 }
@@ -251,14 +270,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     //   LL |     type Assoc = bool;
                     //      |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
                     //
-                    // FIXME: if the obligation comes from the where clause in the `trait`, we
-                    // should point at it:
+                    // If the obligation comes from the where clause in the `trait`, we point at it:
                     //
                     //   error[E0277]: the trait bound `bool: Bar` is not satisfied
                     //     --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5
                     //      |
                     //      | trait Foo where <Self as Foo>>::Assoc: Bar {
-                    //      |                 -------------------------- obligation set here
+                    //      |                 -------------------------- restricted in this bound
                     //   LL |     type Assoc;
                     //      |          ----- associated type defined here
                     //   ...
@@ -278,11 +296,17 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                                 .next()
                                 .map(|impl_item| (impl_item, trait_assoc_item)))
                         {
+                            let bounds = trait_generics.map(|generics| get_generic_bound_spans(
+                                &generics,
+                                trait_name,
+                                trait_assoc_item.ident,
+                            )).unwrap_or_else(Vec::new);
                             cause.span = impl_item.span;
-                            cause.code = traits::AssocTypeBound(
-                                item_span,
-                                trait_assoc_item.ident.span,
-                            );
+                            cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
+                                impl_span: item_span,
+                                original: trait_assoc_item.ident.span,
+                                bounds,
+                            }));
                         }
                     }
                 }
@@ -666,3 +690,56 @@ pub fn object_region_bounds<'tcx>(
 
     tcx.required_region_bounds(open_ty, predicates)
 }
+
+/// Find the span of a generic bound affecting an associated type.
+fn get_generic_bound_spans(
+    generics: &hir::Generics,
+    trait_name: Option<&Ident>,
+    assoc_item_name: Ident,
+) -> Vec<Span> {
+    let mut bounds = vec![];
+    for clause in generics.where_clause.predicates.iter() {
+        if let hir::WherePredicate::BoundPredicate(pred) = clause {
+            match &pred.bounded_ty.kind {
+                hir::TyKind::Path(hir::QPath::Resolved(Some(ty), path)) => {
+                    let mut s = path.segments.iter();
+                    if let (a, Some(b), None) = (s.next(), s.next(), s.next()) {
+                        if a.map(|s| &s.ident) == trait_name
+                            && b.ident == assoc_item_name
+                            && is_self_path(&ty.kind)
+                        {
+                            // `<Self as Foo>::Bar`
+                            bounds.push(pred.span);
+                        }
+                    }
+                }
+                hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => {
+                    if segment.ident == assoc_item_name {
+                        if is_self_path(&ty.kind) {
+                            // `Self::Bar`
+                            bounds.push(pred.span);
+                        }
+                    }
+                }
+                _ => {}
+            }
+        }
+    }
+    bounds
+}
+
+fn is_self_path(kind: &hir::TyKind) -> bool {
+    match kind {
+        hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
+            let mut s = path.segments.iter();
+            if let (Some(segment), None) = (s.next(), s.next()) {
+                if segment.ident.name == kw::SelfUpper {
+                    // `type(Self)`
+                    return true;
+                }
+            }
+        }
+        _ => {}
+    }
+    false
+}
diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs
index 9360d96f05e..67b7c78071c 100644
--- a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs
+++ b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs
@@ -8,4 +8,20 @@ impl Foo for () {
     type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
 }
 
+trait Baz where Self::Assoc: Bar {
+    type Assoc;
+}
+
+impl Baz for () {
+    type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
+}
+
+trait Bat where <Self as Bat>::Assoc: Bar {
+    type Assoc;
+}
+
+impl Bat for () {
+    type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
+}
+
 fn main() {}
diff --git a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
index f1a2e343a7e..072e9dad062 100644
--- a/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
+++ b/src/test/ui/associated-types/point-at-type-on-obligation-failure-2.stderr
@@ -9,6 +9,32 @@ LL | impl Foo for () {
 LL |     type Assoc = bool;
    |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
 
-error: aborting due to previous error
+error[E0277]: the trait bound `bool: Bar` is not satisfied
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:16:5
+   |
+LL | trait Baz where Self::Assoc: Bar {
+   |                 ---------------- restricted in this bound
+LL |     type Assoc;
+   |          ----- associated type defined here
+...
+LL | impl Baz for () {
+   | --------------- in this `impl` item
+LL |     type Assoc = bool;
+   |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
+
+error[E0277]: the trait bound `bool: Bar` is not satisfied
+  --> $DIR/point-at-type-on-obligation-failure-2.rs:24:5
+   |
+LL | trait Bat where <Self as Bat>::Assoc: Bar {
+   |                 ------------------------- restricted in this bound
+LL |     type Assoc;
+   |          ----- associated type defined here
+...
+LL | impl Bat for () {
+   | --------------- in this `impl` item
+LL |     type Assoc = bool;
+   |     ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.