about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/traits/mod.rs98
-rw-r--r--src/librustc/middle/traits/project.rs44
-rw-r--r--src/librustc/middle/traits/select.rs72
-rw-r--r--src/librustc/middle/traits/util.rs21
-rw-r--r--src/librustc/middle/ty_fold.rs14
-rw-r--r--src/librustc_trans/trans/meth.rs12
-rw-r--r--src/test/compile-fail/issue-25700.rs24
-rw-r--r--src/test/run-pass/issue-25700-1.rs22
-rw-r--r--src/test/run-pass/issue-25700-2.rs31
9 files changed, 231 insertions, 107 deletions
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 50536f586e7..b4b53c003ea 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -245,7 +245,7 @@ pub enum Vtable<'tcx, N> {
     /// Vtable automatically generated for a closure. The def ID is the ID
     /// of the closure expression. This is a `VtableImpl` in spirit, but the
     /// impl is generated by the compiler and does not appear in the source.
-    VtableClosure(ast::DefId, subst::Substs<'tcx>),
+    VtableClosure(VtableClosureData<'tcx, N>),
 
     /// Same as above, but for a fn pointer type with the given signature.
     VtableFnPointer(ty::Ty<'tcx>),
@@ -268,7 +268,16 @@ pub struct VtableImplData<'tcx, N> {
     pub nested: Vec<N>
 }
 
-#[derive(Debug,Clone)]
+#[derive(Clone, PartialEq, Eq)]
+pub struct VtableClosureData<'tcx, N> {
+    pub closure_def_id: ast::DefId,
+    pub substs: subst::Substs<'tcx>,
+    /// Nested obligations. This can be non-empty if the closure
+    /// signature contains associated types.
+    pub nested: Vec<N>
+}
+
+#[derive(Debug, Clone)]
 pub struct VtableDefaultImplData<N> {
     pub trait_def_id: ast::DefId,
     pub nested: Vec<N>
@@ -304,12 +313,12 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
 /// `bound` or is not known to meet bound (note that this is
 /// conservative towards *no impl*, which is the opposite of the
 /// `evaluate` methods).
-pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
-                                       typer: &ty::ClosureTyper<'tcx>,
-                                       ty: Ty<'tcx>,
-                                       bound: ty::BuiltinBound,
-                                       span: Span)
-                                       -> SelectionResult<'tcx, ()>
+pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
+                                                 typer: &ty::ClosureTyper<'tcx>,
+                                                 ty: Ty<'tcx>,
+                                                 bound: ty::BuiltinBound,
+                                                 span: Span)
+                                                 -> bool
 {
     debug!("type_known_to_meet_builtin_bound(ty={}, bound={:?})",
            ty.repr(infcx.tcx),
@@ -327,61 +336,18 @@ pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
     // 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.
-    let result = match fulfill_cx.select_all_or_error(infcx, typer) {
-        Ok(()) => Ok(Some(())), // Success, we know it implements Copy.
-        Err(errors) => {
-            // If there were any hard errors, propagate an arbitrary
-            // one of those. If no hard errors at all, report
-            // ambiguity.
-            let sel_error =
-                errors.iter()
-                      .filter_map(|err| {
-                          match err.code {
-                              CodeAmbiguity => None,
-                              CodeSelectionError(ref e) => Some(e.clone()),
-                              CodeProjectionError(_) => {
-                                  infcx.tcx.sess.span_bug(
-                                      span,
-                                      "projection error while selecting?")
-                              }
-                          }
-                      })
-                      .next();
-            match sel_error {
-                None => { Ok(None) }
-                Some(e) => { Err(e) }
-            }
-        }
-    };
-
-    debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} result={:?}",
-           ty.repr(infcx.tcx),
-           bound,
-           result);
-
-    result
-}
-
-pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
-                                                 typer: &ty::ClosureTyper<'tcx>,
-                                                 ty: Ty<'tcx>,
-                                                 bound: ty::BuiltinBound,
-                                                 span: Span)
-                                                 -> bool
-{
-    match evaluate_builtin_bound(infcx, typer, ty, bound, span) {
-        Ok(Some(())) => {
-            // definitely impl'd
+    match fulfill_cx.select_all_or_error(infcx, typer) {
+        Ok(()) => {
+            debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} success",
+                   ty.repr(infcx.tcx),
+                   bound);
             true
         }
-        Ok(None) => {
-            // ambiguous: if coherence check was successful, shouldn't
-            // happen, but we might have reported an error and been
-            // soldering on, so just treat this like not implemented
-            false
-        }
-        Err(_) => {
-            // errors: not implemented.
+        Err(e) => {
+            debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} errors={}",
+                   ty.repr(infcx.tcx),
+                   bound,
+                   e.repr(infcx.tcx));
             false
         }
     }
@@ -545,8 +511,8 @@ impl<'tcx, N> Vtable<'tcx, N> {
             VtableParam(n) => n,
             VtableBuiltin(i) => i.nested,
             VtableDefaultImpl(d) => d.nested,
-            VtableObject(_) | VtableFnPointer(..) |
-            VtableClosure(..) => vec![]
+            VtableClosure(c) => c.nested,
+            VtableObject(_) | VtableFnPointer(..) => vec![]
         }
     }
 
@@ -567,7 +533,11 @@ impl<'tcx, N> Vtable<'tcx, N> {
                 nested: d.nested.into_iter().map(f).collect()
             }),
             VtableFnPointer(f) => VtableFnPointer(f),
-            VtableClosure(d, s) => VtableClosure(d, s),
+            VtableClosure(c) => VtableClosure(VtableClosureData {
+                closure_def_id: c.closure_def_id,
+                substs: c.substs,
+                nested: c.nested.into_iter().map(f).collect()
+            })
         }
     }
 }
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index 7915f9a8bdf..71946aa79ce 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -17,15 +17,15 @@ use super::ObligationCause;
 use super::PredicateObligation;
 use super::SelectionContext;
 use super::SelectionError;
+use super::VtableClosureData;
 use super::VtableImplData;
 use super::util;
 
 use middle::infer;
-use middle::subst::{Subst, Substs};
+use middle::subst::Subst;
 use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
                  HasProjectionTypes, ToPolyTraitRef, Ty};
 use middle::ty_fold::{self, TypeFoldable, TypeFolder};
-use syntax::ast;
 use syntax::parse::token;
 use util::common::FN_OUTPUT_NAME;
 use util::ppaux::Repr;
@@ -57,7 +57,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
 enum ProjectionTyCandidate<'tcx> {
     ParamEnv(ty::PolyProjectionPredicate<'tcx>),
     Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
-    Closure(ast::DefId, Substs<'tcx>),
+    Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>),
     FnPointer(Ty<'tcx>),
 }
 
@@ -162,11 +162,16 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext
                                                         self_ty,
                                                         &closure_type.sig,
                                                         util::TupleArgumentsFlag::No);
+            // We don't have to normalize the return type here - this is only
+            // reached for TyClosure: Fn inputs where the closure kind is
+            // still unknown, which should only occur in typeck where the
+            // closure type is already normalized.
             let (ret_type, _) =
                 infcx.replace_late_bound_regions_with_fresh_var(
                     obligation.cause.span,
                     infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name),
                     &ty::Binder(ret_type));
+
             debug!("consider_unification_despite_ambiguity: ret_type={:?}",
                    ret_type.repr(selcx.tcx()));
             let origin = infer::RelateOutputImplTypes(obligation.cause.span);
@@ -686,9 +691,9 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
                 selcx, obligation, obligation_trait_ref, candidate_set,
                 data.object_ty);
         }
-        super::VtableClosure(closure_def_id, substs) => {
+        super::VtableClosure(data) => {
             candidate_set.vec.push(
-                ProjectionTyCandidate::Closure(closure_def_id, substs));
+                ProjectionTyCandidate::Closure(data));
         }
         super::VtableFnPointer(fn_type) => {
             candidate_set.vec.push(
@@ -755,8 +760,8 @@ fn confirm_candidate<'cx,'tcx>(
             confirm_impl_candidate(selcx, obligation, impl_vtable)
         }
 
-        ProjectionTyCandidate::Closure(def_id, substs) => {
-            confirm_closure_candidate(selcx, obligation, def_id, &substs)
+        ProjectionTyCandidate::Closure(closure_vtable) => {
+            confirm_closure_candidate(selcx, obligation, closure_vtable)
         }
 
         ProjectionTyCandidate::FnPointer(fn_type) => {
@@ -779,13 +784,24 @@ fn confirm_fn_pointer_candidate<'cx,'tcx>(
 fn confirm_closure_candidate<'cx,'tcx>(
     selcx: &mut SelectionContext<'cx,'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    closure_def_id: ast::DefId,
-    substs: &Substs<'tcx>)
+    vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>)
     -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
 {
     let closure_typer = selcx.closure_typer();
-    let closure_type = closure_typer.closure_type(closure_def_id, substs);
-    confirm_callable_candidate(selcx, obligation, &closure_type.sig, util::TupleArgumentsFlag::No)
+    let closure_type = closure_typer.closure_type(vtable.closure_def_id, &vtable.substs);
+    let Normalized {
+        value: closure_type,
+        mut obligations
+    } = normalize_with_depth(selcx,
+                             obligation.cause.clone(),
+                             obligation.recursion_depth+1,
+                             &closure_type);
+    let (ty, mut cc_obligations) = confirm_callable_candidate(selcx,
+                                                              obligation,
+                                                              &closure_type.sig,
+                                                              util::TupleArgumentsFlag::No);
+    obligations.append(&mut cc_obligations);
+    (ty, obligations)
 }
 
 fn confirm_callable_candidate<'cx,'tcx>(
@@ -797,7 +813,7 @@ fn confirm_callable_candidate<'cx,'tcx>(
 {
     let tcx = selcx.tcx();
 
-    debug!("confirm_closure_candidate({},{})",
+    debug!("confirm_callable_candidate({},{})",
            obligation.repr(tcx),
            fn_sig.repr(tcx));
 
@@ -921,8 +937,8 @@ impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
                 format!("ParamEnv({})", data.repr(tcx)),
             ProjectionTyCandidate::Impl(ref data) =>
                 format!("Impl({})", data.repr(tcx)),
-            ProjectionTyCandidate::Closure(ref a, ref b) =>
-                format!("Closure(({},{}))", a.repr(tcx), b.repr(tcx)),
+            ProjectionTyCandidate::Closure(ref data) =>
+                format!("Closure({})", data.repr(tcx)),
             ProjectionTyCandidate::FnPointer(a) =>
                 format!("FnPointer(({}))", a.repr(tcx)),
         }
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 211839fbd25..8e2a90aa808 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -31,7 +31,8 @@ use super::Selection;
 use super::SelectionResult;
 use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
             VtableFnPointer, VtableObject, VtableDefaultImpl};
-use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableDefaultImplData};
+use super::{VtableImplData, VtableObjectData, VtableBuiltinData,
+            VtableClosureData, VtableDefaultImplData};
 use super::object_safety;
 use super::util;
 
@@ -355,7 +356,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         };
         assert!(!substs.has_escaping_regions());
 
-        let closure_trait_ref = self.closure_trait_ref(obligation, closure_def_id, substs);
+        // It is OK to call the unnormalized variant here - this is only
+        // reached for TyClosure: Fn inputs where the closure kind is
+        // still unknown, which should only occur in typeck where the
+        // closure type is already normalized.
+        let closure_trait_ref = self.closure_trait_ref_unnormalized(obligation,
+                                                                    closure_def_id,
+                                                                    substs);
+
         match self.confirm_poly_trait_refs(obligation.cause.clone(),
                                            obligation.predicate.to_poly_trait_ref(),
                                            closure_trait_ref) {
@@ -2001,8 +2009,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             ClosureCandidate(closure_def_id, substs) => {
-                try!(self.confirm_closure_candidate(obligation, closure_def_id, &substs));
-                Ok(VtableClosure(closure_def_id, substs))
+                let vtable_closure =
+                    try!(self.confirm_closure_candidate(obligation, closure_def_id, &substs));
+                Ok(VtableClosure(vtable_closure))
             }
 
             BuiltinObjectCandidate => {
@@ -2343,24 +2352,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                  obligation: &TraitObligation<'tcx>,
                                  closure_def_id: ast::DefId,
                                  substs: &Substs<'tcx>)
-                                 -> Result<(),SelectionError<'tcx>>
+                                 -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>,
+                                           SelectionError<'tcx>>
     {
         debug!("confirm_closure_candidate({},{},{})",
                obligation.repr(self.tcx()),
                closure_def_id.repr(self.tcx()),
                substs.repr(self.tcx()));
 
-        let trait_ref = self.closure_trait_ref(obligation,
-                                               closure_def_id,
-                                               substs);
+        let Normalized {
+            value: trait_ref,
+            obligations
+        } = self.closure_trait_ref(obligation, closure_def_id, substs);
 
-        debug!("confirm_closure_candidate(closure_def_id={}, trait_ref={})",
+        debug!("confirm_closure_candidate(closure_def_id={}, trait_ref={}, obligations={})",
                closure_def_id.repr(self.tcx()),
-               trait_ref.repr(self.tcx()));
+               trait_ref.repr(self.tcx()),
+               obligations.repr(self.tcx()));
+
+        try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
+                                          obligation.predicate.to_poly_trait_ref(),
+                                          trait_ref));
 
-        self.confirm_poly_trait_refs(obligation.cause.clone(),
-                                     obligation.predicate.to_poly_trait_ref(),
-                                     trait_ref)
+        Ok(VtableClosureData {
+            closure_def_id: closure_def_id,
+            substs: substs.clone(),
+            nested: obligations
+        })
     }
 
     /// In the case of closure types and fn pointers,
@@ -2819,11 +2837,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    fn closure_trait_ref(&self,
-                         obligation: &TraitObligation<'tcx>,
-                         closure_def_id: ast::DefId,
-                         substs: &Substs<'tcx>)
-                         -> ty::PolyTraitRef<'tcx>
+    fn closure_trait_ref_unnormalized(&mut self,
+                                      obligation: &TraitObligation<'tcx>,
+                                      closure_def_id: ast::DefId,
+                                      substs: &Substs<'tcx>)
+                                      -> ty::PolyTraitRef<'tcx>
     {
         let closure_type = self.closure_typer.closure_type(closure_def_id, substs);
         let ty::Binder((trait_ref, _)) =
@@ -2832,7 +2850,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                                     obligation.predicate.0.self_ty(), // (1)
                                                     &closure_type.sig,
                                                     util::TupleArgumentsFlag::No);
-
         // (1) Feels icky to skip the binder here, but OTOH we know
         // that the self-type is an unboxed closure type and hence is
         // in fact unparameterized (or at least does not reference any
@@ -2842,6 +2859,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         ty::Binder(trait_ref)
     }
 
+    fn closure_trait_ref(&mut self,
+                         obligation: &TraitObligation<'tcx>,
+                         closure_def_id: ast::DefId,
+                         substs: &Substs<'tcx>)
+                         -> Normalized<'tcx, ty::PolyTraitRef<'tcx>>
+    {
+        let trait_ref = self.closure_trait_ref_unnormalized(
+            obligation, closure_def_id, substs);
+
+        // A closure signature can contain associated types which
+        // must be normalized.
+        normalize_with_depth(self,
+                             obligation.cause.clone(),
+                             obligation.recursion_depth+1,
+                             &trait_ref)
+    }
+
     /// Returns the obligations that are implied by instantiating an
     /// impl or trait. The obligations are substituted and fully
     /// normalized. This is used when confirming an impl or default
diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs
index a864ba4498f..c1205d4a46d 100644
--- a/src/librustc/middle/traits/util.rs
+++ b/src/librustc/middle/traits/util.rs
@@ -308,6 +308,12 @@ impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> {
     }
 }
 
+impl<'tcx, N> fmt::Debug for super::VtableClosureData<'tcx, N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "VtableClosure({:?})", self.closure_def_id)
+    }
+}
+
 impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "VtableObject(...)")
@@ -497,10 +503,8 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
             super::VtableDefaultImpl(ref t) =>
                 t.repr(tcx),
 
-            super::VtableClosure(ref d, ref s) =>
-                format!("VtableClosure({},{})",
-                        d.repr(tcx),
-                        s.repr(tcx)),
+            super::VtableClosure(ref d) =>
+                d.repr(tcx),
 
             super::VtableFnPointer(ref d) =>
                 format!("VtableFnPointer({})",
@@ -529,6 +533,15 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableImplData<'tcx, N> {
     }
 }
 
+impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableClosureData<'tcx, N> {
+    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+        format!("VtableClosure(closure_def_id={}, substs={}, nested={})",
+                self.closure_def_id.repr(tcx),
+                self.substs.repr(tcx),
+                self.nested.repr(tcx))
+    }
+}
+
 impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableBuiltinData<N> {
     fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
         format!("VtableBuiltin(nested={})",
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 38391438298..cc91ccbfbd4 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -479,6 +479,16 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<
     }
 }
 
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
+    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableClosureData<'tcx, N> {
+        traits::VtableClosureData {
+            closure_def_id: self.closure_def_id,
+            substs: self.substs.fold_with(folder),
+            nested: self.nested.fold_with(folder),
+        }
+    }
+}
+
 impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
     fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
         traits::VtableDefaultImplData {
@@ -501,8 +511,8 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
         match *self {
             traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
             traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
-            traits::VtableClosure(d, ref s) => {
-                traits::VtableClosure(d, s.fold_with(folder))
+            traits::VtableClosure(ref d) => {
+                traits::VtableClosure(d.fold_with(folder))
             }
             traits::VtableFnPointer(ref d) => {
                 traits::VtableFnPointer(d.fold_with(folder))
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 0dc1cca85fb..7827771994f 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -359,13 +359,13 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
             Callee { bcx: bcx, data: Fn(llfn) }
         }
-        traits::VtableClosure(closure_def_id, substs) => {
+        traits::VtableClosure(vtable_closure) => {
             // The substitutions should have no type parameters remaining
             // after passing through fulfill_obligation
             let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
             let llfn = closure::trans_closure_method(bcx.ccx(),
-                                                     closure_def_id,
-                                                     substs,
+                                                     vtable_closure.closure_def_id,
+                                                     vtable_closure.substs,
                                                      MethodCallKey(method_call),
                                                      bcx.fcx.param_substs,
                                                      trait_closure_kind);
@@ -716,7 +716,11 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     nested: _ }) => {
                 emit_vtable_methods(ccx, id, substs, param_substs).into_iter()
             }
-            traits::VtableClosure(closure_def_id, substs) => {
+            traits::VtableClosure(
+                traits::VtableClosureData {
+                    closure_def_id,
+                    substs,
+                    nested: _ }) => {
                 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
                 let llfn = closure::trans_closure_method(ccx,
                                                          closure_def_id,
diff --git a/src/test/compile-fail/issue-25700.rs b/src/test/compile-fail/issue-25700.rs
new file mode 100644
index 00000000000..477c3237f84
--- /dev/null
+++ b/src/test/compile-fail/issue-25700.rs
@@ -0,0 +1,24 @@
+// 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.
+
+struct S<T: 'static>(Option<&'static T>);
+
+trait Tr { type Out; }
+impl<T> Tr for T { type Out = T; }
+
+impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
+impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
+    fn clone(&self) -> Self { *self }
+}
+fn main() {
+    let t = S::<()>(None);
+    drop(t);
+    drop(t); //~ ERROR use of moved value
+}
diff --git a/src/test/run-pass/issue-25700-1.rs b/src/test/run-pass/issue-25700-1.rs
new file mode 100644
index 00000000000..57f5b84b285
--- /dev/null
+++ b/src/test/run-pass/issue-25700-1.rs
@@ -0,0 +1,22 @@
+// 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.
+
+struct S<T: 'static>(Option<&'static T>);
+
+trait Tr { type Out; }
+impl<T> Tr for T { type Out = T; }
+
+impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
+impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
+    fn clone(&self) -> Self { *self }
+}
+fn main() {
+    S::<()>(None);
+}
diff --git a/src/test/run-pass/issue-25700-2.rs b/src/test/run-pass/issue-25700-2.rs
new file mode 100644
index 00000000000..3117e6f3681
--- /dev/null
+++ b/src/test/run-pass/issue-25700-2.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.
+
+pub trait Parser {
+    type Input;
+}
+
+pub struct Iter<P: Parser>(P, P::Input);
+
+pub struct Map<P, F>(P, F);
+impl<P, F> Parser for Map<P, F> where F: FnMut(P) {
+    type Input = u8;
+}
+
+trait AstId { type Untyped; }
+impl AstId for u32 { type Untyped = u32; }
+
+fn record_type<Id: AstId>(i: Id::Untyped) -> u8 {
+    Iter(Map(i, |_: Id::Untyped| {}), 42).1
+}
+
+pub fn main() {
+   assert_eq!(record_type::<u32>(3), 42);
+}