提交 e45c7955 编写于 作者: M Masood Malekghassemi

Replace consider_unification_despite_ambiguity with obligation variant

上级 57e5d43c
......@@ -1544,4 +1544,5 @@ fn cookie() -> ! { // error: definition of an unknown language item: `cookie`
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, // the closure implements `..` but not `..`
}
......@@ -59,6 +59,7 @@ pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
ty::Predicate::Equate(..) |
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) |
ty::Predicate::TypeOutlives(..) => {
// No region bounds here
}
......
......@@ -466,6 +466,20 @@ 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,
"the closure implements `{}` but not `{}`",
found_kind,
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
......
......@@ -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) {
......
......@@ -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
}
......
......@@ -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 @@ pub fn select(&mut self, obligation: &TraitObligation<'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 @@ fn evaluate_predicate_recursively<'o>(&mut self,
}
}
}
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 @@ fn assemble_closure_candidates(&mut self,
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 @@ fn confirm_candidate(&mut self,
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 @@ fn confirm_fn_pointer_candidate(&mut self,
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 @@ fn confirm_closure_candidate(&mut self,
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 @@ fn confirm_closure_candidate(&mut self,
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(),
......
......@@ -60,6 +60,9 @@ fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
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 @@ fn push(&mut self, predicate: &ty::Predicate<'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
......
......@@ -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 @@ pub fn subst_supertrait(&self,
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 @@ pub fn walk_tys(&self) -> IntoIter<Ty<'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 @@ pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'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
......
......@@ -644,6 +644,8 @@ fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
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 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
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,
}
}
......
......@@ -301,6 +301,7 @@ pub fn required_region_bounds(&self,
ty::Predicate::Equate(..) |
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) |
ty::Predicate::RegionOutlives(..) => {
None
}
......
......@@ -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![],
......
......@@ -453,6 +453,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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)
}),
}
}
}
......@@ -553,6 +553,18 @@ pub fn parse_predicate(&mut self) -> ty::Predicate<'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)
}
}
......
......@@ -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);
}
}
}
......
......@@ -179,6 +179,9 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
ty::Predicate::TypeOutlives(..) => None,
ty::Predicate::WellFormed(..) => None,
ty::Predicate::ObjectSafe(..) => None,
ty::Predicate::ClosureKind(_closure_def_id, kind) => {
return Some(kind);
}
};
opt_trait_ref
.and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
......
......@@ -491,6 +491,7 @@ fn assemble_inherent_candidates_from_param(&mut self,
ty::Predicate::RegionOutlives(..) |
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) |
ty::Predicate::TypeOutlives(..) => {
None
}
......
......@@ -449,6 +449,7 @@ fn get_type_parameter_bounds(&self,
ty::Predicate::RegionOutlives(..) |
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) |
ty::Predicate::Projection(..) => {
false
}
......
......@@ -853,6 +853,7 @@ fn clean(&self, cx: &DocContext) -> WherePredicate {
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"),
}
}
}
......
// 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 the closure implements `FnOnce` but not `Fn`
bar(closure);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册