]> granicus.if.org Git - vim/commitdiff
patch 8.2.0528: Vim9: function arguments insufficiently tested v8.2.0528
authorBram Moolenaar <Bram@vim.org>
Tue, 7 Apr 2020 20:05:08 +0000 (22:05 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 7 Apr 2020 20:05:08 +0000 (22:05 +0200)
Problem:    Vim9: function arguments insufficiently tested.
Solution:   Check types.  Add more tests.  Fix function with varargs only.

src/testdir/test_vim9_func.vim
src/userfunc.c
src/version.c
src/vim9compile.c

index fb2180fc93037a69b3f85689eee0e5e99ce595db..558f23cb4718a1c6456c3e41c7d504e6f76d1f69 100644 (file)
@@ -130,6 +130,19 @@ def Test_call_def_varargs()
   assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
 enddef
 
+" Only varargs
+def MyVarargsOnly(...args: list<string>): string
+  return join(args, ',')
+enddef
+
+def Test_call_varargs_only()
+  assert_equal('', MyVarargsOnly())
+  assert_equal('one', MyVarargsOnly('one'))
+  assert_equal('one,two', MyVarargsOnly('one', 'two'))
+  call CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: argument 1: type mismatch, expected string but got number')
+  call CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: argument 2: type mismatch, expected string but got number')
+enddef
+
 def Test_using_var_as_arg()
   call writefile(['def Func(x: number)',  'let x = 234', 'enddef'], 'Xdef')
   call assert_fails('so Xdef', 'E1006:')
index f93c1492c4646f811a210633a83d34e97142030e..69a57c28d1f0d84a57dafe96a1636cb4fd918eb5 100644 (file)
@@ -3020,7 +3020,7 @@ ex_function(exarg_T *eap)
 
     if (eap->cmdidx == CMD_def)
     {
-       int lnum_save = SOURCING_LNUM;
+       int     lnum_save = SOURCING_LNUM;
 
        // error messages are for the first function line
        SOURCING_LNUM = sourcing_lnum_top;
@@ -3034,7 +3034,8 @@ ex_function(exarg_T *eap)
            // and uf_va_type.
            int len = argtypes.ga_len - (varargs ? 1 : 0);
 
-           fp->uf_arg_types = ALLOC_CLEAR_MULT(type_T *, len);
+           if (len > 0)
+               fp->uf_arg_types = ALLOC_CLEAR_MULT(type_T *, len);
            if (fp->uf_arg_types != NULL)
            {
                int     i;
index f08ca11d3f451ba073a2f45ef46a2cf8fcffa263..3518aecab84db5603f9a4e3498c86a7f162eac98 100644 (file)
@@ -738,6 +738,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    528,
 /**/
     527,
 /**/
index 18fbdd36ed882a758bb79cb0fc01e363f43a9bfd..fb0adb3b42a1ee26868de38ceb7b5e134a544f7f 100644 (file)
@@ -130,6 +130,8 @@ static int compile_expr1(char_u **arg,  cctx_T *cctx);
 static int compile_expr2(char_u **arg,  cctx_T *cctx);
 static int compile_expr3(char_u **arg,  cctx_T *cctx);
 static void delete_def_function_contents(dfunc_T *dfunc);
+static void arg_type_mismatch(type_T *expected, type_T *actual, int argidx);
+static int check_type(type_T *expected, type_T *actual, int give_msg);
 
 /*
  * Lookup variable "name" in the local scope and return the index.
@@ -1240,6 +1242,32 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
        return FAIL;
     }
 
+    if (ufunc->uf_dfunc_idx >= 0)
+    {
+       int             i;
+
+       for (i = 0; i < argcount; ++i)
+       {
+           type_T *expected;
+           type_T *actual;
+
+           if (i < regular_args)
+           {
+               if (ufunc->uf_arg_types == NULL)
+                   continue;
+               expected = ufunc->uf_arg_types[i];
+           }
+           else
+               expected = ufunc->uf_va_type->tt_member;
+           actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
+           if (check_type(expected, actual, FALSE) == FAIL)
+           {
+               arg_type_mismatch(expected, actual, i + 1);
+               return FAIL;
+           }
+       }
+    }
+
     // Turn varargs into a list.
     if (ufunc->uf_va_name != NULL)
     {
@@ -2403,6 +2431,18 @@ type_mismatch(type_T *expected, type_T *actual)
     vim_free(tofree2);
 }
 
+    static void
+arg_type_mismatch(type_T *expected, type_T *actual, int argidx)
+{
+    char *tofree1, *tofree2;
+
+    semsg(_("E1013: argument %d: type mismatch, expected %s but got %s"),
+           argidx,
+           type_name(expected, &tofree1), type_name(actual, &tofree2));
+    vim_free(tofree1);
+    vim_free(tofree2);
+}
+
 /*
  * Check if the expected and actual types match.
  */