about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-04-13 11:28:30 -0700
committerbors <bors@rust-lang.org>2016-04-13 11:28:30 -0700
commit35dca7fb7b7304cfa8da027d1be6eea7142d90d6 (patch)
treea60302779e6e49f13acb662d1914e3191ba3a84d
parent525aa6102250ec2a33c7066dfb966524f0ce3e21 (diff)
parentde82fc4dc6bbb87e50618f40e8fc671fb016f815 (diff)
downloadrust-35dca7fb7b7304cfa8da027d1be6eea7142d90d6.tar.gz
rust-35dca7fb7b7304cfa8da027d1be6eea7142d90d6.zip
Auto merge of #32780 - soltanmm:consider-the-following, r=nikomatsakis
Replace consider_unification_despite_ambiguity with new obligation variant

Is work towards #32730. Addresses part one of #32286. Addresses #24210 and #26046 to some degree.

r? @nikomatsakis
-rw-r--r--src/librustc/diagnostics.rs1
-rw-r--r--src/librustc/middle/free_region.rs1
-rw-r--r--src/librustc/traits/error_reporting.rs15
-rw-r--r--src/librustc/traits/fulfill.rs15
-rw-r--r--src/librustc/traits/object_safety.rs2
-rw-r--r--src/librustc/traits/select.rs105
-rw-r--r--src/librustc/traits/util.rs6
-rw-r--r--src/librustc/ty/mod.rs13
-rw-r--r--src/librustc/ty/structural_impls.rs3
-rw-r--r--src/librustc/ty/util.rs1
-rw-r--r--src/librustc/ty/wf.rs3
-rw-r--r--src/librustc/util/ppaux.rs18
-rw-r--r--src/librustc_metadata/tydecode.rs12
-rw-r--r--src/librustc_metadata/tyencode.rs8
-rw-r--r--src/librustc_typeck/check/closure.rs10
-rw-r--r--src/librustc_typeck/check/method/probe.rs1
-rw-r--r--src/librustc_typeck/collect.rs1
-rw-r--r--src/librustdoc/clean/mod.rs1
-rw-r--r--src/test/compile-fail/closure-wrong-kind.rs22
19 files changed, 163 insertions, 75 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 4abb1c8b98a..0b1c9609a0f 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1543,4 +1543,5 @@ register_diagnostics! {
     E0490, // a value of type `..` is borrowed for too long
     E0491, // in type `..`, reference has a longer lifetime than the data it...
     E0495, // cannot infer an appropriate lifetime due to conflicting requirements
+    E0524, // expected a closure that implements `..` but this closure only implements `..`
 }
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index ae0540696c5..51eebd43731 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -59,6 +59,7 @@ impl FreeRegionMap {
                 ty::Predicate::Equate(..) |
                 ty::Predicate::WellFormed(..) |
                 ty::Predicate::ObjectSafe(..) |
+                ty::Predicate::ClosureKind(..) |
                 ty::Predicate::TypeOutlives(..) => {
                     // No region bounds here
                 }
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 286733c7c26..3b5bdd734b4 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -495,6 +495,21 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                         err.emit();
                     }
 
+                    ty::Predicate::ClosureKind(closure_def_id, kind) => {
+                        let found_kind = infcx.closure_kind(closure_def_id).unwrap();
+                        let closure_span = infcx.tcx.map.span_if_local(closure_def_id).unwrap();
+                        let mut err = struct_span_err!(
+                            infcx.tcx.sess, closure_span, E0524,
+                            "expected a closure that implements the `{}` trait, but this closure \
+                             only implements `{}`",
+                            kind,
+                            found_kind);
+                        err.span_note(
+                            obligation.cause.span,
+                            &format!("the requirement to implement `{}` derives from here", kind));
+                        err.emit();
+                    }
+
                     ty::Predicate::WellFormed(ty) => {
                         // WF predicates cannot themselves make
                         // errors. They can only block due to
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 11e8dae8717..662adf98007 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -652,6 +652,21 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
             }
         }
 
+        ty::Predicate::ClosureKind(closure_def_id, kind) => {
+            match selcx.infcx().closure_kind(closure_def_id) {
+                Some(closure_kind) => {
+                    if closure_kind.extends(kind) {
+                        Ok(Some(vec![]))
+                    } else {
+                        Err(CodeSelectionError(Unimplemented))
+                    }
+                }
+                None => {
+                    Ok(None)
+                }
+            }
+        }
+
         ty::Predicate::WellFormed(ty) => {
             match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id,
                                       ty, obligation.cause.span) {
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 9af2cfbd04d..c870d609814 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -165,6 +165,7 @@ pub fn supertraits_reference_self<'tcx>(tcx: &TyCtxt<'tcx>,
                 ty::Predicate::ObjectSafe(..) |
                 ty::Predicate::TypeOutlives(..) |
                 ty::Predicate::RegionOutlives(..) |
+                ty::Predicate::ClosureKind(..) |
                 ty::Predicate::Equate(..) => {
                     false
                 }
@@ -207,6 +208,7 @@ fn generics_require_sized_self<'tcx>(tcx: &TyCtxt<'tcx>,
                 ty::Predicate::RegionOutlives(..) |
                 ty::Predicate::WellFormed(..) |
                 ty::Predicate::ObjectSafe(..) |
+                ty::Predicate::ClosureKind(..) |
                 ty::Predicate::TypeOutlives(..) => {
                     false
                 }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 8d7df6e44ae..d7528fc3130 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -198,9 +198,10 @@ enum SelectionCandidate<'tcx> {
     /// we found an applicable bound in the trait definition.
     ProjectionCandidate,
 
-    /// Implementation of a `Fn`-family trait by one of the
-    /// anonymous types generated for a `||` expression.
-    ClosureCandidate(/* closure */ DefId, &'tcx ty::ClosureSubsts<'tcx>),
+    /// Implementation of a `Fn`-family trait by one of the anonymous types
+    /// generated for a `||` expression. The ty::ClosureKind informs the
+    /// confirmation step what ClosureKind obligation to emit.
+    ClosureCandidate(/* closure */ DefId, &'tcx ty::ClosureSubsts<'tcx>, ty::ClosureKind),
 
     /// Implementation of a `Fn`-family trait by one of the anonymous
     /// types generated for a fn pointer type (e.g., `fn(int)->int`)
@@ -321,75 +322,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
         match self.candidate_from_obligation(&stack)? {
-            None => {
-                self.consider_unification_despite_ambiguity(obligation);
-                Ok(None)
-            }
+            None => Ok(None),
             Some(candidate) => Ok(Some(self.confirm_candidate(obligation, candidate)?)),
         }
     }
 
-    /// In the particular case of unboxed closure obligations, we can
-    /// sometimes do some amount of unification for the
-    /// argument/return types even though we can't yet fully match obligation.
-    /// The particular case we are interesting in is an obligation of the form:
-    ///
-    ///    C : FnFoo<A>
-    ///
-    /// where `C` is an unboxed closure type and `FnFoo` is one of the
-    /// `Fn` traits. Because we know that users cannot write impls for closure types
-    /// themselves, the only way that `C : FnFoo` can fail to match is under two
-    /// conditions:
-    ///
-    /// 1. The closure kind for `C` is not yet known, because inference isn't complete.
-    /// 2. The closure kind for `C` *is* known, but doesn't match what is needed.
-    ///    For example, `C` may be a `FnOnce` closure, but a `Fn` closure is needed.
-    ///
-    /// In either case, we always know what argument types are
-    /// expected by `C`, no matter what kind of `Fn` trait it
-    /// eventually matches. So we can go ahead and unify the argument
-    /// types, even though the end result is ambiguous.
-    ///
-    /// Note that this is safe *even if* the trait would never be
-    /// matched (case 2 above). After all, in that case, an error will
-    /// result, so it kind of doesn't matter what we do --- unifying
-    /// the argument types can only be helpful to the user, because
-    /// once they patch up the kind of closure that is expected, the
-    /// argment types won't really change.
-    fn consider_unification_despite_ambiguity(&mut self, obligation: &TraitObligation<'tcx>) {
-        // Is this a `C : FnFoo(...)` trait reference for some trait binding `FnFoo`?
-        match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) {
-            Some(_) => { }
-            None => { return; }
-        }
-
-        // Is the self-type a closure type? We ignore bindings here
-        // because if it is a closure type, it must be a closure type from
-        // within this current fn, and hence none of the higher-ranked
-        // lifetimes can appear inside the self-type.
-        let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
-        let (closure_def_id, substs) = match self_ty.sty {
-            ty::TyClosure(id, ref substs) => (id, substs),
-            _ => { return; }
-        };
-        assert!(!substs.has_escaping_regions());
-
-        // 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) {
-            Ok(()) => { }
-            Err(_) => { /* Silently ignore errors. */ }
-        }
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // EVALUATION
     //
@@ -532,6 +469,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                 }
             }
+
+            ty::Predicate::ClosureKind(closure_def_id, kind) => {
+                match self.infcx.closure_kind(closure_def_id) {
+                    Some(closure_kind) => {
+                        if closure_kind.extends(kind) {
+                            EvaluatedToOk
+                        } else {
+                            EvaluatedToErr
+                        }
+                    }
+                    None => {
+                        EvaluatedToAmbig
+                    }
+                }
+            }
         }
     }
 
@@ -1282,12 +1234,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             Some(closure_kind) => {
                 debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
                 if closure_kind.extends(kind) {
-                    candidates.vec.push(ClosureCandidate(closure_def_id, substs));
+                    candidates.vec.push(ClosureCandidate(closure_def_id, substs, kind));
                 }
             }
             None => {
                 debug!("assemble_unboxed_candidates: closure_kind not yet known");
-                candidates.ambiguous = true;
+                candidates.vec.push(ClosureCandidate(closure_def_id, substs, kind));
             }
         }
 
@@ -2071,9 +2023,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Ok(VtableImpl(vtable_impl))
             }
 
-            ClosureCandidate(closure_def_id, substs) => {
+            ClosureCandidate(closure_def_id, substs, kind) => {
                 let vtable_closure =
-                    self.confirm_closure_candidate(obligation, closure_def_id, substs)?;
+                    self.confirm_closure_candidate(obligation, closure_def_id, substs, kind)?;
                 Ok(VtableClosure(vtable_closure))
             }
 
@@ -2430,7 +2382,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_closure_candidate(&mut self,
                                  obligation: &TraitObligation<'tcx>,
                                  closure_def_id: DefId,
-                                 substs: &ty::ClosureSubsts<'tcx>)
+                                 substs: &ty::ClosureSubsts<'tcx>,
+                                 kind: ty::ClosureKind)
                                  -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>,
                                            SelectionError<'tcx>>
     {
@@ -2441,7 +2394,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let Normalized {
             value: trait_ref,
-            obligations
+            mut obligations
         } = self.closure_trait_ref(obligation, closure_def_id, substs);
 
         debug!("confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
@@ -2453,6 +2406,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                      obligation.predicate.to_poly_trait_ref(),
                                      trait_ref)?;
 
+        obligations.push(Obligation::new(
+                obligation.cause.clone(),
+                ty::Predicate::ClosureKind(closure_def_id, kind)));
+
         Ok(VtableClosureData {
             closure_def_id: closure_def_id,
             substs: substs.clone(),
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 7668b8bf202..90def00be07 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -60,6 +60,9 @@ impl<'a,'tcx> PredicateSet<'a,'tcx> {
 
             ty::Predicate::ObjectSafe(data) =>
                 ty::Predicate::ObjectSafe(data),
+
+            ty::Predicate::ClosureKind(closure_def_id, kind) =>
+                ty::Predicate::ClosureKind(closure_def_id, kind)
         };
         self.set.insert(normalized_pred)
     }
@@ -156,6 +159,9 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
             ty::Predicate::Projection(..) => {
                 // Nothing to elaborate in a projection predicate.
             }
+            ty::Predicate::ClosureKind(..) => {
+                // Nothing to elaborate when waiting for a closure's kind to be inferred.
+            }
             ty::Predicate::RegionOutlives(..) |
             ty::Predicate::TypeOutlives(..) => {
                 // Currently, we do not "elaborate" predicates like
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index cba3a9e2ebb..eaba5d2a860 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -832,6 +832,11 @@ pub enum Predicate<'tcx> {
 
     /// trait must be object-safe
     ObjectSafe(DefId),
+
+    /// No direct syntax. May be thought of as `where T : FnFoo<...>` for some 'TypeSpace'
+    /// substitutions `...` and T being a closure type.  Satisfied (or refuted) once we know the
+    /// closure's kind.
+    ClosureKind(DefId, ClosureKind),
 }
 
 impl<'tcx> Predicate<'tcx> {
@@ -921,6 +926,8 @@ impl<'tcx> Predicate<'tcx> {
                 Predicate::WellFormed(data.subst(tcx, substs)),
             Predicate::ObjectSafe(trait_def_id) =>
                 Predicate::ObjectSafe(trait_def_id),
+            Predicate::ClosureKind(closure_def_id, kind) =>
+                Predicate::ClosureKind(closure_def_id, kind),
         }
     }
 }
@@ -1108,6 +1115,9 @@ impl<'tcx> Predicate<'tcx> {
             ty::Predicate::ObjectSafe(_trait_def_id) => {
                 vec![]
             }
+            ty::Predicate::ClosureKind(_closure_def_id, _kind) => {
+                vec![]
+            }
         };
 
         // The only reason to collect into a vector here is that I was
@@ -1128,6 +1138,7 @@ impl<'tcx> Predicate<'tcx> {
             Predicate::RegionOutlives(..) |
             Predicate::WellFormed(..) |
             Predicate::ObjectSafe(..) |
+            Predicate::ClosureKind(..) |
             Predicate::TypeOutlives(..) => {
                 None
             }
@@ -1783,7 +1794,7 @@ pub struct ItemSubsts<'tcx> {
     pub substs: Substs<'tcx>,
 }
 
-#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub enum ClosureKind {
     // Warning: Ordering is significant here! The ordering is chosen
     // because the trait Fn is a subtrait of FnMut and so in turn, and
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index bbf6d0329b4..4d64dd83071 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -644,6 +644,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
                 ty::Predicate::Projection(binder.fold_with(folder)),
             ty::Predicate::WellFormed(data) =>
                 ty::Predicate::WellFormed(data.fold_with(folder)),
+            ty::Predicate::ClosureKind(closure_def_id, kind) =>
+                ty::Predicate::ClosureKind(closure_def_id, kind),
             ty::Predicate::ObjectSafe(trait_def_id) =>
                 ty::Predicate::ObjectSafe(trait_def_id),
         }
@@ -657,6 +659,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
             ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor),
             ty::Predicate::Projection(ref binder) => binder.visit_with(visitor),
             ty::Predicate::WellFormed(data) => data.visit_with(visitor),
+            ty::Predicate::ClosureKind(_closure_def_id, _kind) => false,
             ty::Predicate::ObjectSafe(_trait_def_id) => false,
         }
     }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 354744b2787..eb1630db980 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -301,6 +301,7 @@ impl<'tcx> TyCtxt<'tcx> {
                     ty::Predicate::Equate(..) |
                     ty::Predicate::WellFormed(..) |
                     ty::Predicate::ObjectSafe(..) |
+                    ty::Predicate::ClosureKind(..) |
                     ty::Predicate::RegionOutlives(..) => {
                         None
                     }
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 9ea634bb41c..f93332e0773 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -92,6 +92,8 @@ pub fn predicate_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>,
         }
         ty::Predicate::ObjectSafe(_) => {
         }
+        ty::Predicate::ClosureKind(..) => {
+        }
     }
 
     wf.normalize()
@@ -155,6 +157,7 @@ pub fn implied_bounds<'a,'tcx>(
                     ty::Predicate::Trait(..) |
                     ty::Predicate::Equate(..) |
                     ty::Predicate::Projection(..) |
+                    ty::Predicate::ClosureKind(..) |
                     ty::Predicate::ObjectSafe(..) =>
                         vec![],
 
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 2173b919d13..9b590ec8aa6 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -467,6 +467,9 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
             ty::Predicate::ObjectSafe(trait_def_id) => {
                 write!(f, "ObjectSafe({:?})", trait_def_id)
             }
+            ty::Predicate::ClosureKind(closure_def_id, kind) => {
+                write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind)
+            }
         }
     }
 }
@@ -1039,6 +1042,16 @@ impl<'tcx> fmt::Display for ty::ProjectionTy<'tcx> {
     }
 }
 
+impl fmt::Display for ty::ClosureKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ty::ClosureKind::Fn => write!(f, "Fn"),
+            ty::ClosureKind::FnMut => write!(f, "FnMut"),
+            ty::ClosureKind::FnOnce => write!(f, "FnOnce"),
+        }
+    }
+}
+
 impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
@@ -1052,6 +1065,11 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
                 ty::tls::with(|tcx| {
                     write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id))
                 }),
+            ty::Predicate::ClosureKind(closure_def_id, kind) =>
+                ty::tls::with(|tcx| {
+                    write!(f, "the closure `{}` implements the trait `{}`",
+                           tcx.item_path_str(closure_def_id), kind)
+                }),
         }
     }
 }
diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs
index 3004246d1d7..9f674a20f92 100644
--- a/src/librustc_metadata/tydecode.rs
+++ b/src/librustc_metadata/tydecode.rs
@@ -553,6 +553,18 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 assert_eq!(self.next(), '|');
                 ty::Predicate::ObjectSafe(def_id)
             }
+            'c' => {
+                let def_id = self.parse_def();
+                assert_eq!(self.next(), '|');
+                let kind = match self.next() {
+                    'f' => ty::ClosureKind::Fn,
+                    'm' => ty::ClosureKind::FnMut,
+                    'o' => ty::ClosureKind::FnOnce,
+                    c => bug!("Encountered invalid character in metadata: {}", c)
+                };
+                assert_eq!(self.next(), '|');
+                ty::Predicate::ClosureKind(def_id, kind)
+            }
             c => bug!("Encountered invalid character in metadata: {}", c)
         }
     }
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
index f49c2e22c6a..61d055d4d51 100644
--- a/src/librustc_metadata/tyencode.rs
+++ b/src/librustc_metadata/tyencode.rs
@@ -479,6 +479,14 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
         ty::Predicate::ObjectSafe(trait_def_id) => {
             write!(w, "O{}|", (cx.ds)(cx.tcx, trait_def_id));
         }
+        ty::Predicate::ClosureKind(closure_def_id, kind) => {
+            let kind_char = match kind {
+                ty::ClosureKind::Fn => 'f',
+                ty::ClosureKind::FnMut => 'm',
+                ty::ClosureKind::FnOnce => 'o',
+            };
+            write!(w, "c{}|{}|", (cx.ds)(cx.tcx, closure_def_id), kind_char);
+        }
     }
 }
 
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 7bca570411c..4ac7e3323ef 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -179,6 +179,16 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
                 ty::Predicate::TypeOutlives(..) => None,
                 ty::Predicate::WellFormed(..) => None,
                 ty::Predicate::ObjectSafe(..) => None,
+
+                // NB: This predicate is created by breaking down a
+                // `ClosureType: FnFoo()` predicate, where
+                // `ClosureType` represents some `TyClosure`. It can't
+                // possibly be referring to the current closure,
+                // because we haven't produced the `TyClosure` for
+                // this closure yet; this is exactly why the other
+                // code is looking for a self type of a unresolved
+                // inference variable.
+                ty::Predicate::ClosureKind(..) => None,
             };
             opt_trait_ref
                 .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 0ffbbfea84e..2defbf0d33e 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -491,6 +491,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                     ty::Predicate::RegionOutlives(..) |
                     ty::Predicate::WellFormed(..) |
                     ty::Predicate::ObjectSafe(..) |
+                    ty::Predicate::ClosureKind(..) |
                     ty::Predicate::TypeOutlives(..) => {
                         None
                     }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 95cb2269a1f..2e9c8676dc7 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -449,6 +449,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> {
                     ty::Predicate::RegionOutlives(..) |
                     ty::Predicate::WellFormed(..) |
                     ty::Predicate::ObjectSafe(..) |
+                    ty::Predicate::ClosureKind(..) |
                     ty::Predicate::Projection(..) => {
                         false
                     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index d8d1472560d..e2189e003ae 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -849,6 +849,7 @@ impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
             Predicate::Projection(ref pred) => pred.clean(cx),
             Predicate::WellFormed(_) => panic!("not user writable"),
             Predicate::ObjectSafe(_) => panic!("not user writable"),
+            Predicate::ClosureKind(..) => panic!("not user writable"),
         }
     }
 }
diff --git a/src/test/compile-fail/closure-wrong-kind.rs b/src/test/compile-fail/closure-wrong-kind.rs
new file mode 100644
index 00000000000..6792414c367
--- /dev/null
+++ b/src/test/compile-fail/closure-wrong-kind.rs
@@ -0,0 +1,22 @@
+// Copyright 2016 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.
+
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+struct X;
+fn foo<T>(_: T) {}
+fn bar<T: Fn(u32)>(_: T) {}
+
+fn main() {
+    let x = X;
+    let closure = |_| foo(x);  //~ ERROR E0524
+    bar(closure);
+}