Mercurial > vim
diff src/vim9instr.c @ 30166:d1c04b4dc60d v9.0.0419
patch 9.0.0419: the :defer command does not check the function arguments
Commit: https://github.com/vim/vim/commit/169003289fb4b2ad18fd7f5807e0d05efff0be85
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Sep 8 19:51:45 2022 +0100
patch 9.0.0419: the :defer command does not check the function arguments
Problem: The :defer command does not check the function argument count and
types.
Solution: Check the function arguments when adding a deferred function.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 08 Sep 2022 21:00:04 +0200 |
parents | d45ee1f829ba |
children | 42a6345b91fd |
line wrap: on
line diff
--- a/src/vim9instr.c +++ b/src/vim9instr.c @@ -1329,6 +1329,65 @@ generate_TRYCONT(cctx_T *cctx, int level return OK; } +/* + * Check "argount" arguments and their types on the type stack. + * Give an error and return FAIL if something is wrong. + * When "method_call" is NULL no code is generated. + */ + int +check_internal_func_args( + cctx_T *cctx, + int func_idx, + int argcount, + int method_call, + type2_T **argtypes, + type2_T *shuffled_argtypes) +{ + garray_T *stack = &cctx->ctx_type_stack; + int argoff = check_internal_func(func_idx, argcount); + + if (argoff < 0) + return FAIL; + + if (method_call && argoff > 1) + { + isn_T *isn = generate_instr(cctx, ISN_SHUFFLE); + + if (isn == NULL) + return FAIL; + isn->isn_arg.shuffle.shfl_item = argcount; + isn->isn_arg.shuffle.shfl_up = argoff - 1; + } + + if (argcount > 0) + { + type2_T *typep = ((type2_T *)stack->ga_data) + stack->ga_len - argcount; + + // Check the types of the arguments. + if (method_call && argoff > 1) + { + int i; + + for (i = 0; i < argcount; ++i) + shuffled_argtypes[i] = (i < argoff - 1) + ? typep[i + 1] + : (i == argoff - 1) ? typep[0] : typep[i]; + *argtypes = shuffled_argtypes; + } + else + { + int i; + + for (i = 0; i < argcount; ++i) + shuffled_argtypes[i] = typep[i]; + *argtypes = shuffled_argtypes; + } + if (internal_func_check_arg_types(*argtypes, func_idx, argcount, + cctx) == FAIL) + return FAIL; + } + return OK; +} /* * Generate an ISN_BCALL instruction. @@ -1340,8 +1399,6 @@ generate_BCALL(cctx_T *cctx, int func_id { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; - int argoff; - type2_T *typep; type2_T *argtypes = NULL; type2_T shuffled_argtypes[MAX_FUNC_ARGS]; type2_T *maptype = NULL; @@ -1349,46 +1406,13 @@ generate_BCALL(cctx_T *cctx, int func_id type_T *decl_type; RETURN_OK_IF_SKIP(cctx); - argoff = check_internal_func(func_idx, argcount); - if (argoff < 0) + + if (check_internal_func_args(cctx, func_idx, argcount, method_call, + &argtypes, shuffled_argtypes) == FAIL) return FAIL; - if (method_call && argoff > 1) - { - if ((isn = generate_instr(cctx, ISN_SHUFFLE)) == NULL) - return FAIL; - isn->isn_arg.shuffle.shfl_item = argcount; - isn->isn_arg.shuffle.shfl_up = argoff - 1; - } - - if (argcount > 0) - { - // Check the types of the arguments. - typep = ((type2_T *)stack->ga_data) + stack->ga_len - argcount; - if (method_call && argoff > 1) - { - int i; - - for (i = 0; i < argcount; ++i) - shuffled_argtypes[i] = (i < argoff - 1) - ? typep[i + 1] - : (i == argoff - 1) ? typep[0] : typep[i]; - argtypes = shuffled_argtypes; - } - else - { - int i; - - for (i = 0; i < argcount; ++i) - shuffled_argtypes[i] = typep[i]; - argtypes = shuffled_argtypes; - } - if (internal_func_check_arg_types(argtypes, func_idx, argcount, - cctx) == FAIL) - return FAIL; - if (internal_func_is_map(func_idx)) - maptype = argtypes; - } + if (internal_func_is_map(func_idx)) + maptype = argtypes; if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL) return FAIL; @@ -1578,6 +1602,61 @@ generate_UCALL(cctx_T *cctx, char_u *nam } /* + * Check the arguments of function "type" against the types on the stack. + * Returns OK or FAIL; + */ + int +check_func_args_from_type( + cctx_T *cctx, + type_T *type, + int argcount, + int at_top, + char_u *name) +{ + if (type->tt_argcount != -1) + { + int varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0; + + if (argcount < type->tt_min_argcount - varargs) + { + emsg_funcname(e_not_enough_arguments_for_function_str, name); + return FAIL; + } + if (!varargs && argcount > type->tt_argcount) + { + emsg_funcname(e_too_many_arguments_for_function_str, name); + return FAIL; + } + if (type->tt_args != NULL) + { + int i; + + for (i = 0; i < argcount; ++i) + { + int offset = -argcount + i - (at_top ? 0 : 1); + type_T *actual = get_type_on_stack(cctx, -1 - offset); + type_T *expected; + + if (varargs && i >= type->tt_argcount - 1) + expected = type->tt_args[type->tt_argcount - 1]->tt_member; + else if (i >= type->tt_min_argcount + && actual->tt_type == VAR_SPECIAL) + expected = &t_any; + else + expected = type->tt_args[i]; + if (need_type(actual, expected, offset, i + 1, + cctx, TRUE, FALSE) == FAIL) + { + arg_type_mismatch(expected, actual, i + 1); + return FAIL; + } + } + } + } + + return OK; +} +/* * Generate an ISN_PCALL instruction. * "type" is the type of the FuncRef. */ @@ -1598,47 +1677,9 @@ generate_PCALL( ret_type = &t_any; else if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL) { - if (type->tt_argcount != -1) - { - int varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0; - - if (argcount < type->tt_min_argcount - varargs) - { - emsg_funcname(e_not_enough_arguments_for_function_str, name); - return FAIL; - } - if (!varargs && argcount > type->tt_argcount) - { - emsg_funcname(e_too_many_arguments_for_function_str, name); - return FAIL; - } - if (type->tt_args != NULL) - { - int i; + if (check_func_args_from_type(cctx, type, argcount, at_top, name) == FAIL) + return FAIL; - for (i = 0; i < argcount; ++i) - { - int offset = -argcount + i - (at_top ? 0 : 1); - type_T *actual = get_type_on_stack(cctx, -1 - offset); - type_T *expected; - - if (varargs && i >= type->tt_argcount - 1) - expected = type->tt_args[ - type->tt_argcount - 1]->tt_member; - else if (i >= type->tt_min_argcount - && actual->tt_type == VAR_SPECIAL) - expected = &t_any; - else - expected = type->tt_args[i]; - if (need_type(actual, expected, offset, i + 1, - cctx, TRUE, FALSE) == FAIL) - { - arg_type_mismatch(expected, actual, i + 1); - return FAIL; - } - } - } - } ret_type = type->tt_member; if (ret_type == &t_unknown) // return type not known yet, use a runtime check