mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 03:38:29 +00:00
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()));
|
obligation.repr(selcx.tcx()));
|
||||||
|
|
||||||
let infcx = selcx.infcx();
|
let infcx = selcx.infcx();
|
||||||
let result = infcx.try(|snapshot| {
|
infcx.try(|snapshot| {
|
||||||
let (skol_predicate, skol_map) =
|
let (skol_predicate, skol_map) =
|
||||||
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||||
|
|
||||||
let skol_obligation = obligation.with(skol_predicate);
|
let skol_obligation = obligation.with(skol_predicate);
|
||||||
match project_and_unify_type(selcx, &skol_obligation) {
|
match project_and_unify_type(selcx, &skol_obligation) {
|
||||||
Ok(Some(obligations)) => {
|
Ok(result) => {
|
||||||
match infcx.leak_check(&skol_map, snapshot) {
|
match infcx.leak_check(&skol_map, snapshot) {
|
||||||
Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &obligations)),
|
Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &result)),
|
||||||
Err(e) => Err(Some(MismatchedProjectionTypes { err: e })),
|
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(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:
|
/// Evaluates constraints of the form:
|
||||||
@ -132,7 +118,10 @@ fn project_and_unify_type<'cx,'tcx>(
|
|||||||
obligation.cause.clone(),
|
obligation.cause.clone(),
|
||||||
obligation.recursion_depth) {
|
obligation.recursion_depth) {
|
||||||
Some(n) => n,
|
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={}",
|
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
|
/// Normalizes any associated type projections in `value`, replacing
|
||||||
/// them with a fully resolved type where possible. The return value
|
/// them with a fully resolved type where possible. The return value
|
||||||
/// combines the normalized result and any additional obligations that
|
/// 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
|
/// the argument types can only be helpful to the user, because
|
||||||
/// once they patch up the kind of closure that is expected, the
|
/// once they patch up the kind of closure that is expected, the
|
||||||
/// argment types won't really change.
|
/// 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`?
|
// 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()) {
|
match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) {
|
||||||
Some(_) => { }
|
Some(_) => { }
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
// except according to those terms.
|
// 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) }
|
fn apply<A, F>(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) }
|
||||||
|
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(unboxed_closures)]
|
#![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 k = box 22;
|
||||||
let _u = A {a: k.clone()};
|
let _u = A {a: k.clone()};
|
||||||
let result = |&mut:| 22;
|
let result = |&mut:| 22;
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut zero = |&mut:| {};
|
let mut zero = || {};
|
||||||
let () = zero.call_mut(());
|
let () = zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user