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