mirror of https://github.com/rust-lang/rust.git
Teach project to unify the return type even if a precise match is not
possible. There is some amount of duplication as a result (similar to select) -- I am not happy about this but not sure how to fix it without deeper rewrites.
This commit is contained in:
parent
c9e1c445db
commit
498595a3dc
|
@ -80,37 +80,23 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
|
|||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
let result = infcx.try(|snapshot| {
|
||||
infcx.try(|snapshot| {
|
||||
let (skol_predicate, skol_map) =
|
||||
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
|
||||
let skol_obligation = obligation.with(skol_predicate);
|
||||
match project_and_unify_type(selcx, &skol_obligation) {
|
||||
Ok(Some(obligations)) => {
|
||||
Ok(result) => {
|
||||
match infcx.leak_check(&skol_map, snapshot) {
|
||||
Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &obligations)),
|
||||
Err(e) => Err(Some(MismatchedProjectionTypes { err: e })),
|
||||
Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &result)),
|
||||
Err(e) => Err(MismatchedProjectionTypes { err: e }),
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
// Signal ambiguity using Err just so that infcx.try()
|
||||
// rolls back the snapshot. We adapt below.
|
||||
Err(None)
|
||||
}
|
||||
Err(e) => {
|
||||
Err(Some(e))
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Above, we use Err(None) to signal ambiguity so that the
|
||||
// snapshot will be rolled back. But here, we want to translate to
|
||||
// Ok(None). Kind of weird.
|
||||
match result {
|
||||
Ok(obligations) => Ok(Some(obligations)),
|
||||
Err(None) => Ok(None),
|
||||
Err(Some(e)) => Err(e),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Evaluates constraints of the form:
|
||||
|
@ -132,7 +118,10 @@ fn project_and_unify_type<'cx,'tcx>(
|
|||
obligation.cause.clone(),
|
||||
obligation.recursion_depth) {
|
||||
Some(n) => n,
|
||||
None => { return Ok(None); }
|
||||
None => {
|
||||
consider_unification_despite_ambiguity(selcx, obligation);
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
debug!("project_and_unify_type: normalized_ty={} obligations={}",
|
||||
|
@ -147,6 +136,50 @@ fn project_and_unify_type<'cx,'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionObligation<'tcx>) {
|
||||
debug!("consider_unification_despite_ambiguity(obligation={})",
|
||||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let def_id = obligation.predicate.projection_ty.trait_ref.def_id;
|
||||
match selcx.tcx().lang_items.fn_trait_kind(def_id) {
|
||||
Some(_) => { }
|
||||
None => { return; }
|
||||
}
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
let self_ty = obligation.predicate.projection_ty.trait_ref.self_ty();
|
||||
let self_ty = infcx.shallow_resolve(self_ty);
|
||||
debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}",
|
||||
self_ty.sty);
|
||||
match self_ty.sty {
|
||||
ty::ty_closure(closure_def_id, _, substs) => {
|
||||
let closure_typer = selcx.closure_typer();
|
||||
let closure_type = closure_typer.closure_type(closure_def_id, substs);
|
||||
let ty::Binder((_, ret_type)) =
|
||||
util::closure_trait_ref_and_return_type(infcx.tcx,
|
||||
def_id,
|
||||
self_ty,
|
||||
&closure_type.sig,
|
||||
util::TupleArgumentsFlag::No);
|
||||
let (ret_type, _) =
|
||||
infcx.replace_late_bound_regions_with_fresh_var(
|
||||
obligation.cause.span,
|
||||
infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name),
|
||||
&ty::Binder(ret_type));
|
||||
debug!("consider_unification_despite_ambiguity: ret_type={:?}",
|
||||
ret_type.repr(selcx.tcx()));
|
||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||
let obligation_ty = obligation.predicate.ty;
|
||||
match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) {
|
||||
Ok(()) => { }
|
||||
Err(_) => { /* ignore errors */ }
|
||||
}
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
/// Normalizes any associated type projections in `value`, replacing
|
||||
/// them with a fully resolved type where possible. The return value
|
||||
/// combines the normalized result and any additional obligations that
|
||||
|
|
|
@ -277,8 +277,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// 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>)
|
||||
{
|
||||
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(_) => { }
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
|
||||
fn foo(i: int) -> int { i + 1 }
|
||||
fn foo(i: isize) -> isize { i + 1 }
|
||||
|
||||
fn apply<A, F>(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) }
|
||||
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
#![feature(box_syntax)]
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
struct A { a: Box<int> }
|
||||
struct A { a: Box<isize> }
|
||||
|
||||
fn foo() -> Box<FnMut() -> int + 'static> {
|
||||
fn foo() -> Box<FnMut() -> isize + 'static> {
|
||||
let k = box 22;
|
||||
let _u = A {a: k.clone()};
|
||||
let result = |&mut:| 22;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#![feature(unboxed_closures)]
|
||||
|
||||
fn main() {
|
||||
let mut zero = |&mut:| {};
|
||||
let () = zero.call_mut(());
|
||||
let mut zero = || {};
|
||||
let () = zero();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue