about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/dep_graph/dep_node.rs4
-rw-r--r--src/librustc/diagnostics.rs17
-rw-r--r--src/librustc/hir/map/mod.rs24
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/ty/maps.rs97
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_typeck/astconv.rs56
-rw-r--r--src/librustc_typeck/check/mod.rs43
-rw-r--r--src/librustc_typeck/collect.rs257
-rw-r--r--src/librustc_typeck/diagnostics.rs17
-rw-r--r--src/librustc_typeck/lib.rs25
-rw-r--r--src/test/compile-fail/cycle-projection-based-on-where-clause.rs1
-rw-r--r--src/test/compile-fail/cycle-trait-supertrait-indirect.rs6
-rw-r--r--src/test/compile-fail/issue-12511.rs7
-rw-r--r--src/test/compile-fail/issue-20772.rs1
-rw-r--r--src/test/compile-fail/issue-21177.rs3
16 files changed, 266 insertions, 295 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 8da032f5935..769c08a81ef 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -109,6 +109,7 @@ pub enum DepNode<D: Clone + Debug> {
     // predicates for an item wind up in `ItemSignature`).
     AssociatedItems(D),
     ItemSignature(D),
+    TypeParamPredicates((D, D)),
     SizedConstraint(D),
     AssociatedItemDefIds(D),
     InherentImpls(D),
@@ -259,6 +260,9 @@ impl<D: Clone + Debug> DepNode<D> {
             TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
             AssociatedItems(ref d) => op(d).map(AssociatedItems),
             ItemSignature(ref d) => op(d).map(ItemSignature),
+            TypeParamPredicates((ref item, ref param)) => {
+                Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
+            }
             SizedConstraint(ref d) => op(d).map(SizedConstraint),
             AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
             InherentImpls(ref d) => op(d).map(InherentImpls),
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index cf51dad5142..458a774c956 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1390,6 +1390,23 @@ error. To resolve it, add an `else` block having the same type as the `if`
 block.
 "##,
 
+E0391: r##"
+This error indicates that some types or traits depend on each other
+and therefore cannot be constructed.
+
+The following example contains a circular dependency between two traits:
+
+```compile_fail,E0391
+trait FirstTrait : SecondTrait {
+
+}
+
+trait SecondTrait : FirstTrait {
+
+}
+```
+"##,
+
 E0398: r##"
 In Rust 1.3, the default object lifetime bounds are expected to change, as
 described in RFC #1156 [1]. You are getting a warning because the compiler
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 9f31b5b456b..13b786541c5 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -437,6 +437,30 @@ impl<'hir> Map<'hir> {
         self.local_def_id(self.body_owner(id))
     }
 
+    pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
+        match self.get(id) {
+            NodeItem(&Item { node: ItemTrait(..), .. }) => id,
+            NodeTyParam(_) => self.get_parent_node(id),
+            _ => {
+                bug!("ty_param_owner: {} not a type parameter",
+                    self.node_to_string(id))
+            }
+        }
+    }
+
+    pub fn ty_param_name(&self, id: NodeId) -> Name {
+        match self.get(id) {
+            NodeItem(&Item { node: ItemTrait(..), .. }) => {
+                keywords::SelfType.name()
+            }
+            NodeTyParam(tp) => tp.name,
+            _ => {
+                bug!("ty_param_name: {} not a type parameter",
+                    self.node_to_string(id))
+            }
+        }
+    }
+
     /// Get the attributes on the krate. This is preferable to
     /// invoking `krate.attrs` because it registers a tighter
     /// dep-graph access.
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index d144f7575a2..60d03ccfe24 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -39,6 +39,7 @@
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(slice_patterns)]
+#![feature(specialization)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
 
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index aeb7a207c44..dc87bb43c26 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -20,6 +20,7 @@ use rustc_data_structures::indexed_vec::IndexVec;
 use std::cell::RefCell;
 use std::rc::Rc;
 use syntax::attr;
+use syntax_pos::Span;
 
 trait Key {
     fn map_crate(&self) -> CrateNum;
@@ -31,13 +32,105 @@ impl Key for DefId {
     }
 }
 
+impl Key for (DefId, DefId) {
+    fn map_crate(&self) -> CrateNum {
+        self.0.krate
+    }
+}
+
+trait Value<'tcx>: Sized {
+    fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
+}
+
+impl<'tcx, T> Value<'tcx> for T {
+    default fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> T {
+        tcx.sess.abort_if_errors();
+        bug!("Value::from_cycle_error called without errors");
+    }
+}
+
+impl<'tcx, T: Default> Value<'tcx> for T {
+    default fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> T {
+        T::default()
+    }
+}
+
+impl<'tcx> Value<'tcx> for Ty<'tcx> {
+    fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
+        tcx.types.err
+    }
+}
+
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+    fn report_cycle(self, span: Span, cycle: &[(Span, Query)]) {
+        assert!(!cycle.is_empty());
+
+        let mut err = struct_span_err!(self.sess, span, E0391,
+            "unsupported cyclic reference between types/traits detected");
+        err.span_label(span, &format!("cyclic reference"));
+
+        err.span_note(cycle[0].0, &format!("the cycle begins when {}...",
+                                           cycle[0].1.describe(self)));
+
+        for &(span, ref query) in &cycle[1..] {
+            err.span_note(span, &format!("...which then requires {}...",
+                                         query.describe(self)));
+        }
+
+        err.note(&format!("...which then again requires {}, completing the cycle.",
+                          cycle[0].1.describe(self)));
+
+        err.emit();
+    }
+
+    pub fn cycle_check<F, R>(self, span: Span, query: Query, compute: F) -> R
+        where F: FnOnce() -> R
+    {
+        {
+            let mut stack = self.maps.query_stack.borrow_mut();
+            if let Some((i, _)) = stack.iter().enumerate().rev()
+                                       .find(|&(_, &(_, ref q))| *q == query) {
+                let cycle = &stack[i..];
+                self.report_cycle(span, cycle);
+                return R::from_cycle_error(self.global_tcx());
+            }
+            stack.push((span, query));
+        }
+
+        let result = compute();
+
+        self.maps.query_stack.borrow_mut().pop();
+        result
+    }
+}
+
+impl Query {
+    fn describe(&self, tcx: TyCtxt) -> String {
+        match *self {
+            Query::ty(def_id) => {
+                format!("processing `{}`", tcx.item_path_str(def_id))
+            }
+            Query::super_predicates(def_id) => {
+                format!("computing the supertraits of `{}`",
+                        tcx.item_path_str(def_id))
+            }
+            Query::type_param_predicates((_, def_id)) => {
+                let id = tcx.hir.as_local_node_id(def_id).unwrap();
+                format!("computing the bounds for type parameter `{}`",
+                        tcx.hir.ty_param_name(id))
+            }
+            _ => bug!("unexpected `{:?}`", self)
+        }
+    }
+}
+
 macro_rules! define_maps {
     (<$tcx:tt>
      $($(#[$attr:meta])*
        pub $name:ident: $node:ident($K:ty) -> $V:ty),*) => {
         pub struct Maps<$tcx> {
             providers: IndexVec<CrateNum, Providers<$tcx>>,
-            pub query_stack: RefCell<Vec<Query>>,
+            pub query_stack: RefCell<Vec<(Span, Query)>>,
             $($(#[$attr])* pub $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>),*
         }
 
@@ -129,7 +222,7 @@ define_maps! { <'tcx>
 
     /// To avoid cycles within the predicates of a single item we compute
     /// per-type-parameter predicates for resolving `T::AssocTy`.
-    pub type_param_predicates: ItemSignature(DefId)
+    pub type_param_predicates: TypeParamPredicates((DefId, DefId))
         -> ty::GenericPredicates<'tcx>,
 
     pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 97476489a8a..9d4e17138a0 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -669,7 +669,7 @@ impl Generics {
 }
 
 /// Bounds on generics.
-#[derive(Clone)]
+#[derive(Clone, Default)]
 pub struct GenericPredicates<'tcx> {
     pub parent: Option<DefId>,
     pub predicates: Vec<Predicate<'tcx>>,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index cf93ef21f5d..ef0dcd4c774 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -64,13 +64,12 @@ pub trait AstConv<'gcx, 'tcx> {
     /// Ensure that the super-predicates for the trait with the given
     /// id are available and also for the transitive set of
     /// super-predicates.
-    fn ensure_super_predicates(&self, span: Span, id: DefId)
-                               -> Result<(), ErrorReported>;
+    fn ensure_super_predicates(&self, span: Span, id: DefId);
 
     /// Returns the set of bounds in scope for the type parameter with
     /// the given id.
-    fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId)
-                                 -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>;
+    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
+                                 -> Vec<ty::Predicate<'tcx>>;
 
     /// Return an (optional) substitution to convert bound type parameters that
     /// are in scope into free ones. This function should only return Some
@@ -599,7 +598,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         // Otherwise, we have to walk through the supertraits to find
         // those that do.
-        self.ensure_super_predicates(binding.span, trait_ref.def_id())?;
+        self.ensure_super_predicates(binding.span, trait_ref.def_id());
 
         let candidates =
             traits::supertraits(tcx, trait_ref.clone())
@@ -685,10 +684,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             })
         });
 
-        // ensure the super predicates and stop if we encountered an error
-        if self.ensure_super_predicates(span, principal.def_id()).is_err() {
-            return tcx.types.err;
-        }
+        // ensure the super predicates
+        self.ensure_super_predicates(span, principal.def_id());
 
         // check that there are no gross object safety violations,
         // most importantly, that the supertraits don't contain Self,
@@ -774,29 +771,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     }
 
     // Search for a bound on a type parameter which includes the associated item
-    // given by assoc_name. ty_param_node_id is the node id for the type parameter
-    // (which might be `Self`, but only if it is the `Self` of a trait, not an
-    // impl). This function will fail if there are no suitable bounds or there is
+    // given by `assoc_name`. `ty_param_def_id` is the `DefId` for the type parameter
+    // This function will fail if there are no suitable bounds or there is
     // any ambiguity.
     fn find_bound_for_assoc_item(&self,
-                                 ty_param_node_id: ast::NodeId,
-                                 ty_param_name: ast::Name,
+                                 ty_param_def_id: DefId,
                                  assoc_name: ast::Name,
                                  span: Span)
                                  -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
     {
         let tcx = self.tcx();
 
-        let bounds = match self.get_type_parameter_bounds(span, ty_param_node_id) {
-            Ok(v) => v,
-            Err(ErrorReported) => {
-                return Err(ErrorReported);
-            }
-        };
+        let bounds: Vec<_> = self.get_type_parameter_bounds(span, ty_param_def_id)
+            .into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect();
 
-        // Ensure the super predicates and stop if we encountered an error.
-        if bounds.iter().any(|b| self.ensure_super_predicates(span, b.def_id()).is_err()) {
-            return Err(ErrorReported);
+        // Ensure the super predicates.
+        for b in &bounds {
+            self.ensure_super_predicates(span, b.def_id());
         }
 
         // Check that there is exactly one way to find an associated type with the
@@ -805,8 +796,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             traits::transitive_bounds(tcx, &bounds)
             .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name));
 
+        let param_node_id = tcx.hir.as_local_node_id(ty_param_def_id).unwrap();
+        let param_name = tcx.hir.ty_param_name(param_node_id);
         self.one_bound_for_assoc_type(suitable_bounds,
-                                      &ty_param_name.as_str(),
+                                      &param_name.as_str(),
                                       &assoc_name.as_str(),
                                       span)
     }
@@ -914,9 +907,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     trait_ref
                 };
 
-                if self.ensure_super_predicates(span, trait_ref.def_id).is_err() {
-                    return (tcx.types.err, Def::Err);
-                }
+                self.ensure_super_predicates(span, trait_ref.def_id);
 
                 let candidates =
                     traits::supertraits(tcx, ty::Binder(trait_ref))
@@ -933,12 +924,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             (&ty::TyParam(_), Def::SelfTy(Some(param_did), None)) |
             (&ty::TyParam(_), Def::TyParam(param_did)) => {
-                let param_node_id = tcx.hir.as_local_node_id(param_did).unwrap();
-                let param_name = ::ty_param_name(tcx, param_node_id);
-                match self.find_bound_for_assoc_item(param_node_id,
-                                                     param_name,
-                                                     assoc_name,
-                                                     span) {
+                match self.find_bound_for_assoc_item(param_did, assoc_name, span) {
                     Ok(bound) => bound,
                     Err(ErrorReported) => return (tcx.types.err, Def::Err),
                 }
@@ -1375,9 +1361,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                existential_predicates);
 
         if let Some(principal) = existential_predicates.principal() {
-            if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) {
-                return Some(tcx.mk_region(ty::ReStatic));
-            }
+            self.ensure_super_predicates(span, principal.def_id());
         }
 
         // No explicit region bound specified. Therefore, examine trait
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d52516e0ae5..d2cd766fdf0 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -91,7 +91,7 @@ use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::{ParamTy, ParameterEnvironment};
 use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
-use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPolyTraitRef};
+use rustc::ty::{self, Ty, TyCtxt, Visibility};
 use rustc::ty::{MethodCall, MethodCallee};
 use rustc::ty::adjustment;
 use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
@@ -1366,44 +1366,31 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
         self.tcx().lookup_trait_def(id)
     }
 
-    fn ensure_super_predicates(&self, _: Span, _: DefId) -> Result<(), ErrorReported> {
+    fn ensure_super_predicates(&self, _: Span, _: DefId) {
         // all super predicates are ensured during collect pass
-        Ok(())
     }
 
     fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
         Some(&self.parameter_environment.free_substs)
     }
 
-    fn get_type_parameter_bounds(&self,
-                                 _: Span,
-                                 node_id: ast::NodeId)
-                                 -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
+    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
+                                 -> Vec<ty::Predicate<'tcx>>
     {
         let tcx = self.tcx;
-        let item_id = ::ty_param_owner(tcx, node_id);
+        let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+        let item_id = tcx.hir.ty_param_owner(node_id);
         let item_def_id = tcx.hir.local_def_id(item_id);
         let generics = tcx.item_generics(item_def_id);
-        let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id).index];
-        let r = self.parameter_environment
-                                  .caller_bounds
-                                  .iter()
-                                  .filter_map(|predicate| {
-                                      match *predicate {
-                                          ty::Predicate::Trait(ref data) => {
-                                              if data.0.self_ty().is_param(index) {
-                                                  Some(data.to_poly_trait_ref())
-                                              } else {
-                                                  None
-                                              }
-                                          }
-                                          _ => {
-                                              None
-                                          }
-                                      }
-                                  })
-                                  .collect();
-        Ok(r)
+        let index = generics.type_param_to_index[&def_id.index];
+        self.parameter_environment.caller_bounds.iter().filter(|predicate| {
+            match **predicate {
+                ty::Predicate::Trait(ref data) => {
+                    data.0.self_ty().is_param(index)
+                }
+                _ => false
+            }
+        }).cloned().collect()
     }
 
     fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 95fd123b7df..ff9c1cc7d36 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -70,7 +70,7 @@ use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContai
 use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
 use rustc::ty::util::IntTypeExt;
 use rustc::dep_graph::DepNode;
-use util::common::{ErrorReported, MemoizationMap};
+use util::common::MemoizationMap;
 use util::nodemap::{NodeMap, FxHashMap};
 
 use rustc_const_math::ConstInt;
@@ -80,7 +80,7 @@ use std::collections::BTreeMap;
 
 use syntax::{abi, ast, attr};
 use syntax::symbol::{Symbol, keywords};
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 use rustc::hir::{self, map as hir_map};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
@@ -231,91 +231,6 @@ impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
     }
 }
 
-    fn cycle_check<F,R>(tcx: TyCtxt,
-                        span: Span,
-                        query: ty::maps::Query,
-                        code: F)
-                        -> Result<R,ErrorReported>
-        where F: FnOnce() -> Result<R,ErrorReported>
-    {
-        {
-            let mut stack = tcx.maps.query_stack.borrow_mut();
-            if let Some((i, _)) = stack.iter().enumerate().rev().find(|&(_, q)| *q == query) {
-                let cycle = &stack[i..];
-                report_cycle(tcx, span, cycle);
-                return Err(ErrorReported);
-            }
-            stack.push(query);
-        }
-
-        let result = code();
-
-        tcx.maps.query_stack.borrow_mut().pop();
-        result
-    }
-
-    fn report_cycle(tcx: TyCtxt,
-                    span: Span,
-                    cycle: &[ty::maps::Query])
-    {
-        assert!(!cycle.is_empty());
-
-        let mut err = struct_span_err!(tcx.sess, span, E0391,
-            "unsupported cyclic reference between types/traits detected");
-        err.span_label(span, &format!("cyclic reference"));
-
-        let describe = |query: ty::maps::Query| {
-            match query {
-                ty::maps::Query::ty(def_id) => {
-                    format!("processing `{}`", tcx.item_path_str(def_id))
-                }
-                ty::maps::Query::super_predicates(def_id) => {
-                    format!("computing the supertraits of `{}`",
-                            tcx.item_path_str(def_id))
-                }
-                ty::maps::Query::type_param_predicates(def_id) => {
-                    let id = tcx.hir.as_local_node_id(def_id).unwrap();
-                    format!("the cycle begins when computing the bounds \
-                             for type parameter `{}`",
-                            ::ty_param_name(tcx, id))
-                }
-                query => span_bug!(span, "unexpected `{:?}`", query)
-            }
-        };
-
-        err.note(&format!("the cycle begins when {}...",
-                          describe(cycle[0])));
-
-        for &query in &cycle[1..] {
-            err.note(&format!("...which then requires {}...",
-                              describe(query)));
-        }
-
-        err.note(&format!("...which then again requires {}, completing the cycle.",
-                          describe(cycle[0])));
-
-        err.emit();
-    }
-
-    /// Ensure that the (transitive) super predicates for
-    /// `trait_def_id` are available. This will report a cycle error
-    /// if a trait `X` (transitively) extends itself in some form.
-    fn ensure_super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                         span: Span,
-                                         trait_def_id: DefId)
-                                         -> Result<(), ErrorReported>
-    {
-        cycle_check(tcx, span, ty::maps::Query::super_predicates(trait_def_id), || {
-            let def_ids = ensure_super_predicates_step(tcx, trait_def_id);
-
-            for def_id in def_ids {
-                ensure_super_predicates(tcx, span, def_id)?;
-            }
-
-            Ok(())
-        })
-    }
-
 impl<'a,'tcx> ItemCtxt<'a,'tcx> {
     fn to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
         AstConv::ast_ty_to_ty(self, ast_ty)
@@ -334,9 +249,9 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
     }
 
     fn get_item_type(&self, span: Span, id: DefId) -> Ty<'tcx> {
-        cycle_check(self.tcx, span, ty::maps::Query::ty(id), || {
-            Ok(type_of_def_id(self.tcx, id))
-        }).unwrap_or(self.tcx.types.err)
+        self.tcx.cycle_check(span, ty::maps::Query::ty(id), || {
+            type_of_def_id(self.tcx, id)
+        })
     }
 
     fn get_trait_def(&self, def_id: DefId) -> &'tcx ty::TraitDef {
@@ -349,30 +264,36 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
         }
     }
 
+    /// Ensure that the (transitive) super predicates for
+    /// `trait_def_id` are available. This will report a cycle error
+    /// if a trait `X` (transitively) extends itself in some form.
     fn ensure_super_predicates(&self,
                                span: Span,
-                               trait_def_id: DefId)
-                               -> Result<(), ErrorReported>
-    {
-        debug!("ensure_super_predicates(trait_def_id={:?})",
-               trait_def_id);
+                               trait_def_id: DefId) {
+        if !trait_def_id.is_local() {
+            // If this trait comes from an external crate, then all of the
+            // supertraits it may depend on also must come from external
+            // crates, and hence all of them already have their
+            // super-predicates "converted" (and available from crate
+            // meta-data), so there is no need to transitively test them.
+            return;
+        }
 
-        ensure_super_predicates(self.tcx, span, trait_def_id)
+        self.tcx.maps.super_predicates.memoize(trait_def_id, || {
+            self.tcx.cycle_check(span, ty::maps::Query::super_predicates(trait_def_id), || {
+                super_predicates(self.tcx, trait_def_id)
+            })
+        });
     }
 
     fn get_type_parameter_bounds(&self,
                                  span: Span,
-                                 node_id: ast::NodeId)
-                                 -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
+                                 def_id: DefId)
+                                 -> Vec<ty::Predicate<'tcx>>
     {
-        let def_id = self.tcx.hir.local_def_id(node_id);
-        cycle_check(self.tcx, span, ty::maps::Query::type_param_predicates(def_id), || {
-            let v = get_type_parameter_bounds(self.tcx, self.item_def_id, node_id)
-                            .into_iter()
-                            .filter_map(|p| p.to_opt_poly_trait_ref())
-                            .collect();
-            Ok(v)
-        })
+        self.tcx.cycle_check(span,
+            ty::maps::Query::type_param_predicates((self.item_def_id, def_id)),
+            || get_type_parameter_bounds(self.tcx, self.item_def_id, def_id))
     }
 
     fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
@@ -428,7 +349,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
 
     fn get_type_parameter_bounds<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                            item_def_id: DefId,
-                                           param_id: ast::NodeId)
+                                           def_id: DefId)
                                            -> Vec<ty::Predicate<'tcx>>
     {
         use rustc::hir::map::*;
@@ -438,10 +359,12 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
         // written inline like `<T:Foo>` or in a where clause like
         // `where T:Foo`.
 
-        let param_owner_def_id = tcx.hir.local_def_id(::ty_param_owner(tcx, param_id));
+        let param_id = tcx.hir.as_local_node_id(def_id).unwrap();
+        let param_owner = tcx.hir.ty_param_owner(param_id);
+        let param_owner_def_id = tcx.hir.local_def_id(param_owner);
         let generics = generics_of_def_id(tcx, param_owner_def_id);
-        let index = generics.type_param_to_index[&tcx.hir.local_def_id(param_id).index];
-        let ty = tcx.mk_param(index, ::ty_param_name(tcx, param_id));
+        let index = generics.type_param_to_index[&def_id.index];
+        let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id));
 
         // Don't look for bounds where the type parameter isn't in scope.
         let parent = if item_def_id == param_owner_def_id {
@@ -450,8 +373,9 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
             generics_of_def_id(tcx, item_def_id).parent
         };
 
-        let mut results = parent.map_or(vec![], |def_id| {
-            get_type_parameter_bounds(tcx, def_id, param_id)
+        let mut results = parent.map_or(vec![], |parent| {
+            let icx = ItemCtxt::new(tcx, parent);
+            icx.get_type_parameter_bounds(DUMMY_SP, def_id)
         });
 
         let item_node_id = tcx.hir.as_local_node_id(item_def_id).unwrap();
@@ -706,8 +630,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
         hir::ItemTrait(..) => {
             generics_of_def_id(tcx, def_id);
             trait_def_of_item(tcx, it);
-            let _: Result<(), ErrorReported> = // any error is already reported, can ignore
-                ensure_super_predicates(tcx, it.span, def_id);
+            icx.ensure_super_predicates(it.span, def_id);
             predicates_of_item(tcx, it);
         },
         hir::ItemStruct(ref struct_def, _) |
@@ -1025,82 +948,54 @@ fn convert_enum_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 /// Ensures that the super-predicates of the trait with def-id
-/// trait_def_id are converted and stored. This does NOT ensure that
-/// the transitive super-predicates are converted; that is the job of
-/// the `ensure_super_predicates()` method in the `AstConv` impl
-/// above. Returns a list of trait def-ids that must be ensured as
-/// well to guarantee that the transitive superpredicates are
-/// converted.
-fn ensure_super_predicates_step<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                          trait_def_id: DefId)
-                                          -> Vec<DefId>
-{
-    debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id);
-
-    let trait_node_id = if let Some(n) = tcx.hir.as_local_node_id(trait_def_id) {
-        n
-    } else {
-        // If this trait comes from an external crate, then all of the
-        // supertraits it may depend on also must come from external
-        // crates, and hence all of them already have their
-        // super-predicates "converted" (and available from crate
-        // meta-data), so there is no need to transitively test them.
-        return Vec::new();
+/// trait_def_id are converted and stored. This also ensures that
+/// the transitive super-predicates are converted;
+fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                              trait_def_id: DefId)
+                              -> ty::GenericPredicates<'tcx> {
+    debug!("super_predicates(trait_def_id={:?})", trait_def_id);
+    let trait_node_id = tcx.hir.as_local_node_id(trait_def_id).unwrap();
+
+    let item = match tcx.hir.get(trait_node_id) {
+        hir_map::NodeItem(item) => item,
+        _ => bug!("trait_node_id {} is not an item", trait_node_id)
     };
 
-    let superpredicates = tcx.maps.super_predicates.borrow().get(&trait_def_id).cloned();
-    let superpredicates = superpredicates.unwrap_or_else(|| {
-        let item = match tcx.hir.get(trait_node_id) {
-            hir_map::NodeItem(item) => item,
-            _ => bug!("trait_node_id {} is not an item", trait_node_id)
-        };
-
-        let (generics, bounds) = match item.node {
-            hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
-            _ => span_bug!(item.span,
-                           "ensure_super_predicates_step invoked on non-trait"),
-        };
-
-        let icx = ItemCtxt::new(tcx, trait_def_id);
-
-        // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
-        let self_param_ty = tcx.mk_self_type();
-        let superbounds1 = compute_bounds(&icx,
-                                          self_param_ty,
-                                          bounds,
-                                          SizedByDefault::No,
-                                          item.span);
-
-        let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+    let (generics, bounds) = match item.node {
+        hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
+        _ => span_bug!(item.span,
+                       "super_predicates invoked on non-trait"),
+    };
 
-        // Convert any explicit superbounds in the where clause,
-        // e.g. `trait Foo where Self : Bar`:
-        let superbounds2 = icx.type_parameter_bounds_in_generics(generics, item.id, self_param_ty);
+    let icx = ItemCtxt::new(tcx, trait_def_id);
 
-        // Combine the two lists to form the complete set of superbounds:
-        let superbounds = superbounds1.into_iter().chain(superbounds2).collect();
-        let superpredicates = ty::GenericPredicates {
-            parent: None,
-            predicates: superbounds
-        };
-        debug!("superpredicates for trait {:?} = {:?}",
-               tcx.hir.local_def_id(item.id),
-               superpredicates);
+    // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
+    let self_param_ty = tcx.mk_self_type();
+    let superbounds1 = compute_bounds(&icx,
+                                      self_param_ty,
+                                      bounds,
+                                      SizedByDefault::No,
+                                      item.span);
 
-        tcx.maps.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone());
+    let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
 
-        superpredicates
-    });
+    // Convert any explicit superbounds in the where clause,
+    // e.g. `trait Foo where Self : Bar`:
+    let superbounds2 = icx.type_parameter_bounds_in_generics(generics, item.id, self_param_ty);
 
-    let def_ids: Vec<_> = superpredicates.predicates
-                                         .iter()
-                                         .filter_map(|p| p.to_opt_poly_trait_ref())
-                                         .map(|tr| tr.def_id())
-                                         .collect();
+    // Combine the two lists to form the complete set of superbounds:
+    let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect();
 
-    debug!("ensure_super_predicates_step: def_ids={:?}", def_ids);
+    // Now require that immediate supertraits are converted,
+    // which will, in turn, reach indirect supertraits.
+    for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) {
+        icx.ensure_super_predicates(item.span, bound.def_id());
+    }
 
-    def_ids
+    ty::GenericPredicates {
+        parent: None,
+        predicates: superbounds
+    }
 }
 
 fn trait_def_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) -> &'tcx ty::TraitDef {
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 1ff6944d98d..e8cb25cec4f 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -3417,23 +3417,6 @@ impl Bar for *mut Foo {
 ```
 "##,
 
-E0391: r##"
-This error indicates that some types or traits depend on each other
-and therefore cannot be constructed.
-
-The following example contains a circular dependency between two traits:
-
-```compile_fail,E0391
-trait FirstTrait : SecondTrait {
-
-}
-
-trait SecondTrait : FirstTrait {
-
-}
-```
-"##,
-
 E0392: r##"
 This error indicates that a type or lifetime parameter has been declared
 but not actually used. Here is an example that demonstrates the error:
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index ddd8d9259cc..c3c1952415b 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -116,7 +116,6 @@ use util::common::time;
 
 use syntax::ast;
 use syntax::abi::Abi;
-use syntax::symbol::keywords;
 use syntax_pos::Span;
 
 use std::iter;
@@ -170,30 +169,6 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     })
 }
 
-fn ty_param_owner(tcx: TyCtxt, id: ast::NodeId) -> ast::NodeId {
-    match tcx.hir.get(id) {
-        hir::map::NodeItem(&hir::Item { node: hir::ItemTrait(..), .. }) => id,
-        hir::map::NodeTyParam(_) => tcx.hir.get_parent_node(id),
-        _ => {
-            bug!("ty_param_owner: {} not a type parameter",
-                 tcx.hir.node_to_string(id))
-        }
-    }
-}
-
-fn ty_param_name(tcx: TyCtxt, id: ast::NodeId) -> ast::Name {
-    match tcx.hir.get(id) {
-        hir::map::NodeItem(&hir::Item { node: hir::ItemTrait(..), .. }) => {
-            keywords::SelfType.name()
-        }
-        hir::map::NodeTyParam(tp) => tp.name,
-        _ => {
-            bug!("ty_param_name: {} not a type parameter",
-                 tcx.hir.node_to_string(id))
-        }
-    }
-}
-
 fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               main_id: ast::NodeId,
                               main_span: Span) {
diff --git a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs
index 5ca0700ce6e..7af2f11bd28 100644
--- a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs
+++ b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs
@@ -26,6 +26,7 @@ struct A<T>
     where T : Trait,
           T : Add<T::Item>
     //~^ ERROR unsupported cyclic reference between types/traits detected
+    //~| ERROR associated type `Item` not found for `T`
 {
     data: T
 }
diff --git a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs
index c9bfde3f4ed..905d546e99a 100644
--- a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs
+++ b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs
@@ -12,14 +12,16 @@
 // a direct participant in the cycle.
 
 trait A: B {
-    //~^ ERROR unsupported cyclic reference
+    //~^ NOTE the cycle begins when computing the supertraits of `B`...
 }
 
 trait B: C {
-    //~^ ERROR unsupported cyclic reference
+    //~^ NOTE ...which then requires computing the supertraits of `C`...
 }
 
 trait C: B { }
     //~^ ERROR unsupported cyclic reference
+    //~| cyclic reference
+    //~| NOTE ...which then again requires computing the supertraits of `B`, completing the cycle
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-12511.rs b/src/test/compile-fail/issue-12511.rs
index 35697e68734..0c3073a7701 100644
--- a/src/test/compile-fail/issue-12511.rs
+++ b/src/test/compile-fail/issue-12511.rs
@@ -9,11 +9,14 @@
 // except according to those terms.
 
 trait t1 : t2 {
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ NOTE the cycle begins when computing the supertraits of `t1`...
+//~| NOTE ...which then requires computing the supertraits of `t2`...
 }
 
 trait t2 : t1 {
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ ERROR unsupported cyclic reference between types/traits detected
+//~| cyclic reference
+//~| NOTE ...which then again requires computing the supertraits of `t1`, completing the cycle
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/issue-20772.rs b/src/test/compile-fail/issue-20772.rs
index 44c92f946f0..7ae4250d420 100644
--- a/src/test/compile-fail/issue-20772.rs
+++ b/src/test/compile-fail/issue-20772.rs
@@ -10,6 +10,7 @@
 
 trait T : Iterator<Item=Self::Item>
 //~^ ERROR unsupported cyclic reference between types/traits detected
+//~| ERROR associated type `Item` not found for `Self`
 {}
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-21177.rs b/src/test/compile-fail/issue-21177.rs
index 5ad9a12362d..f49b7195383 100644
--- a/src/test/compile-fail/issue-21177.rs
+++ b/src/test/compile-fail/issue-21177.rs
@@ -14,6 +14,7 @@ trait Trait {
 }
 
 fn foo<T: Trait<A = T::B>>() { }
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ ERROR unsupported cyclic reference between types/traits detected
+//~| ERROR associated type `B` not found for `T`
 
 fn main() { }