summaryrefslogtreecommitdiff
path: root/src/vim9instr.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-09-08 19:51:45 +0100
committerBram Moolenaar <Bram@vim.org>2022-09-08 19:51:45 +0100
commit169003289fb4b2ad18fd7f5807e0d05efff0be85 (patch)
tree50602045f6b4e7ed30d2498bef163412839c8776 /src/vim9instr.c
parent45bbaef0382c5468d9fac511775bd99ea7bf5b84 (diff)
downloadvim-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.c169
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