Skip to content

Commit 498595a

Browse files
committed
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.
1 parent c9e1c44 commit 498595a

File tree

5 files changed

+60
-28
lines changed

5 files changed

+60
-28
lines changed

src/librustc/middle/traits/project.rs

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -80,37 +80,23 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
8080
obligation.repr(selcx.tcx()));
8181

8282
let infcx = selcx.infcx();
83-
let result = infcx.try(|snapshot| {
83+
infcx.try(|snapshot| {
8484
let (skol_predicate, skol_map) =
8585
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
8686

8787
let skol_obligation = obligation.with(skol_predicate);
8888
match project_and_unify_type(selcx, &skol_obligation) {
89-
Ok(Some(obligations)) => {
89+
Ok(result) => {
9090
match infcx.leak_check(&skol_map, snapshot) {
91-
Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &obligations)),
92-
Err(e) => Err(Some(MismatchedProjectionTypes { err: e })),
91+
Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &result)),
92+
Err(e) => Err(MismatchedProjectionTypes { err: e }),
9393
}
9494
}
95-
Ok(None) => {
96-
// Signal ambiguity using Err just so that infcx.try()
97-
// rolls back the snapshot. We adapt below.
98-
Err(None)
99-
}
10095
Err(e) => {
101-
Err(Some(e))
96+
Err(e)
10297
}
10398
}
104-
});
105-
106-
// Above, we use Err(None) to signal ambiguity so that the
107-
// snapshot will be rolled back. But here, we want to translate to
108-
// Ok(None). Kind of weird.
109-
match result {
110-
Ok(obligations) => Ok(Some(obligations)),
111-
Err(None) => Ok(None),
112-
Err(Some(e)) => Err(e),
113-
}
99+
})
114100
}
115101

116102
/// Evaluates constraints of the form:
@@ -132,7 +118,10 @@ fn project_and_unify_type<'cx,'tcx>(
132118
obligation.cause.clone(),
133119
obligation.recursion_depth) {
134120
Some(n) => n,
135-
None => { return Ok(None); }
121+
None => {
122+
consider_unification_despite_ambiguity(selcx, obligation);
123+
return Ok(None);
124+
}
136125
};
137126

138127
debug!("project_and_unify_type: normalized_ty={} obligations={}",
@@ -147,6 +136,50 @@ fn project_and_unify_type<'cx,'tcx>(
147136
}
148137
}
149138

139+
fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext<'cx,'tcx>,
140+
obligation: &ProjectionObligation<'tcx>) {
141+
debug!("consider_unification_despite_ambiguity(obligation={})",
142+
obligation.repr(selcx.tcx()));
143+
144+
let def_id = obligation.predicate.projection_ty.trait_ref.def_id;
145+
match selcx.tcx().lang_items.fn_trait_kind(def_id) {
146+
Some(_) => { }
147+
None => { return; }
148+
}
149+
150+
let infcx = selcx.infcx();
151+
let self_ty = obligation.predicate.projection_ty.trait_ref.self_ty();
152+
let self_ty = infcx.shallow_resolve(self_ty);
153+
debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}",
154+
self_ty.sty);
155+
match self_ty.sty {
156+
ty::ty_closure(closure_def_id, _, substs) => {
157+
let closure_typer = selcx.closure_typer();
158+
let closure_type = closure_typer.closure_type(closure_def_id, substs);
159+
let ty::Binder((_, ret_type)) =
160+
util::closure_trait_ref_and_return_type(infcx.tcx,
161+
def_id,
162+
self_ty,
163+
&closure_type.sig,
164+
util::TupleArgumentsFlag::No);
165+
let (ret_type, _) =
166+
infcx.replace_late_bound_regions_with_fresh_var(
167+
obligation.cause.span,
168+
infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name),
169+
&ty::Binder(ret_type));
170+
debug!("consider_unification_despite_ambiguity: ret_type={:?}",
171+
ret_type.repr(selcx.tcx()));
172+
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
173+
let obligation_ty = obligation.predicate.ty;
174+
match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) {
175+
Ok(()) => { }
176+
Err(_) => { /* ignore errors */ }
177+
}
178+
}
179+
_ => { }
180+
}
181+
}
182+
150183
/// Normalizes any associated type projections in `value`, replacing
151184
/// them with a fully resolved type where possible. The return value
152185
/// combines the normalized result and any additional obligations that

src/librustc/middle/traits/select.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
277277
/// the argument types can only be helpful to the user, because
278278
/// once they patch up the kind of closure that is expected, the
279279
/// argment types won't really change.
280-
fn consider_unification_despite_ambiguity(&mut self, obligation: &TraitObligation<'tcx>)
281-
{
280+
fn consider_unification_despite_ambiguity(&mut self, obligation: &TraitObligation<'tcx>) {
282281
// Is this a `C : FnFoo(...)` trait reference for some trait binding `FnFoo`?
283282
match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) {
284283
Some(_) => { }

src/test/run-pass/closure-inference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111

12-
fn foo(i: int) -> int { i + 1 }
12+
fn foo(i: isize) -> isize { i + 1 }
1313

1414
fn apply<A, F>(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) }
1515

src/test/run-pass/last-use-in-cap-clause.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
#![feature(box_syntax)]
1515
#![feature(unboxed_closures)]
1616

17-
struct A { a: Box<int> }
17+
struct A { a: Box<isize> }
1818

19-
fn foo() -> Box<FnMut() -> int + 'static> {
19+
fn foo() -> Box<FnMut() -> isize + 'static> {
2020
let k = box 22;
2121
let _u = A {a: k.clone()};
2222
let result = |&mut:| 22;

src/test/run-pass/unboxed-closures-zero-args.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#![feature(unboxed_closures)]
1212

1313
fn main() {
14-
let mut zero = |&mut:| {};
15-
let () = zero.call_mut(());
14+
let mut zero = || {};
15+
let () = zero();
1616
}
1717

0 commit comments

Comments
 (0)