Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace consider_unification_despite_ambiguity with new obligation variant #32780

Merged
merged 2 commits into from
Apr 13, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, // the closure implements `..` but not `..`
}
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
14 changes: 14 additions & 0 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 `{}`",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think you should say something like "expected a closure that implements the {} trait, but this closure only implement {}". This fits our usual "expected, found" order better, and helps clarify that FnMut (etc) is a trait.

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
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 @@ -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> {
Expand Down Expand Up @@ -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),
}
}
}
Expand Down Expand Up @@ -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
Expand All @@ -1080,6 +1090,7 @@ impl<'tcx> Predicate<'tcx> {
Predicate::RegionOutlives(..) |
Predicate::WellFormed(..) |
Predicate::ObjectSafe(..) |
Predicate::ClosureKind(..) |
Predicate::TypeOutlives(..) => {
None
}
Expand Down Expand Up @@ -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
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 @@ -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)
}
}
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}),
}
}
}
Loading