refactor check_call_inner to have a better name and be readable
This commit is contained in:
parent
babe506333
commit
1745a2cd08
1 changed files with 86 additions and 104 deletions
|
@ -1122,9 +1122,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
unifier: &fn()) {
|
unifier: &fn()) {
|
||||||
debug!(">> typechecking %s", fcx.expr_to_str(expr));
|
debug!(">> typechecking %s", fcx.expr_to_str(expr));
|
||||||
|
|
||||||
// A generic function to factor out common logic from call and
|
fn check_argument_types(
|
||||||
// overloaded operations
|
|
||||||
fn check_call_inner(
|
|
||||||
fcx: @mut FnCtxt,
|
fcx: @mut FnCtxt,
|
||||||
sp: span,
|
sp: span,
|
||||||
call_expr_id: ast::node_id,
|
call_expr_id: ast::node_id,
|
||||||
|
@ -1134,18 +1132,24 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
sugar: ast::CallSugar,
|
sugar: ast::CallSugar,
|
||||||
deref_args: DerefArgs) -> ty::t
|
deref_args: DerefArgs) -> ty::t
|
||||||
{
|
{
|
||||||
|
/*!
|
||||||
|
*
|
||||||
|
* Generic function that factors out common logic from
|
||||||
|
* function calls, method calls and overloaded operators.
|
||||||
|
*/
|
||||||
|
|
||||||
let tcx = fcx.ccx.tcx;
|
let tcx = fcx.ccx.tcx;
|
||||||
|
|
||||||
// Replace all region parameters in the arguments and return
|
// Replace all region parameters in the arguments and return
|
||||||
// type with fresh region variables.
|
// type with fresh region variables.
|
||||||
|
|
||||||
debug!("check_call_inner: before universal quant., in_fty=%s",
|
debug!("check_argument_types: before universal quant., in_fty=%s",
|
||||||
fcx.infcx().ty_to_str(in_fty));
|
fcx.infcx().ty_to_str(in_fty));
|
||||||
|
|
||||||
let formal_tys;
|
let sty = structure_of(fcx, sp, in_fty);
|
||||||
|
|
||||||
// FIXME(#3678) For now, do not permit calls to C abi functions.
|
// FIXME(#3678) For now, do not permit calls to C abi functions.
|
||||||
match structure_of(fcx, sp, in_fty) {
|
match sty {
|
||||||
ty::ty_bare_fn(ty::BareFnTy {abis, _}) => {
|
ty::ty_bare_fn(ty::BareFnTy {abis, _}) => {
|
||||||
if !abis.is_rust() {
|
if !abis.is_rust() {
|
||||||
tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
|
@ -1157,68 +1161,65 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is subtle: we expect `fty` to be a function type, which
|
// Extract the function signature from `in_fty`.
|
||||||
// normally introduce a level of binding. In this case, we want to
|
let sig = match sty {
|
||||||
// process the types bound by the function but not by any nested
|
ty::ty_bare_fn(ty::BareFnTy {sig: sig, _}) |
|
||||||
// functions. Therefore, we match one level of structure.
|
ty::ty_closure(ty::ClosureTy {sig: sig, _}) => sig,
|
||||||
let ret_ty = match structure_of(fcx, sp, in_fty) {
|
|
||||||
ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) |
|
|
||||||
ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => {
|
|
||||||
let (_, _, sig) =
|
|
||||||
replace_bound_regions_in_fn_sig(
|
|
||||||
tcx, @Nil, None, sig,
|
|
||||||
|_br| fcx.infcx().next_region_var(
|
|
||||||
sp, call_expr_id));
|
|
||||||
|
|
||||||
let supplied_arg_count = args.len();
|
|
||||||
|
|
||||||
// Grab the argument types, supplying fresh type variables
|
|
||||||
// if the wrong number of arguments were supplied
|
|
||||||
let expected_arg_count = sig.inputs.len();
|
|
||||||
formal_tys = if expected_arg_count == supplied_arg_count {
|
|
||||||
sig.inputs.map(|a| a.ty)
|
|
||||||
} else {
|
|
||||||
let suffix = match sugar {
|
|
||||||
ast::NoSugar => "",
|
|
||||||
ast::DoSugar => " (including the closure passed by \
|
|
||||||
the `do` keyword)",
|
|
||||||
ast::ForSugar => " (including the closure passed by \
|
|
||||||
the `for` keyword)"
|
|
||||||
};
|
|
||||||
let msg = fmt!("this function takes %u parameter%s but \
|
|
||||||
%u parameter%s supplied%s",
|
|
||||||
expected_arg_count,
|
|
||||||
if expected_arg_count == 1 {""}
|
|
||||||
else {"s"},
|
|
||||||
supplied_arg_count,
|
|
||||||
if supplied_arg_count == 1 {" was"}
|
|
||||||
else {"s were"},
|
|
||||||
suffix);
|
|
||||||
|
|
||||||
tcx.sess.span_err(sp, msg);
|
|
||||||
|
|
||||||
vec::from_fn(supplied_arg_count, |_| ty::mk_err(tcx))
|
|
||||||
};
|
|
||||||
|
|
||||||
sig.output
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
fcx.type_error_message(sp, |actual| {
|
fcx.type_error_message(sp, |actual| {
|
||||||
fmt!("expected function or foreign function but \
|
fmt!("expected function but \
|
||||||
found `%s`", actual) }, in_fty, None);
|
found `%s`", actual) }, in_fty, None);
|
||||||
|
|
||||||
// check each arg against "error", in order to set up
|
// check each arg against "error", in order to set up
|
||||||
// all the node type bindings
|
// all the node type bindings
|
||||||
formal_tys = args.map(|_x| ty::mk_err(tcx));
|
FnSig {bound_lifetime_names: opt_vec::Empty,
|
||||||
ty::mk_err(tcx)
|
inputs: args.map(|_x| ty::arg {mode: ast::expl(ast::by_copy),
|
||||||
|
ty: ty::mk_err(tcx)}),
|
||||||
|
output: ty::mk_err(tcx)}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("check_call_inner: after universal quant., \
|
// Replace any bound regions that appear in the function
|
||||||
formal_tys=%? ret_ty=%s",
|
// signature with region variables
|
||||||
|
let (_, _, sig) =
|
||||||
|
replace_bound_regions_in_fn_sig(
|
||||||
|
tcx, @Nil, None, &sig,
|
||||||
|
|_br| fcx.infcx().next_region_var(
|
||||||
|
sp, call_expr_id));
|
||||||
|
|
||||||
|
// Grab the argument types, supplying fresh type variables
|
||||||
|
// if the wrong number of arguments were supplied
|
||||||
|
let supplied_arg_count = args.len();
|
||||||
|
let expected_arg_count = sig.inputs.len();
|
||||||
|
let formal_tys = if expected_arg_count == supplied_arg_count {
|
||||||
|
sig.inputs.map(|a| a.ty)
|
||||||
|
} else {
|
||||||
|
let suffix = match sugar {
|
||||||
|
ast::NoSugar => "",
|
||||||
|
ast::DoSugar => " (including the closure passed by \
|
||||||
|
the `do` keyword)",
|
||||||
|
ast::ForSugar => " (including the closure passed by \
|
||||||
|
the `for` keyword)"
|
||||||
|
};
|
||||||
|
let msg = fmt!("this function takes %u parameter%s but \
|
||||||
|
%u parameter%s supplied%s",
|
||||||
|
expected_arg_count,
|
||||||
|
if expected_arg_count == 1 {""}
|
||||||
|
else {"s"},
|
||||||
|
supplied_arg_count,
|
||||||
|
if supplied_arg_count == 1 {" was"}
|
||||||
|
else {"s were"},
|
||||||
|
suffix);
|
||||||
|
|
||||||
|
tcx.sess.span_err(sp, msg);
|
||||||
|
|
||||||
|
vec::from_elem(supplied_arg_count, ty::mk_err(tcx))
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("check_argument_types: after universal quant., \
|
||||||
|
formal_tys=%? sig.output=%s",
|
||||||
formal_tys.map(|t| fcx.infcx().ty_to_str(*t)),
|
formal_tys.map(|t| fcx.infcx().ty_to_str(*t)),
|
||||||
fcx.infcx().ty_to_str(ret_ty));
|
fcx.infcx().ty_to_str(sig.output));
|
||||||
|
|
||||||
// Check the arguments.
|
// Check the arguments.
|
||||||
// We do this in a pretty awful way: first we typecheck any arguments
|
// We do this in a pretty awful way: first we typecheck any arguments
|
||||||
|
@ -1269,7 +1270,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret_ty
|
sig.output
|
||||||
}
|
}
|
||||||
|
|
||||||
// A generic function for checking assignment expressions
|
// A generic function for checking assignment expressions
|
||||||
|
@ -1284,43 +1285,23 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
// The callee checks for bot / err, we don't need to
|
// The callee checks for bot / err, we don't need to
|
||||||
}
|
}
|
||||||
|
|
||||||
// A generic function for doing all of the checking for call or
|
|
||||||
// method expressions
|
|
||||||
fn check_call_or_method(fcx: @mut FnCtxt,
|
|
||||||
sp: span,
|
|
||||||
call_expr_id: ast::node_id,
|
|
||||||
fn_ty: ty::t,
|
|
||||||
expr: @ast::expr,
|
|
||||||
args: &[@ast::expr],
|
|
||||||
sugar: ast::CallSugar)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Call the generic checker.
|
|
||||||
let ret_ty = check_call_inner(fcx, sp, call_expr_id,
|
|
||||||
fn_ty, expr, args, sugar,
|
|
||||||
DontDerefArgs);
|
|
||||||
// Pull the return type out of the type of the function.
|
|
||||||
fcx.write_ty(call_expr_id, ret_ty);
|
|
||||||
// Callee checks for bot and err, no need for that
|
|
||||||
}
|
|
||||||
|
|
||||||
// A generic function for doing all of the checking for call expressions
|
// A generic function for doing all of the checking for call expressions
|
||||||
fn check_call(fcx: @mut FnCtxt,
|
fn check_call(fcx: @mut FnCtxt,
|
||||||
sp: span,
|
call_expr: @ast::expr,
|
||||||
call_expr_id: ast::node_id,
|
|
||||||
f: @ast::expr,
|
f: @ast::expr,
|
||||||
args: &[@ast::expr],
|
args: &[@ast::expr],
|
||||||
sugar: ast::CallSugar) {
|
sugar: ast::CallSugar) {
|
||||||
// Index expressions need to be handled separately, to inform them
|
// Index expressions need to be handled separately, to inform them
|
||||||
// that they appear in call position.
|
// that they appear in call position.
|
||||||
let mut _bot = check_expr(fcx, f);
|
check_expr(fcx, f);
|
||||||
check_call_or_method(fcx,
|
|
||||||
sp,
|
// Call the generic checker.
|
||||||
call_expr_id,
|
let ret_ty = check_argument_types(fcx, call_expr.span, call_expr.id,
|
||||||
fcx.expr_ty(f),
|
fcx.expr_ty(f), f, args, sugar,
|
||||||
f,
|
DontDerefArgs);
|
||||||
args,
|
|
||||||
sugar)
|
// Pull the return type out of the type of the function.
|
||||||
|
fcx.write_ty(call_expr.id, ret_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks a method call.
|
// Checks a method call.
|
||||||
|
@ -1369,13 +1350,14 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check_call_or_method(fcx,
|
// Call the generic checker.
|
||||||
expr.span,
|
let fn_ty = fcx.node_ty(expr.callee_id);
|
||||||
expr.id,
|
let ret_ty = check_argument_types(fcx, expr.span, expr.id,
|
||||||
fcx.node_ty(expr.callee_id),
|
fn_ty, expr, args, sugar,
|
||||||
expr,
|
DontDerefArgs);
|
||||||
args,
|
|
||||||
sugar)
|
// Pull the return type out of the type of the function.
|
||||||
|
fcx.write_ty(expr.id, ret_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A generic function for checking the then and else in an if
|
// A generic function for checking the then and else in an if
|
||||||
|
@ -1423,10 +1405,10 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
let method_ty = fcx.node_ty(op_ex.callee_id);
|
let method_ty = fcx.node_ty(op_ex.callee_id);
|
||||||
let method_map = fcx.inh.method_map;
|
let method_map = fcx.inh.method_map;
|
||||||
method_map.insert(op_ex.id, *origin);
|
method_map.insert(op_ex.id, *origin);
|
||||||
check_call_inner(fcx, op_ex.span,
|
check_argument_types(fcx, op_ex.span,
|
||||||
op_ex.id, method_ty,
|
op_ex.id, method_ty,
|
||||||
op_ex, args,
|
op_ex, args,
|
||||||
ast::NoSugar, deref_args)
|
ast::NoSugar, deref_args)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let tcx = fcx.tcx();
|
let tcx = fcx.tcx();
|
||||||
|
@ -1434,9 +1416,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
// Check the args anyway
|
// Check the args anyway
|
||||||
// so we get all the error messages
|
// so we get all the error messages
|
||||||
let expected_ty = ty::mk_err(tcx);
|
let expected_ty = ty::mk_err(tcx);
|
||||||
check_call_inner(fcx, op_ex.span, op_ex.id,
|
check_argument_types(fcx, op_ex.span, op_ex.id,
|
||||||
expected_ty, op_ex, args,
|
expected_ty, op_ex, args,
|
||||||
ast::NoSugar, deref_args);
|
ast::NoSugar, deref_args);
|
||||||
ty::mk_err(tcx)
|
ty::mk_err(tcx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2546,7 +2528,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
|
||||||
fcx.write_ty(id, fcx.node_ty(b.node.id));
|
fcx.write_ty(id, fcx.node_ty(b.node.id));
|
||||||
}
|
}
|
||||||
ast::expr_call(f, ref args, sugar) => {
|
ast::expr_call(f, ref args, sugar) => {
|
||||||
check_call(fcx, expr.span, expr.id, f, *args, sugar);
|
check_call(fcx, expr, f, *args, sugar);
|
||||||
let f_ty = fcx.expr_ty(f);
|
let f_ty = fcx.expr_ty(f);
|
||||||
let (args_bot, args_err) = args.foldl((false, false),
|
let (args_bot, args_err) = args.foldl((false, false),
|
||||||
|&(rest_bot, rest_err), a| {
|
|&(rest_bot, rest_err), a| {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue