about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/traits/mod.rs70
-rw-r--r--src/librustc/middle/traits/select.rs414
-rw-r--r--src/librustc/middle/ty/context.rs6
-rw-r--r--src/librustc/middle/ty/mod.rs6
-rw-r--r--src/librustc/middle/ty/structural_impls.rs1
-rw-r--r--src/librustc_typeck/collect.rs58
-rw-r--r--src/librustc_typeck/constrained_type_params.rs114
-rw-r--r--src/test/compile-fail/cast-rfc0401.rs5
-rw-r--r--src/test/compile-fail/infinite-instantiation.rs2
-rw-r--r--src/test/compile-fail/issue-29147.rs32
-rw-r--r--src/test/compile-fail/recursion.rs8
-rw-r--r--src/test/run-pass/coherence-rfc447-constrained.rs31
-rw-r--r--src/test/run-pass/issue-29147.rs36
-rw-r--r--src/test/run-pass/trait-copy-guessing.rs46
14 files changed, 530 insertions, 299 deletions
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index a037621f5c0..691bac0cef8 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -44,6 +44,7 @@ pub use self::object_safety::object_safety_violations;
 pub use self::object_safety::ObjectSafetyViolation;
 pub use self::object_safety::MethodViolationCode;
 pub use self::object_safety::is_vtable_safe_method;
+pub use self::select::EvaluationCache;
 pub use self::select::SelectionContext;
 pub use self::select::SelectionCache;
 pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
@@ -339,32 +340,53 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
            ty,
            bound);
 
-    let mut fulfill_cx = FulfillmentContext::new(false);
-
-    // We can use a dummy node-id here because we won't pay any mind
-    // to region obligations that arise (there shouldn't really be any
-    // anyhow).
     let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
-
-    fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
-
-    // Note: we only assume something is `Copy` if we can
-    // *definitively* show that it implements `Copy`. Otherwise,
-    // assume it is move; linear is always ok.
-    match fulfill_cx.select_all_or_error(infcx) {
-        Ok(()) => {
-            debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success",
-                   ty,
-                   bound);
-            true
-        }
-        Err(e) => {
-            debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}",
-                   ty,
-                   bound,
-                   e);
-            false
+    let obligation =
+        util::predicate_for_builtin_bound(infcx.tcx, cause, bound, 0, ty);
+    let obligation = match obligation {
+        Ok(o) => o,
+        Err(..) => return false
+    };
+    let result = SelectionContext::new(infcx)
+        .evaluate_obligation_conservatively(&obligation);
+    debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} => {:?}",
+           ty, bound, result);
+
+    if result && (ty.has_infer_types() || ty.has_closure_types()) {
+        // Because of inference "guessing", selection can sometimes claim
+        // to succeed while the success requires a guess. To ensure
+        // this function's result remains infallible, we must confirm
+        // that guess. While imperfect, I believe this is sound.
+
+        let mut fulfill_cx = FulfillmentContext::new(false);
+
+        // We can use a dummy node-id here because we won't pay any mind
+        // to region obligations that arise (there shouldn't really be any
+        // anyhow).
+        let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
+
+        fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
+
+        // Note: we only assume something is `Copy` if we can
+        // *definitively* show that it implements `Copy`. Otherwise,
+        // assume it is move; linear is always ok.
+        match fulfill_cx.select_all_or_error(infcx) {
+            Ok(()) => {
+                debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success",
+                       ty,
+                       bound);
+                true
+            }
+            Err(e) => {
+                debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}",
+                       ty,
+                       bound,
+                       e);
+                false
+            }
         }
+    } else {
+        result
     }
 }
 
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index f6e35cf739d..ba69632fde1 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 //! See `README.md` for high-level documentation
-#![allow(dead_code)] // FIXME -- just temporarily
 
 pub use self::MethodMatchResult::*;
 pub use self::MethodMatchedData::*;
@@ -190,7 +189,6 @@ pub enum MethodMatchedData {
 /// parameter environment.
 #[derive(PartialEq,Eq,Debug,Clone)]
 enum SelectionCandidate<'tcx> {
-    PhantomFnCandidate,
     BuiltinCandidate(ty::BuiltinBound),
     ParamCandidate(ty::PolyTraitRef<'tcx>),
     ImplCandidate(DefId),
@@ -236,11 +234,24 @@ enum BuiltinBoundConditions<'tcx> {
     AmbiguousBuiltin
 }
 
-#[derive(Debug)]
-enum EvaluationResult<'tcx> {
+#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
+/// The result of trait evaluation. The order is important
+/// here as the evaluation of a list is the maximum of the
+/// evaluations.
+enum EvaluationResult {
+    /// Evaluation successful
     EvaluatedToOk,
+    /// Evaluation failed because of recursion - treated as ambiguous
+    EvaluatedToUnknown,
+    /// Evaluation is known to be ambiguous
     EvaluatedToAmbig,
-    EvaluatedToErr(SelectionError<'tcx>),
+    /// Evaluation failed
+    EvaluatedToErr,
+}
+
+#[derive(Clone)]
+pub struct EvaluationCache<'tcx> {
+    hashmap: RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>, EvaluationResult>>
 }
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
@@ -381,6 +392,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     // The result is "true" if the obligation *may* hold and "false" if
     // we can be sure it does not.
 
+
     /// Evaluates whether the obligation `obligation` can be satisfied (by any means).
     pub fn evaluate_obligation(&mut self,
                                obligation: &PredicateObligation<'tcx>)
@@ -389,45 +401,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         debug!("evaluate_obligation({:?})",
                obligation);
 
-        self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
-            .may_apply()
+        self.infcx.probe(|_| {
+            self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
+                .may_apply()
+        })
     }
 
-    fn evaluate_builtin_bound_recursively<'o>(&mut self,
-                                              bound: ty::BuiltinBound,
-                                              previous_stack: &TraitObligationStack<'o, 'tcx>,
-                                              ty: Ty<'tcx>)
-                                              -> EvaluationResult<'tcx>
+    /// Evaluates whether the obligation `obligation` can be satisfied,
+    /// and returns `false` if not certain. However, this is not entirely
+    /// accurate if inference variables are involved.
+    pub fn evaluate_obligation_conservatively(&mut self,
+                                              obligation: &PredicateObligation<'tcx>)
+                               -> bool
     {
-        let obligation =
-            util::predicate_for_builtin_bound(
-                self.tcx(),
-                previous_stack.obligation.cause.clone(),
-                bound,
-                previous_stack.obligation.recursion_depth + 1,
-                ty);
-
-        match obligation {
-            Ok(obligation) => {
-                self.evaluate_predicate_recursively(previous_stack.list(), &obligation)
-            }
-            Err(ErrorReported) => {
-                EvaluatedToOk
-            }
-        }
+        debug!("evaluate_obligation_conservatively({:?})",
+               obligation);
+
+        self.infcx.probe(|_| {
+            self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
+                == EvaluatedToOk
+        })
     }
 
+    /// Evaluates the predicates in `predicates` recursively. Note that
+    /// this applies projections in the predicates, and therefore
+    /// is run within an inference probe.
     fn evaluate_predicates_recursively<'a,'o,I>(&mut self,
                                                 stack: TraitObligationStackList<'o, 'tcx>,
                                                 predicates: I)
-                                                -> EvaluationResult<'tcx>
+                                                -> EvaluationResult
         where I : Iterator<Item=&'a PredicateObligation<'tcx>>, 'tcx:'a
     {
         let mut result = EvaluatedToOk;
         for obligation in predicates {
-            match self.evaluate_predicate_recursively(stack, obligation) {
-                EvaluatedToErr(e) => { return EvaluatedToErr(e); }
+            let eval = self.evaluate_predicate_recursively(stack, obligation);
+            debug!("evaluate_predicate_recursively({:?}) = {:?}",
+                   obligation, eval);
+            match eval {
+                EvaluatedToErr => { return EvaluatedToErr; }
                 EvaluatedToAmbig => { result = EvaluatedToAmbig; }
+                EvaluatedToUnknown => {
+                    if result < EvaluatedToUnknown {
+                        result = EvaluatedToUnknown;
+                    }
+                }
                 EvaluatedToOk => { }
             }
         }
@@ -437,7 +454,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn evaluate_predicate_recursively<'o>(&mut self,
                                           previous_stack: TraitObligationStackList<'o, 'tcx>,
                                           obligation: &PredicateObligation<'tcx>)
-                                           -> EvaluationResult<'tcx>
+                                           -> EvaluationResult
     {
         debug!("evaluate_predicate_recursively({:?})",
                obligation);
@@ -459,12 +476,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             ty::Predicate::Equate(ref p) => {
-                let result = self.infcx.probe(|_| {
-                    self.infcx.equality_predicate(obligation.cause.span, p)
-                });
-                match result {
+                // does this code ever run?
+                match self.infcx.equality_predicate(obligation.cause.span, p) {
                     Ok(()) => EvaluatedToOk,
-                    Err(_) => EvaluatedToErr(Unimplemented),
+                    Err(_) => EvaluatedToErr
                 }
             }
 
@@ -489,26 +504,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 if object_safety::is_object_safe(self.tcx(), trait_def_id) {
                     EvaluatedToOk
                 } else {
-                    EvaluatedToErr(Unimplemented)
+                    EvaluatedToErr
                 }
             }
 
             ty::Predicate::Projection(ref data) => {
-                self.infcx.probe(|_| {
-                    let project_obligation = obligation.with(data.clone());
-                    match project::poly_project_and_unify_type(self, &project_obligation) {
-                        Ok(Some(subobligations)) => {
-                            self.evaluate_predicates_recursively(previous_stack,
-                                                                 subobligations.iter())
-                        }
-                        Ok(None) => {
-                            EvaluatedToAmbig
-                        }
-                        Err(_) => {
-                            EvaluatedToErr(Unimplemented)
-                        }
+                let project_obligation = obligation.with(data.clone());
+                match project::poly_project_and_unify_type(self, &project_obligation) {
+                    Ok(Some(subobligations)) => {
+                        self.evaluate_predicates_recursively(previous_stack,
+                                                             subobligations.iter())
                     }
-                })
+                    Ok(None) => {
+                        EvaluatedToAmbig
+                    }
+                    Err(_) => {
+                        EvaluatedToErr
+                    }
+                }
             }
         }
     }
@@ -516,22 +529,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn evaluate_obligation_recursively<'o>(&mut self,
                                            previous_stack: TraitObligationStackList<'o, 'tcx>,
                                            obligation: &TraitObligation<'tcx>)
-                                           -> EvaluationResult<'tcx>
+                                           -> EvaluationResult
     {
         debug!("evaluate_obligation_recursively({:?})",
                obligation);
 
         let stack = self.push_stack(previous_stack, obligation);
+        let fresh_trait_ref = stack.fresh_trait_ref;
+        if let Some(result) = self.check_evaluation_cache(fresh_trait_ref) {
+            debug!("CACHE HIT: EVAL({:?})={:?}",
+                   fresh_trait_ref,
+                   result);
+            return result;
+        }
 
         let result = self.evaluate_stack(&stack);
 
-        debug!("result: {:?}", result);
+        debug!("CACHE MISS: EVAL({:?})={:?}",
+               fresh_trait_ref,
+               result);
+        self.insert_evaluation_cache(fresh_trait_ref, result);
+
         result
     }
 
     fn evaluate_stack<'o>(&mut self,
                           stack: &TraitObligationStack<'o, 'tcx>)
-                          -> EvaluationResult<'tcx>
+                          -> EvaluationResult
     {
         // In intercrate mode, whenever any of the types are unbound,
         // there can always be an impl. Even if there are no impls in
@@ -559,16 +583,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // precise still.
         let input_types = stack.fresh_trait_ref.0.input_types();
         let unbound_input_types = input_types.iter().any(|ty| ty.is_fresh());
-        if
-            unbound_input_types &&
-             (self.intercrate ||
+        if unbound_input_types && self.intercrate {
+            debug!("evaluate_stack({:?}) --> unbound argument, intercrate -->  ambiguous",
+                   stack.fresh_trait_ref);
+            return EvaluatedToAmbig;
+        }
+        if unbound_input_types &&
               stack.iter().skip(1).any(
                   |prev| self.match_fresh_trait_refs(&stack.fresh_trait_ref,
-                                                     &prev.fresh_trait_ref)))
+                                                     &prev.fresh_trait_ref))
         {
-            debug!("evaluate_stack({:?}) --> unbound argument, recursion -->  ambiguous",
+            debug!("evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
                    stack.fresh_trait_ref);
-            return EvaluatedToAmbig;
+            return EvaluatedToUnknown;
         }
 
         // If there is any previous entry on the stack that precisely
@@ -601,40 +628,74 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         match self.candidate_from_obligation(stack) {
-            Ok(Some(c)) => self.winnow_candidate(stack, &c),
+            Ok(Some(c)) => self.evaluate_candidate(stack, &c),
             Ok(None) => EvaluatedToAmbig,
-            Err(e) => EvaluatedToErr(e),
+            Err(..) => EvaluatedToErr
         }
     }
 
-    /// Evaluates whether the impl with id `impl_def_id` could be applied to the self type
-    /// `obligation_self_ty`. This can be used either for trait or inherent impls.
-    pub fn evaluate_impl(&mut self,
-                         impl_def_id: DefId,
-                         obligation: &TraitObligation<'tcx>)
-                         -> bool
+    /// Further evaluate `candidate` to decide whether all type parameters match and whether nested
+    /// obligations are met. Returns true if `candidate` remains viable after this further
+    /// scrutiny.
+    fn evaluate_candidate<'o>(&mut self,
+                              stack: &TraitObligationStack<'o, 'tcx>,
+                              candidate: &SelectionCandidate<'tcx>)
+                              -> EvaluationResult
     {
-        debug!("evaluate_impl(impl_def_id={:?}, obligation={:?})",
-               impl_def_id,
-               obligation);
-
-        self.infcx.probe(|snapshot| {
-            match self.match_impl(impl_def_id, obligation, snapshot) {
-                Ok((substs, skol_map)) => {
-                    let vtable_impl = self.vtable_impl(impl_def_id,
-                                                       substs,
-                                                       obligation.cause.clone(),
-                                                       obligation.recursion_depth + 1,
-                                                       skol_map,
-                                                       snapshot);
-                    self.winnow_selection(TraitObligationStackList::empty(),
-                                          VtableImpl(vtable_impl)).may_apply()
-                }
-                Err(()) => {
-                    false
+        debug!("evaluate_candidate: depth={} candidate={:?}",
+               stack.obligation.recursion_depth, candidate);
+        let result = self.infcx.probe(|_| {
+            let candidate = (*candidate).clone();
+            match self.confirm_candidate(stack.obligation, candidate) {
+                Ok(selection) => {
+                    self.evaluate_predicates_recursively(
+                        stack.list(),
+                        selection.nested_obligations().iter())
                 }
+                Err(..) => EvaluatedToErr
             }
-        })
+        });
+        debug!("evaluate_candidate: depth={} result={:?}",
+               stack.obligation.recursion_depth, result);
+        result
+    }
+
+    fn pick_evaluation_cache(&self) -> &EvaluationCache<'tcx> {
+        // see comment in `pick_candidate_cache`
+        if self.intercrate ||
+            !self.param_env().caller_bounds.is_empty()
+        {
+            &self.param_env().evaluation_cache
+        } else
+        {
+            &self.tcx().evaluation_cache
+        }
+    }
+
+    fn check_evaluation_cache(&self, trait_ref: ty::PolyTraitRef<'tcx>)
+                              -> Option<EvaluationResult>
+    {
+        let cache = self.pick_evaluation_cache();
+        cache.hashmap.borrow().get(&trait_ref).cloned()
+    }
+
+    fn insert_evaluation_cache(&mut self,
+                               trait_ref: ty::PolyTraitRef<'tcx>,
+                               result: EvaluationResult)
+    {
+        // Avoid caching results that depend on more than just the trait-ref:
+        // The stack can create EvaluatedToUnknown, and closure signatures
+        // being yet uninferred can create "spurious" EvaluatedToAmbig
+        // and EvaluatedToOk.
+        if result == EvaluatedToUnknown ||
+            ((result == EvaluatedToAmbig || result == EvaluatedToOk)
+             && trait_ref.has_closure_types())
+        {
+            return;
+        }
+
+        let cache = self.pick_evaluation_cache();
+        cache.hashmap.borrow_mut().insert(trait_ref, result);
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -669,7 +730,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         match self.check_candidate_cache(&cache_fresh_trait_pred) {
             Some(c) => {
-                debug!("CACHE HIT: cache_fresh_trait_pred={:?}, candidate={:?}",
+                debug!("CACHE HIT: SELECT({:?})={:?}",
                        cache_fresh_trait_pred,
                        c);
                 return c;
@@ -681,7 +742,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let candidate = self.candidate_from_obligation_no_cache(stack);
 
         if self.should_update_candidate_cache(&cache_fresh_trait_pred, &candidate) {
-            debug!("CACHE MISS: cache_fresh_trait_pred={:?}, candidate={:?}",
+            debug!("CACHE MISS: SELECT({:?})={:?}",
                    cache_fresh_trait_pred, candidate);
             self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone());
         }
@@ -740,7 +801,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // Instead, we select the right impl now but report `Bar does
         // not implement Clone`.
         if candidates.len() > 1 {
-            candidates.retain(|c| self.winnow_candidate(stack, c).may_apply())
+            candidates.retain(|c| self.evaluate_candidate(stack, c).may_apply())
         }
 
         // If there are STILL multiple candidate, we can further reduce
@@ -1138,16 +1199,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn evaluate_where_clause<'o>(&mut self,
                                  stack: &TraitObligationStack<'o, 'tcx>,
                                  where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
-                                 -> EvaluationResult<'tcx>
+                                 -> EvaluationResult
     {
         self.infcx().probe(move |_| {
             match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
                 Ok(obligations) => {
                     self.evaluate_predicates_recursively(stack.list(), obligations.iter())
                 }
-                Err(()) => {
-                    EvaluatedToErr(Unimplemented)
-                }
+                Err(()) => EvaluatedToErr
             }
         })
     }
@@ -1486,37 +1545,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     // attempt to evaluate recursive bounds to see if they are
     // satisfied.
 
-    /// Further evaluate `candidate` to decide whether all type parameters match and whether nested
-    /// obligations are met. Returns true if `candidate` remains viable after this further
-    /// scrutiny.
-    fn winnow_candidate<'o>(&mut self,
-                            stack: &TraitObligationStack<'o, 'tcx>,
-                            candidate: &SelectionCandidate<'tcx>)
-                            -> EvaluationResult<'tcx>
-    {
-        debug!("winnow_candidate: candidate={:?}", candidate);
-        let result = self.infcx.probe(|_| {
-            let candidate = (*candidate).clone();
-            match self.confirm_candidate(stack.obligation, candidate) {
-                Ok(selection) => self.winnow_selection(stack.list(),
-                                                       selection),
-                Err(error) => EvaluatedToErr(error),
-            }
-        });
-        debug!("winnow_candidate depth={} result={:?}",
-               stack.obligation.recursion_depth, result);
-        result
-    }
-
-    fn winnow_selection<'o>(&mut self,
-                            stack: TraitObligationStackList<'o,'tcx>,
-                            selection: Selection<'tcx>)
-                            -> EvaluationResult<'tcx>
-    {
-        self.evaluate_predicates_recursively(stack,
-                                             selection.nested_obligations().iter())
-    }
-
     /// Returns true if `candidate_i` should be dropped in favor of
     /// `candidate_j`.  Generally speaking we will drop duplicate
     /// candidates and prefer where-clause candidates.
@@ -1542,9 +1570,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         "default implementations shouldn't be recorded \
                          when there are other valid candidates");
                 }
-                &PhantomFnCandidate => {
-                    self.tcx().sess.bug("PhantomFn didn't short-circuit selection");
-                }
                 &ImplCandidate(..) |
                 &ClosureCandidate(..) |
                 &FnPointerCandidate(..) |
@@ -1974,7 +1999,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     try!(self.confirm_builtin_candidate(obligation, builtin_bound))))
             }
 
-            PhantomFnCandidate |
             ErrorCandidate => {
                 Ok(VtableBuiltin(VtableBuiltinData { nested: vec![] }))
             }
@@ -2260,6 +2284,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                impl_def_id,
                impl_obligations);
 
+        // Because of RFC447, the impl-trait-ref and obligations
+        // are sufficient to determine the impl substs, without
+        // relying on projections in the impl-trait-ref.
+        //
+        // e.g. `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V`
         impl_obligations.append(&mut substs.obligations);
 
         VtableImplData { impl_def_id: impl_def_id,
@@ -2744,74 +2773,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    /// Determines whether the self type declared against
-    /// `impl_def_id` matches `obligation_self_ty`. If successful,
-    /// returns the substitutions used to make them match. See
-    /// `match_impl()`. For example, if `impl_def_id` is declared
-    /// as:
-    ///
-    ///    impl<T:Copy> Foo for Box<T> { ... }
-    ///
-    /// and `obligation_self_ty` is `int`, we'd get back an `Err(_)`
-    /// result. But if `obligation_self_ty` were `Box<int>`, we'd get
-    /// back `Ok(T=int)`.
-    fn match_inherent_impl(&mut self,
-                           impl_def_id: DefId,
-                           obligation_cause: &ObligationCause,
-                           obligation_self_ty: Ty<'tcx>)
-                           -> Result<Substs<'tcx>,()>
-    {
-        // Create fresh type variables for each type parameter declared
-        // on the impl etc.
-        let impl_substs = util::fresh_type_vars_for_impl(self.infcx,
-                                                         obligation_cause.span,
-                                                         impl_def_id);
-
-        // Find the self type for the impl.
-        let impl_self_ty = self.tcx().lookup_item_type(impl_def_id).ty;
-        let impl_self_ty = impl_self_ty.subst(self.tcx(), &impl_substs);
-
-        debug!("match_impl_self_types(obligation_self_ty={:?}, impl_self_ty={:?})",
-               obligation_self_ty,
-               impl_self_ty);
-
-        match self.match_self_types(obligation_cause,
-                                    impl_self_ty,
-                                    obligation_self_ty) {
-            Ok(()) => {
-                debug!("Matched impl_substs={:?}", impl_substs);
-                Ok(impl_substs)
-            }
-            Err(()) => {
-                debug!("NoMatch");
-                Err(())
-            }
-        }
-    }
-
-    fn match_self_types(&mut self,
-                        cause: &ObligationCause,
-
-                        // The self type provided by the impl/caller-obligation:
-                        provided_self_ty: Ty<'tcx>,
-
-                        // The self type the obligation is for:
-                        required_self_ty: Ty<'tcx>)
-                        -> Result<(),()>
-    {
-        // FIXME(#5781) -- equating the types is stronger than
-        // necessary. Should consider variance of trait w/r/t Self.
-
-        let origin = infer::RelateSelfType(cause.span);
-        match self.infcx.eq_types(false,
-                                  origin,
-                                  provided_self_ty,
-                                  required_self_ty) {
-            Ok(()) => Ok(()),
-            Err(_) => Err(()),
-        }
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // Miscellany
 
@@ -2892,17 +2853,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                  -> Vec<PredicateObligation<'tcx>>
     {
         debug!("impl_or_trait_obligations(def_id={:?})", def_id);
+        let tcx = self.tcx();
 
-        let predicates = self.tcx().lookup_predicates(def_id);
-        let predicates = predicates.instantiate(self.tcx(), substs);
-        let predicates = normalize_with_depth(self, cause.clone(), recursion_depth, &predicates);
-        let mut predicates = self.infcx().plug_leaks(skol_map, snapshot, &predicates);
-        let mut obligations =
-            util::predicates_for_generics(cause,
-                                          recursion_depth,
-                                          &predicates.value);
-        obligations.append(&mut predicates.obligations);
-        obligations
+        // To allow for one-pass evaluation of the nested obligation,
+        // each predicate must be preceded by the obligations required
+        // to normalize it.
+        // for example, if we have:
+        //    impl<U: Iterator, V: Iterator<Item=U>> Foo for V where U::Item: Copy
+        // the impl will have the following predicates:
+        //    <V as Iterator>::Item = U,
+        //    U: Iterator, U: Sized,
+        //    V: Iterator, V: Sized,
+        //    <U as Iterator>::Item: Copy
+        // When we substitute, say, `V => IntoIter<u32>, U => $0`, the last
+        // obligation will normalize to `<$0 as Iterator>::Item = $1` and
+        // `$1: Copy`, so we must ensure the obligations are emitted in
+        // that order.
+        let predicates = tcx
+            .lookup_predicates(def_id)
+            .predicates.iter()
+            .flat_map(|predicate| {
+                let predicate =
+                    normalize_with_depth(self, cause.clone(), recursion_depth,
+                                         &predicate.subst(tcx, substs));
+                predicate.obligations.into_iter().chain(
+                    Some(Obligation {
+                        cause: cause.clone(),
+                        recursion_depth: recursion_depth,
+                        predicate: predicate.value
+                    }))
+            }).collect();
+        self.infcx().plug_leaks(skol_map, snapshot, &predicates)
     }
 
     #[allow(unused_comparisons)]
@@ -2956,6 +2937,14 @@ impl<'tcx> SelectionCache<'tcx> {
     }
 }
 
+impl<'tcx> EvaluationCache<'tcx> {
+    pub fn new() -> EvaluationCache<'tcx> {
+        EvaluationCache {
+            hashmap: RefCell::new(FnvHashMap())
+        }
+    }
+}
+
 impl<'o,'tcx> TraitObligationStack<'o,'tcx> {
     fn list(&'o self) -> TraitObligationStackList<'o,'tcx> {
         TraitObligationStackList::with(self)
@@ -3001,17 +2990,14 @@ impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> {
     }
 }
 
-impl<'tcx> EvaluationResult<'tcx> {
+impl EvaluationResult {
     fn may_apply(&self) -> bool {
         match *self {
             EvaluatedToOk |
             EvaluatedToAmbig |
-            EvaluatedToErr(OutputTypeParameterMismatch(..)) |
-            EvaluatedToErr(TraitNotObjectSafe(_)) =>
-                true,
+            EvaluatedToUnknown => true,
 
-            EvaluatedToErr(Unimplemented) =>
-                false,
+            EvaluatedToErr => false
         }
     }
 }
diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs
index d91cac4cc75..e02a120a5c6 100644
--- a/src/librustc/middle/ty/context.rs
+++ b/src/librustc/middle/ty/context.rs
@@ -332,6 +332,11 @@ pub struct ctxt<'tcx> {
     /// for things that do not have to do with the parameters in scope.
     pub selection_cache: traits::SelectionCache<'tcx>,
 
+    /// Caches the results of trait evaluation. This cache is used
+    /// for things that do not have to do with the parameters in scope.
+    /// Merge this with `selection_cache`?
+    pub evaluation_cache: traits::EvaluationCache<'tcx>,
+
     /// A set of predicates that have been fulfilled *somewhere*.
     /// This is used to avoid duplicate work. Predicates are only
     /// added to this set when they mention only "global" names
@@ -512,6 +517,7 @@ impl<'tcx> ctxt<'tcx> {
             transmute_restrictions: RefCell::new(Vec::new()),
             stability: RefCell::new(stability),
             selection_cache: traits::SelectionCache::new(),
+            evaluation_cache: traits::EvaluationCache::new(),
             repr_hint_cache: RefCell::new(DefIdMap()),
             const_qualif_map: RefCell::new(NodeMap()),
             custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs
index aa189744701..0a9fa1d6ce3 100644
--- a/src/librustc/middle/ty/mod.rs
+++ b/src/librustc/middle/ty/mod.rs
@@ -1091,6 +1091,9 @@ pub struct ParameterEnvironment<'a, 'tcx:'a> {
     /// for things that have to do with the parameters in scope.
     pub selection_cache: traits::SelectionCache<'tcx>,
 
+    /// Caches the results of trait evaluation.
+    pub evaluation_cache: traits::EvaluationCache<'tcx>,
+
     /// Scope that is attached to free regions for this scope. This
     /// is usually the id of the fn body, but for more abstract scopes
     /// like structs we often use the node-id of the struct.
@@ -1112,6 +1115,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
             implicit_region_bound: self.implicit_region_bound,
             caller_bounds: caller_bounds,
             selection_cache: traits::SelectionCache::new(),
+            evaluation_cache: traits::EvaluationCache::new(),
             free_id: self.free_id,
         }
     }
@@ -2584,6 +2588,7 @@ impl<'tcx> ctxt<'tcx> {
                                    caller_bounds: Vec::new(),
                                    implicit_region_bound: ty::ReEmpty,
                                    selection_cache: traits::SelectionCache::new(),
+                                   evaluation_cache: traits::EvaluationCache::new(),
 
                                    // for an empty parameter
                                    // environment, there ARE no free
@@ -2673,6 +2678,7 @@ impl<'tcx> ctxt<'tcx> {
             implicit_region_bound: ty::ReScope(free_id_outlive),
             caller_bounds: predicates,
             selection_cache: traits::SelectionCache::new(),
+            evaluation_cache: traits::EvaluationCache::new(),
             free_id: free_id,
         };
 
diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs
index 176dc5a743d..41303b46dfd 100644
--- a/src/librustc/middle/ty/structural_impls.rs
+++ b/src/librustc/middle/ty/structural_impls.rs
@@ -822,6 +822,7 @@ impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where '
             implicit_region_bound: self.implicit_region_bound.fold_with(folder),
             caller_bounds: self.caller_bounds.fold_with(folder),
             selection_cache: traits::SelectionCache::new(),
+            evaluation_cache: traits::EvaluationCache::new(),
             free_id: self.free_id,
         }
     }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 30eb468d9f8..185623a4402 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -775,31 +775,33 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                       ref impl_items) => {
             // Create generics from the generics specified in the impl head.
             debug!("convert: ast_generics={:?}", generics);
+            let def_id = ccx.tcx.map.local_def_id(it.id);
             let ty_generics = ty_generics_for_type_or_impl(ccx, generics);
-            let ty_predicates = ty_generic_predicates_for_type_or_impl(ccx, generics);
+            let mut ty_predicates = ty_generic_predicates_for_type_or_impl(ccx, generics);
 
             debug!("convert: impl_bounds={:?}", ty_predicates);
 
             let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &**selfty);
             write_ty_to_tcx(tcx, it.id, selfty);
 
-            tcx.register_item_type(ccx.tcx.map.local_def_id(it.id),
+            tcx.register_item_type(def_id,
                                    TypeScheme { generics: ty_generics.clone(),
                                                 ty: selfty });
-            tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
-                                               ty_predicates.clone());
             if let &Some(ref ast_trait_ref) = opt_trait_ref {
                 tcx.impl_trait_refs.borrow_mut().insert(
-                    ccx.tcx.map.local_def_id(it.id),
+                    def_id,
                     Some(astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
                                                              &ExplicitRscope,
                                                              ast_trait_ref,
                                                              Some(selfty)))
                         );
             } else {
-                tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), None);
+                tcx.impl_trait_refs.borrow_mut().insert(def_id, None);
             }
 
+            enforce_impl_params_are_constrained(tcx, generics, &mut ty_predicates, def_id);
+            tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
+
 
             // If there is a trait reference, treat the methods as always public.
             // This is to work around some incorrect behavior in privacy checking:
@@ -844,7 +846,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                                                generics: ty_generics.clone(),
                                                ty: ty,
                                            });
-                    convert_associated_const(ccx, ImplContainer(ccx.tcx.map.local_def_id(it.id)),
+                    convert_associated_const(ccx, ImplContainer(def_id),
                                              impl_item.name, impl_item.id,
                                              impl_item.vis.inherit_from(parent_visibility),
                                              ty, true /* has_value */);
@@ -861,7 +863,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
                     let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
 
-                    convert_associated_type(ccx, ImplContainer(ccx.tcx.map.local_def_id(it.id)),
+                    convert_associated_type(ccx, ImplContainer(def_id),
                                             impl_item.name, impl_item.id, impl_item.vis,
                                             Some(typ));
                 }
@@ -880,7 +882,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                 }
             });
             convert_methods(ccx,
-                            ImplContainer(ccx.tcx.map.local_def_id(it.id)),
+                            ImplContainer(def_id),
                             methods,
                             selfty,
                             &ty_generics,
@@ -898,10 +900,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                 }
             }
 
-            enforce_impl_params_are_constrained(tcx,
-                                                generics,
-                                                ccx.tcx.map.local_def_id(it.id),
-                                                impl_items);
+            enforce_impl_lifetimes_are_constrained(tcx, generics, def_id, impl_items);
         },
         hir::ItemTrait(_, _, _, ref trait_items) => {
             let trait_def = trait_def_of_item(ccx, it);
@@ -2377,13 +2376,15 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
 /// Checks that all the type parameters on an impl
 fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
                                              ast_generics: &hir::Generics,
-                                             impl_def_id: DefId,
-                                             impl_items: &[P<hir::ImplItem>])
+                                             impl_predicates: &mut ty::GenericPredicates<'tcx>,
+                                             impl_def_id: DefId)
 {
     let impl_scheme = tcx.lookup_item_type(impl_def_id);
-    let impl_predicates = tcx.lookup_predicates(impl_def_id);
     let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
 
+    assert!(impl_predicates.predicates.is_empty_in(FnSpace));
+    assert!(impl_predicates.predicates.is_empty_in(SelfSpace));
+
     // The trait reference is an input, so find all type parameters
     // reachable from there, to start (if this is an inherent impl,
     // then just examine the self type).
@@ -2393,10 +2394,10 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
         input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref));
     }
 
-    ctp::identify_constrained_type_params(tcx,
-                                          impl_predicates.predicates.as_slice(),
-                                          impl_trait_ref,
-                                          &mut input_parameters);
+    ctp::setup_constraining_predicates(tcx,
+                                       impl_predicates.predicates.get_mut_slice(TypeSpace),
+                                       impl_trait_ref,
+                                       &mut input_parameters);
 
     for (index, ty_param) in ast_generics.ty_params.iter().enumerate() {
         let param_ty = ty::ParamTy { space: TypeSpace,
@@ -2406,8 +2407,25 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
             report_unused_parameter(tcx, ty_param.span, "type", &param_ty.to_string());
         }
     }
+}
 
+fn enforce_impl_lifetimes_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                                ast_generics: &hir::Generics,
+                                                impl_def_id: DefId,
+                                                impl_items: &[P<hir::ImplItem>])
+{
     // Every lifetime used in an associated type must be constrained.
+    let impl_scheme = tcx.lookup_item_type(impl_def_id);
+    let impl_predicates = tcx.lookup_predicates(impl_def_id);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+
+    let mut input_parameters: HashSet<_> =
+        ctp::parameters_for_type(impl_scheme.ty).into_iter().collect();
+    if let Some(ref trait_ref) = impl_trait_ref {
+        input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref));
+    }
+    ctp::identify_constrained_type_params(tcx,
+        &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
 
     let lifetimes_in_associated_types: HashSet<_> =
         impl_items.iter()
diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs
index 7844d71462c..39d5872b3dc 100644
--- a/src/librustc_typeck/constrained_type_params.rs
+++ b/src/librustc_typeck/constrained_type_params.rs
@@ -84,40 +84,92 @@ pub fn identify_constrained_type_params<'tcx>(_tcx: &ty::ctxt<'tcx>,
                                               impl_trait_ref: Option<ty::TraitRef<'tcx>>,
                                               input_parameters: &mut HashSet<Parameter>)
 {
-    loop {
-        let num_inputs = input_parameters.len();
-
-        let poly_projection_predicates = // : iterator over PolyProjectionPredicate
-            predicates.iter()
-                      .filter_map(|predicate| {
-                          match *predicate {
-                              ty::Predicate::Projection(ref data) => Some(data.clone()),
-                              _ => None,
-                          }
-                      });
-
-        for poly_projection in poly_projection_predicates {
-            // Note that we can skip binder here because the impl
-            // trait ref never contains any late-bound regions.
-            let projection = poly_projection.skip_binder();
-
-            // Special case: watch out for some kind of sneaky attempt
-            // to project out an associated type defined by this very
-            // trait.
-            let unbound_trait_ref = &projection.projection_ty.trait_ref;
-            if Some(unbound_trait_ref.clone()) == impl_trait_ref {
-                continue;
-            }
+    let mut predicates = predicates.to_owned();
+    setup_constraining_predicates(_tcx, &mut predicates, impl_trait_ref, input_parameters);
+}
+
 
-            let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref);
-            let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
-            if relies_only_on_inputs {
+/// Order the predicates in `predicates` such that each parameter is
+/// constrained before it is used, if that is possible, and add the
+/// paramaters so constrained to `input_parameters`. For example,
+/// imagine the following impl:
+///
+///     impl<T: Debug, U: Iterator<Item=T>> Trait for U
+///
+/// The impl's predicates are collected from left to right. Ignoring
+/// the implicit `Sized` bounds, these are
+///   * T: Debug
+///   * U: Iterator
+///   * <U as Iterator>::Item = T -- a desugared ProjectionPredicate
+///
+/// When we, for example, try to go over the trait-reference
+/// `IntoIter<u32> as Trait`, we substitute the impl parameters with fresh
+/// variables and match them with the impl trait-ref, so we know that
+/// `$U = IntoIter<u32>`.
+///
+/// However, in order to process the `$T: Debug` predicate, we must first
+/// know the value of `$T` - which is only given by processing the
+/// projection. As we occasionally want to process predicates in a single
+/// pass, we want the projection to come first. In fact, as projections
+/// can (acyclically) depend on one another - see RFC447 for details - we
+/// need to topologically sort them.
+pub fn setup_constraining_predicates<'tcx>(_tcx: &ty::ctxt<'tcx>,
+                                           predicates: &mut [ty::Predicate<'tcx>],
+                                           impl_trait_ref: Option<ty::TraitRef<'tcx>>,
+                                           input_parameters: &mut HashSet<Parameter>)
+{
+    // The canonical way of doing the needed topological sort
+    // would be a DFS, but getting the graph and its ownership
+    // right is annoying, so I am using an in-place fixed-point iteration,
+    // which is `O(nt)` where `t` is the depth of type-parameter constraints,
+    // remembering that `t` should be less than 7 in practice.
+    //
+    // Basically, I iterate over all projections and swap every
+    // "ready" projection to the start of the list, such that
+    // all of the projections before `i` are topologically sorted
+    // and constrain all the parameters in `input_parameters`.
+    //
+    // In the example, `input_parameters` starts by containing `U` - which
+    // is constrained by the trait-ref - and so on the first pass we
+    // observe that `<U as Iterator>::Item = T` is a "ready" projection that
+    // constrains `T` and swap it to front. As it is the sole projection,
+    // no more swaps can take place afterwards, with the result being
+    //   * <U as Iterator>::Item = T
+    //   * T: Debug
+    //   * U: Iterator
+    let mut i = 0;
+    let mut changed = true;
+    while changed {
+        changed = false;
+
+        for j in i..predicates.len() {
+
+            if let ty::Predicate::Projection(ref poly_projection) = predicates[j] {
+                // Note that we can skip binder here because the impl
+                // trait ref never contains any late-bound regions.
+                let projection = poly_projection.skip_binder();
+
+                // Special case: watch out for some kind of sneaky attempt
+                // to project out an associated type defined by this very
+                // trait.
+                let unbound_trait_ref = &projection.projection_ty.trait_ref;
+                if Some(unbound_trait_ref.clone()) == impl_trait_ref {
+                    continue;
+                }
+
+                let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref);
+                let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
+                if !relies_only_on_inputs {
+                    continue;
+                }
                 input_parameters.extend(parameters_for_type(projection.ty));
+            } else {
+                continue;
             }
-        }
-
-        if input_parameters.len() == num_inputs {
-            break;
+            // fancy control flow to bypass borrow checker
+            predicates.swap(i, j);
+            i += 1;
+            changed = true;
         }
     }
 }
diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs
index 4603ed00347..d14b0fa9e66 100644
--- a/src/test/compile-fail/cast-rfc0401.rs
+++ b/src/test/compile-fail/cast-rfc0401.rs
@@ -37,6 +37,7 @@ fn main()
     let f: f32 = 1.2;
     let v = 0 as *const u8;
     let fat_v : *const [u8] = unsafe { &*(0 as *const [u8; 1])};
+    let fat_sv : *const [i8] = unsafe { &*(0 as *const [i8; 1])};
     let foo: &Foo = &f;
 
     let _ = v as &u8; //~ ERROR non-scalar
@@ -94,7 +95,7 @@ fn main()
     let _ = main as *mut str; //~ ERROR casting
     let _ = &f as *mut f32; //~ ERROR casting
     let _ = &f as *const f64; //~ ERROR casting
-    let _ = fat_v as usize;
+    let _ = fat_sv as usize;
     //~^ ERROR casting
     //~^^ HELP through a thin pointer first
 
@@ -106,7 +107,7 @@ fn main()
     let _ = main.f as *const u32; //~ ERROR attempted access of field
 
     let cf: *const Foo = &0;
-    let _ = cf as *const [u8];
+    let _ = cf as *const [u16];
     //~^ ERROR casting
     //~^^ NOTE vtable kinds
     let _ = cf as *const Bar;
diff --git a/src/test/compile-fail/infinite-instantiation.rs b/src/test/compile-fail/infinite-instantiation.rs
index 9b02bf4cb85..28806b6e2ab 100644
--- a/src/test/compile-fail/infinite-instantiation.rs
+++ b/src/test/compile-fail/infinite-instantiation.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//~^^^^^^^^^^ ERROR overflow
 //
 // We get an error message at the top of file (dummy span).
 // This is not helpful, but also kind of annoying to prevent,
@@ -32,6 +31,7 @@ impl<T:Clone> ToOpt for Option<T> {
 }
 
 fn function<T:ToOpt + Clone>(counter: usize, t: T) {
+//~^ ERROR reached the recursion limit during monomorphization
     if counter > 0 {
         function(counter - 1, t.to_option());
         // FIXME(#4287) Error message should be here. It should be
diff --git a/src/test/compile-fail/issue-29147.rs b/src/test/compile-fail/issue-29147.rs
new file mode 100644
index 00000000000..64bfa232f3f
--- /dev/null
+++ b/src/test/compile-fail/issue-29147.rs
@@ -0,0 +1,32 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![recursion_limit="1024"]
+
+pub struct S0<T>(T,T);
+pub struct S1<T>(Option<Box<S0<S0<T>>>>,Option<Box<S0<S0<T>>>>);
+pub struct S2<T>(Option<Box<S1<S1<T>>>>,Option<Box<S1<S1<T>>>>);
+pub struct S3<T>(Option<Box<S2<S2<T>>>>,Option<Box<S2<S2<T>>>>);
+pub struct S4<T>(Option<Box<S3<S3<T>>>>,Option<Box<S3<S3<T>>>>);
+pub struct S5<T>(Option<Box<S4<S4<T>>>>,Option<Box<S4<S4<T>>>>,Option<T>);
+
+trait Foo { fn xxx(&self); }
+trait Bar {} // anything local or #[fundamental]
+
+impl<T> Foo for T where T: Bar, T: Sync {
+    fn xxx(&self) {}
+}
+
+impl Foo for S5<u32> { fn xxx(&self) {} }
+impl Foo for S5<u64> { fn xxx(&self) {} }
+
+fn main() {
+    let _ = <S5<_>>::xxx; //~ ERROR cannot resolve `S5<_> : Foo`
+}
diff --git a/src/test/compile-fail/recursion.rs b/src/test/compile-fail/recursion.rs
index 55f3b995336..b1d45a82276 100644
--- a/src/test/compile-fail/recursion.rs
+++ b/src/test/compile-fail/recursion.rs
@@ -8,12 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//~^^^^^^^^^^ ERROR overflow
-//
-// We get an error message at the top of file (dummy span).
-// This is not helpful, but also kind of annoying to prevent,
-// so for now just live with it.
-
 enum Nil {NilValue}
 struct Cons<T> {head:isize, tail:T}
 trait Dot {fn dot(&self, other:Self) -> isize;}
@@ -26,7 +20,7 @@ impl<T:Dot> Dot for Cons<T> {
   }
 }
 fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize {
-  match n {    0 => {first.dot(second)}
+  match n {    0 => {first.dot(second)} //~ ERROR overflow
       // FIXME(#4287) Error message should be here. It should be
       // a type error to instantiate `test` at a type other than T.
     _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})}
diff --git a/src/test/run-pass/coherence-rfc447-constrained.rs b/src/test/run-pass/coherence-rfc447-constrained.rs
new file mode 100644
index 00000000000..4b52378e508
--- /dev/null
+++ b/src/test/run-pass/coherence-rfc447-constrained.rs
@@ -0,0 +1,31 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that trait matching can handle impls whose types are only
+// constrained by a projection.
+
+trait IsU32 {}
+impl IsU32 for u32 {}
+
+trait Mirror { type Image: ?Sized; }
+impl<T: ?Sized> Mirror for T { type Image = T; }
+
+trait Bar {}
+impl<U: Mirror, V: Mirror<Image=L>, L: Mirror<Image=U>> Bar for V
+    where U::Image: IsU32 {}
+
+trait Foo { fn name() -> &'static str; }
+impl Foo for u64 { fn name() -> &'static str { "u64" } }
+impl<T: Bar> Foo for T { fn name() -> &'static str { "Bar" }}
+
+fn main() {
+    assert_eq!(<u64 as Foo>::name(), "u64");
+    assert_eq!(<u32 as Foo>::name(), "Bar");
+}
diff --git a/src/test/run-pass/issue-29147.rs b/src/test/run-pass/issue-29147.rs
new file mode 100644
index 00000000000..026b98905d0
--- /dev/null
+++ b/src/test/run-pass/issue-29147.rs
@@ -0,0 +1,36 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![recursion_limit="1024"]
+
+use std::mem;
+
+pub struct S0<T>(T,T);
+pub struct S1<T>(Option<Box<S0<S0<T>>>>,Option<Box<S0<S0<T>>>>);
+pub struct S2<T>(Option<Box<S1<S1<T>>>>,Option<Box<S1<S1<T>>>>);
+pub struct S3<T>(Option<Box<S2<S2<T>>>>,Option<Box<S2<S2<T>>>>);
+pub struct S4<T>(Option<Box<S3<S3<T>>>>,Option<Box<S3<S3<T>>>>);
+pub struct S5<T>(Option<Box<S4<S4<T>>>>,Option<Box<S4<S4<T>>>>,Option<T>);
+
+trait Foo { fn xxx(&self); }
+/// some local of #[fundamental] trait
+trait Bar {}
+
+impl<T> Foo for T where T: Bar, T: Sync {
+    fn xxx(&self) {}
+}
+
+impl Foo for S5<u8> { fn xxx(&self) {} }
+
+fn main() {
+    let s = S5(None,None,None);
+    s.xxx();
+    assert_eq!(mem::size_of_val(&s.2), mem::size_of::<Option<u8>>());
+}
diff --git a/src/test/run-pass/trait-copy-guessing.rs b/src/test/run-pass/trait-copy-guessing.rs
new file mode 100644
index 00000000000..71cd3c9441e
--- /dev/null
+++ b/src/test/run-pass/trait-copy-guessing.rs
@@ -0,0 +1,46 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// "guessing" in trait selection can affect `copy_or_move`. Check that this
+// is correctly handled. I am not sure what is the "correct" behaviour,
+// but we should at least not ICE.
+
+use std::mem;
+
+struct U([u8; 1337]);
+
+struct S<'a,T:'a>(&'a T);
+impl<'a, T> Clone for S<'a, T> { fn clone(&self) -> Self { S(self.0) } }
+/// This impl triggers inference "guessing" - S<_>: Copy => _ = U
+impl<'a> Copy for S<'a, Option<U>> {}
+
+fn assert_impls_fn<R,T: Fn()->R>(_: &T){}
+
+fn main() {
+    let n = None;
+    let e = S(&n);
+    let f = || {
+        // S being copy is critical for this to work
+        drop(e);
+        mem::size_of_val(e.0)
+    };
+    assert_impls_fn(&f);
+    assert_eq!(f(), 1337+1);
+
+    assert_eq!((|| {
+        // S being Copy is not critical here, but
+        // we check it anyway.
+        let n = None;
+        let e = S(&n);
+        let ret = mem::size_of_val(e.0);
+        drop(e);
+        ret
+    })(), 1337+1);
+}