diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-09-08 19:51:45 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-09-08 19:51:45 +0100 |
commit | 169003289fb4b2ad18fd7f5807e0d05efff0be85 (patch) | |
tree | 50602045f6b4e7ed30d2498bef163412839c8776 /src/vim9instr.c | |
parent | 45bbaef0382c5468d9fac511775bd99ea7bf5b84 (diff) | |
download | vim-git-169003289fb4b2ad18fd7f5807e0d05efff0be85.tar.gz |
patch 9.0.0419: the :defer command does not check the function argumentsv9.0.0419
Problem: The :defer command does not check the function argument count and
types.
Solution: Check the function arguments when adding a deferred function.
Diffstat (limited to 'src/vim9instr.c')
-rw-r--r-- | src/vim9instr.c | 169 |
1 files changed, 105 insertions, 64 deletions
diff --git a/src/vim9instr.c b/src/vim9instr.c index 34d4ae33f..6a387fa51 100644 --- a/src/vim9instr.c +++ b/src/vim9instr.c @@ -1329,33 +1329,31 @@ generate_TRYCONT(cctx_T *cctx, int levels, int where) return OK; } - /* - * Generate an ISN_BCALL instruction. - * "method_call" is TRUE for "value->method()" - * Return FAIL if the number of arguments is wrong. + * 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 -generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call) +check_internal_func_args( + cctx_T *cctx, + int func_idx, + int argcount, + int method_call, + type2_T **argtypes, + type2_T *shuffled_argtypes) { - 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; - type_T *type; - type_T *decl_type; + int argoff = check_internal_func(func_idx, argcount); - RETURN_OK_IF_SKIP(cctx); - argoff = check_internal_func(func_idx, argcount); if (argoff < 0) return FAIL; if (method_call && argoff > 1) { - if ((isn = generate_instr(cctx, ISN_SHUFFLE)) == NULL) + 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; @@ -1363,17 +1361,18 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call) if (argcount > 0) { + type2_T *typep = ((type2_T *)stack->ga_data) + stack->ga_len - argcount; + // 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; + ? typep[i + 1] + : (i == argoff - 1) ? typep[0] : typep[i]; + *argtypes = shuffled_argtypes; } else { @@ -1381,14 +1380,39 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call) for (i = 0; i < argcount; ++i) shuffled_argtypes[i] = typep[i]; - argtypes = shuffled_argtypes; + *argtypes = shuffled_argtypes; } - if (internal_func_check_arg_types(argtypes, func_idx, argcount, + if (internal_func_check_arg_types(*argtypes, func_idx, argcount, cctx) == FAIL) return FAIL; - if (internal_func_is_map(func_idx)) - maptype = argtypes; } + return OK; +} + +/* + * Generate an ISN_BCALL instruction. + * "method_call" is TRUE for "value->method()" + * Return FAIL if the number of arguments is wrong. + */ + int +generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call) +{ + isn_T *isn; + garray_T *stack = &cctx->ctx_type_stack; + type2_T *argtypes = NULL; + type2_T shuffled_argtypes[MAX_FUNC_ARGS]; + type2_T *maptype = NULL; + type_T *type; + type_T *decl_type; + + RETURN_OK_IF_SKIP(cctx); + + if (check_internal_func_args(cctx, func_idx, argcount, method_call, + &argtypes, shuffled_argtypes) == FAIL) + return FAIL; + + 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 *name, int argcount) } /* + * 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 |