diff src/vim9compile.c @ 24272:cabed216cc2f v8.2.2677

patch 8.2.2677: Vim9: cannot use only some of the default arguments Commit: https://github.com/vim/vim/commit/38a3bfa9a2931729a5e0c28dc087f745b68988ef Author: Bram Moolenaar <Bram@vim.org> Date: Mon Mar 29 22:14:55 2021 +0200 patch 8.2.2677: Vim9: cannot use only some of the default arguments Problem: Vim9: cannot use only some of the default arguments. Solution: Use v:none to use default argument value. Remove uf_def_arg_idx[], use JUMP_IF_ARG_SET. (closes #6504)
author Bram Moolenaar <Bram@vim.org>
date Mon, 29 Mar 2021 22:15:03 +0200
parents d0e86f1b34e7
children bcfff560e089
line wrap: on
line diff
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1629,6 +1629,22 @@ generate_JUMP(cctx_T *cctx, jumpwhen_T w
     return OK;
 }
 
+/*
+ * Generate an ISN_JUMP_IF_ARG_SET instruction.
+ */
+    static int
+generate_JUMP_IF_ARG_SET(cctx_T *cctx, int arg_off)
+{
+    isn_T	*isn;
+
+    RETURN_OK_IF_SKIP(cctx);
+    if ((isn = generate_instr(cctx, ISN_JUMP_IF_ARG_SET)) == NULL)
+	return FAIL;
+    isn->isn_arg.jumparg.jump_arg_off = arg_off;
+    // jump_where is set later
+    return OK;
+}
+
     static int
 generate_FOR(cctx_T *cctx, int loop_idx)
 {
@@ -1834,6 +1850,13 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufu
 	    type_T *expected;
 	    type_T *actual;
 
+	    actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
+	    if (actual == &t_special
+			      && i >= regular_args - ufunc->uf_def_args.ga_len)
+	    {
+		// assume v:none used for default argument value
+		continue;
+	    }
 	    if (i < regular_args)
 	    {
 		if (ufunc->uf_arg_types == NULL)
@@ -1845,7 +1868,6 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufu
 		expected = &t_any;
 	    else
 		expected = ufunc->uf_va_type->tt_member;
-	    actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
 	    if (need_type(actual, expected, -argcount + i, i + 1, cctx,
 							  TRUE, FALSE) == FAIL)
 	    {
@@ -1961,6 +1983,9 @@ generate_PCALL(
 		    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 == &t_special)
+			expected = &t_any;
 		    else
 			expected = type->tt_args[i];
 		    if (need_type(actual, expected, offset, i + 1,
@@ -8363,12 +8388,6 @@ compile_def_function(
 	int	did_set_arg_type = FALSE;
 
 	// Produce instructions for the default values of optional arguments.
-	// Store the instruction index in uf_def_arg_idx[] so that we know
-	// where to start when the function is called, depending on the number
-	// of arguments.
-	ufunc->uf_def_arg_idx = ALLOC_CLEAR_MULT(int, count + 1);
-	if (ufunc->uf_def_arg_idx == NULL)
-	    goto erret;
 	SOURCING_LNUM = 0;  // line number unknown
 	for (i = 0; i < count; ++i)
 	{
@@ -8377,11 +8396,16 @@ compile_def_function(
 	    int		arg_idx = first_def_arg + i;
 	    where_T	where;
 	    int		r;
+	    int		jump_instr_idx = instr->ga_len;
+	    isn_T	*isn;
+
+	    // Use a JUMP_IF_ARG_SET instruction to skip if the value was given.
+	    if (generate_JUMP_IF_ARG_SET(&cctx, i - count - off) == FAIL)
+		goto erret;
 
 	    // Make sure later arguments are not found.
 	    ufunc->uf_args.ga_len = i;
 
-	    ufunc->uf_def_arg_idx[i] = instr->ga_len;
 	    arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i];
 	    r = compile_expr0(&arg, &cctx);
 
@@ -8406,8 +8430,11 @@ compile_def_function(
 
 	    if (generate_STORE(&cctx, ISN_STORE, i - count - off, NULL) == FAIL)
 		goto erret;
-	}
-	ufunc->uf_def_arg_idx[count] = instr->ga_len;
+
+	    // set instruction index in JUMP_IF_ARG_SET to here
+	    isn = ((isn_T *)instr->ga_data) + jump_instr_idx;
+	    isn->isn_arg.jumparg.jump_where = instr->ga_len;
+	}
 
 	if (did_set_arg_type)
 	    set_function_type(ufunc);
@@ -9114,6 +9141,7 @@ delete_instr(isn_T *isn)
 	case ISN_FOR:
 	case ISN_GETITEM:
 	case ISN_JUMP:
+	case ISN_JUMP_IF_ARG_SET:
 	case ISN_LISTAPPEND:
 	case ISN_LISTINDEX:
 	case ISN_LISTSLICE: