diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 6f06efd0f9f26..7541132951666 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1544,4 +1544,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 ae0540696c572..51eebd4373113 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 f15b9ee44ce52..a40a5ce81c880 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -466,6 +466,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 11e8dae871764..662adf9800768 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 7cd2ac5938d41..90a54d8263b4c 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 f68386feddb59..17dbe90c1e19c 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 - /// - /// 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>, 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 befca878bc0e4..f01f2e1954b26 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 edfad09ae1fa1..971f62ffdc5a6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -784,6 +784,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> { @@ -873,6 +878,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), } } } @@ -1060,6 +1067,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 @@ -1080,6 +1090,7 @@ impl<'tcx> Predicate<'tcx> { Predicate::RegionOutlives(..) | Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | + Predicate::ClosureKind(..) | Predicate::TypeOutlives(..) => { None } @@ -1735,7 +1746,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 82cc9e7f2e3db..9a432fb628e15 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 6e8363f629b69..253dfb8110bd3 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 e6c4e90babbf5..d50e0091e554a 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 20f16a1d255c7..1c68e0177a137 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -453,6 +453,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) + } } } } @@ -1027,6 +1030,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 { @@ -1040,6 +1053,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 28985c75a912d..49dea39283496 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 ffaf7e2d465db..298d7d47ab991 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>, 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 9333b10d27e4a..a2949ef30c8d1 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 2e15ac0e13084..5eb486181a5c2 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 59546f619c0ac..80eda54ad6224 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 7437d6087718a..b621460c65902 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -853,6 +853,7 @@ impl<'a> Clean 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 0000000000000..6792414c36790 --- /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 or the MIT license +// , 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) {} +fn bar(_: T) {} + +fn main() { + let x = X; + let closure = |_| foo(x); //~ ERROR E0524 + bar(closure); +}