Skip to content

Commit

Permalink
Merge pull request #20415 from eddyb/unify-expected-return
Browse files Browse the repository at this point in the history
rustc_typeck: unify expected return types with formal return types to propagate coercions through calls of generic functions.

Reviewed-by: nikomatsakis
  • Loading branch information
bors committed Jan 12, 2015
2 parents e7b397b + 4748721 commit 3d5a102
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 71 deletions.
33 changes: 33 additions & 0 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.commit_unconditionally(move || self.try(move |_| f()))
}

/// Execute `f` and commit only the region bindings if successful.
/// The function f must be very careful not to leak any non-region
/// variables that get created.
pub fn commit_regions_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
F: FnOnce() -> Result<T, E>
{
debug!("commit_regions_if_ok()");
let CombinedSnapshot { type_snapshot,
int_snapshot,
float_snapshot,
region_vars_snapshot } = self.start_snapshot();

let r = self.try(move |_| f());

// Roll back any non-region bindings - they should be resolved
// inside `f`, with, e.g. `resolve_type_vars_if_possible`.
self.type_variables
.borrow_mut()
.rollback_to(type_snapshot);
self.int_unification_table
.borrow_mut()
.rollback_to(int_snapshot);
self.float_unification_table
.borrow_mut()
.rollback_to(float_snapshot);

// Commit region vars that may escape through resolved types.
self.region_vars
.commit(region_vars_snapshot);

r
}

/// Execute `f`, unroll bindings on panic
pub fn try<T, E, F>(&self, f: F) -> Result<T, E> where
F: FnOnce(&CombinedSnapshot) -> Result<T, E>
Expand Down
32 changes: 21 additions & 11 deletions src/librustc_typeck/check/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use super::check_argument_types;
use super::check_expr;
use super::check_method_argument_types;
use super::err_args;
use super::Expectation;
use super::expected_types_for_fn_args;
use super::FnCtxt;
use super::LvaluePreference;
use super::method;
Expand Down Expand Up @@ -65,7 +67,8 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id:
pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
call_expr: &ast::Expr,
callee_expr: &ast::Expr,
arg_exprs: &[P<ast::Expr>])
arg_exprs: &[P<ast::Expr>],
expected: Expectation<'tcx>)
{
check_expr(fcx, callee_expr);
let original_callee_ty = fcx.expr_ty(callee_expr);
Expand All @@ -84,15 +87,15 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
match result {
None => {
// this will report an error since original_callee_ty is not a fn
confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs);
confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs, expected);
}

Some(CallStep::Builtin) => {
confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs);
confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs, expected);
}

Some(CallStep::Overloaded(method_callee)) => {
confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee);
confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee, expected);
}
}
}
Expand Down Expand Up @@ -153,7 +156,8 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
call_expr: &ast::Expr,
callee_ty: Ty<'tcx>,
arg_exprs: &[P<ast::Expr>])
arg_exprs: &[P<ast::Expr>],
expected: Expectation<'tcx>)
{
let error_fn_sig;

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

// Call the generic checker.
let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>].
let expected_arg_tys = expected_types_for_fn_args(fcx,
call_expr.span,
expected,
fn_sig.output,
fn_sig.inputs.as_slice());
check_argument_types(fcx,
call_expr.span,
fn_sig.inputs.as_slice(),
arg_exprs.as_slice(),
&expected_arg_tys[],
arg_exprs,
AutorefArgs::No,
fn_sig.variadic,
TupleArgumentsFlag::DontTupleArguments);
Expand All @@ -207,16 +216,17 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
call_expr: &ast::Expr,
arg_exprs: &[P<ast::Expr>],
method_callee: ty::MethodCallee<'tcx>)
method_callee: ty::MethodCallee<'tcx>,
expected: Expectation<'tcx>)
{
let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>].
let output_type = check_method_argument_types(fcx,
call_expr.span,
method_callee.ty,
call_expr,
arg_exprs.as_slice(),
arg_exprs,
AutorefArgs::No,
TupleArgumentsFlag::TupleArguments);
TupleArgumentsFlag::TupleArguments,
expected);
let method_call = ty::MethodCall::expr(call_expr.id);
fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
write_call(fcx, call_expr, output_type);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
expr.repr(fcx.tcx()),
expected.repr(fcx.tcx()));

let expected_sig_and_kind = expected.map_to_option(fcx, |ty| {
let expected_sig_and_kind = expected.to_option(fcx).and_then(|ty| {
deduce_unboxed_closure_expectations_from_expected_type(fcx, ty)
});

Expand Down
Loading

0 comments on commit 3d5a102

Please sign in to comment.