Skip to content

Commit 3d5a102

Browse files
committed
Merge pull request #20415 from eddyb/unify-expected-return
rustc_typeck: unify expected return types with formal return types to propagate coercions through calls of generic functions. Reviewed-by: nikomatsakis
2 parents e7b397b + 4748721 commit 3d5a102

File tree

9 files changed

+215
-71
lines changed

9 files changed

+215
-71
lines changed

src/librustc/middle/infer/mod.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
613613
self.commit_unconditionally(move || self.try(move |_| f()))
614614
}
615615

616+
/// Execute `f` and commit only the region bindings if successful.
617+
/// The function f must be very careful not to leak any non-region
618+
/// variables that get created.
619+
pub fn commit_regions_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
620+
F: FnOnce() -> Result<T, E>
621+
{
622+
debug!("commit_regions_if_ok()");
623+
let CombinedSnapshot { type_snapshot,
624+
int_snapshot,
625+
float_snapshot,
626+
region_vars_snapshot } = self.start_snapshot();
627+
628+
let r = self.try(move |_| f());
629+
630+
// Roll back any non-region bindings - they should be resolved
631+
// inside `f`, with, e.g. `resolve_type_vars_if_possible`.
632+
self.type_variables
633+
.borrow_mut()
634+
.rollback_to(type_snapshot);
635+
self.int_unification_table
636+
.borrow_mut()
637+
.rollback_to(int_snapshot);
638+
self.float_unification_table
639+
.borrow_mut()
640+
.rollback_to(float_snapshot);
641+
642+
// Commit region vars that may escape through resolved types.
643+
self.region_vars
644+
.commit(region_vars_snapshot);
645+
646+
r
647+
}
648+
616649
/// Execute `f`, unroll bindings on panic
617650
pub fn try<T, E, F>(&self, f: F) -> Result<T, E> where
618651
F: FnOnce(&CombinedSnapshot) -> Result<T, E>

src/librustc_typeck/check/callee.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use super::check_argument_types;
1414
use super::check_expr;
1515
use super::check_method_argument_types;
1616
use super::err_args;
17+
use super::Expectation;
18+
use super::expected_types_for_fn_args;
1719
use super::FnCtxt;
1820
use super::LvaluePreference;
1921
use super::method;
@@ -65,7 +67,8 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id:
6567
pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
6668
call_expr: &ast::Expr,
6769
callee_expr: &ast::Expr,
68-
arg_exprs: &[P<ast::Expr>])
70+
arg_exprs: &[P<ast::Expr>],
71+
expected: Expectation<'tcx>)
6972
{
7073
check_expr(fcx, callee_expr);
7174
let original_callee_ty = fcx.expr_ty(callee_expr);
@@ -84,15 +87,15 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
8487
match result {
8588
None => {
8689
// this will report an error since original_callee_ty is not a fn
87-
confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs);
90+
confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs, expected);
8891
}
8992

9093
Some(CallStep::Builtin) => {
91-
confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs);
94+
confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs, expected);
9295
}
9396

9497
Some(CallStep::Overloaded(method_callee)) => {
95-
confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee);
98+
confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee, expected);
9699
}
97100
}
98101
}
@@ -153,7 +156,8 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
153156
fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
154157
call_expr: &ast::Expr,
155158
callee_ty: Ty<'tcx>,
156-
arg_exprs: &[P<ast::Expr>])
159+
arg_exprs: &[P<ast::Expr>],
160+
expected: Expectation<'tcx>)
157161
{
158162
let error_fn_sig;
159163

@@ -192,11 +196,16 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
192196
fcx.normalize_associated_types_in(call_expr.span, &fn_sig);
193197

194198
// Call the generic checker.
195-
let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>].
199+
let expected_arg_tys = expected_types_for_fn_args(fcx,
200+
call_expr.span,
201+
expected,
202+
fn_sig.output,
203+
fn_sig.inputs.as_slice());
196204
check_argument_types(fcx,
197205
call_expr.span,
198206
fn_sig.inputs.as_slice(),
199-
arg_exprs.as_slice(),
207+
&expected_arg_tys[],
208+
arg_exprs,
200209
AutorefArgs::No,
201210
fn_sig.variadic,
202211
TupleArgumentsFlag::DontTupleArguments);
@@ -207,16 +216,17 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
207216
fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
208217
call_expr: &ast::Expr,
209218
arg_exprs: &[P<ast::Expr>],
210-
method_callee: ty::MethodCallee<'tcx>)
219+
method_callee: ty::MethodCallee<'tcx>,
220+
expected: Expectation<'tcx>)
211221
{
212-
let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>].
213222
let output_type = check_method_argument_types(fcx,
214223
call_expr.span,
215224
method_callee.ty,
216225
call_expr,
217-
arg_exprs.as_slice(),
226+
arg_exprs,
218227
AutorefArgs::No,
219-
TupleArgumentsFlag::TupleArguments);
228+
TupleArgumentsFlag::TupleArguments,
229+
expected);
220230
let method_call = ty::MethodCall::expr(call_expr.id);
221231
fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
222232
write_call(fcx, call_expr, output_type);

src/librustc_typeck/check/closure.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
3333
expr.repr(fcx.tcx()),
3434
expected.repr(fcx.tcx()));
3535

36-
let expected_sig_and_kind = expected.map_to_option(fcx, |ty| {
36+
let expected_sig_and_kind = expected.to_option(fcx).and_then(|ty| {
3737
deduce_unboxed_closure_expectations_from_expected_type(fcx, ty)
3838
});
3939

0 commit comments

Comments
 (0)