Skip to content

Commit

Permalink
Auto merge of #32780 - soltanmm:consider-the-following, r=nikomatsakis
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Apr 13, 2016
2 parents 525aa61 + de82fc4 commit 35dca7f
Show file tree
Hide file tree
Showing 19 changed files with 163 additions and 75 deletions.
1 change: 1 addition & 0 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 `..`
}
1 change: 1 addition & 0 deletions src/librustc/middle/free_region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
15 changes: 15 additions & 0 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
105 changes: 31 additions & 74 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
Expand Down Expand Up @@ -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
//
Expand Down Expand Up @@ -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
}
}
}
}
}

Expand Down Expand Up @@ -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));
}
}

Expand Down Expand Up @@ -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))
}

Expand Down Expand Up @@ -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>>
{
Expand All @@ -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={:?})",
Expand All @@ -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(),
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
Expand Down
13 changes: 12 additions & 1 deletion src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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),
}
}
}
Expand Down Expand Up @@ -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
Expand All @@ -1128,6 +1138,7 @@ impl<'tcx> Predicate<'tcx> {
Predicate::RegionOutlives(..) |
Predicate::WellFormed(..) |
Predicate::ObjectSafe(..) |
Predicate::ClosureKind(..) |
Predicate::TypeOutlives(..) => {
None
}
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
Expand All @@ -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,
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ impl<'tcx> TyCtxt<'tcx> {
ty::Predicate::Equate(..) |
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) |
ty::Predicate::RegionOutlives(..) => {
None
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/ty/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ pub fn predicate_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>,
}
ty::Predicate::ObjectSafe(_) => {
}
ty::Predicate::ClosureKind(..) => {
}
}

wf.normalize()
Expand Down Expand Up @@ -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![],

Expand Down
18 changes: 18 additions & 0 deletions src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}),
}
}
}
Loading

0 comments on commit 35dca7f

Please sign in to comment.