patch 8.2.5026: Vim9: a few lines not covered by tests v8.2.5026
authorBram Moolenaar <Bram@vim.org>
Thu, 26 May 2022 21:24:43 +0000 (22:24 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 26 May 2022 21:24:43 +0000 (22:24 +0100)
Problem:    Vim9: a few lines not covered by tests.
Solution:   Delete dead code.  Add a few test cases. make "12->func()" work.

src/ex_docmd.c
src/proto/ex_docmd.pro
src/testdir/test_vim9_assign.vim
src/testdir/test_vim9_func.vim
src/version.c
src/vim9compile.c
src/vim9type.c

index 6cf77155cacdba9272326936884c22b0a36fe8a4..048c224362c796e378acb0d7b4f399998b965d4f 100644 (file)
@@ -3506,6 +3506,18 @@ one_letter_cmd(char_u *p, cmdidx_T *idx)
     return FALSE;
 }
 
+/*
+ * Return TRUE if "cmd" starts with "123->", a number followed by a method
+ * call.
+ */
+    int
+number_method(char_u *cmd)
+{
+    char_u *p = skipdigits(cmd);
+
+    return p > cmd && (p = skipwhite(p))[0] == '-' && p[1] == '>';
+}
+
 /*
  * Find an Ex command by its name, either built-in or user.
  * Start of the name can be found at eap->cmd.
@@ -3716,6 +3728,13 @@ find_ex_command(
            }
        }
 
+       // 1234->func() is a method call
+       if (number_method(eap->cmd))
+       {
+           eap->cmdidx = CMD_eval;
+           return eap->cmd;
+       }
+
        // "g:", "s:" and "l:" are always assumed to be a variable, thus start
        // an expression.  A global/substitute/list command needs to use a
        // longer name.
index d67cb9a91c563019db7db9dcad463b6c30509c29..28f4c43dc5e352fc39a7dde68e0288fe99d9d650 100644 (file)
@@ -17,6 +17,7 @@ void apply_cmdmod(cmdmod_T *cmod);
 void undo_cmdmod(cmdmod_T *cmod);
 int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
 char_u *skip_option_env_lead(char_u *start);
+int number_method(char_u *cmd);
 char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, int cmd, cctx_T *), cctx_T *cctx);
 int modifier_len(char_u *cmd);
 int cmd_exists(char_u *name);
index b0ce398568a84e6dc126a65c24970d5e8b889d94..faa4928ea58f3f0930a83d1952cd84e4e22d9acf 100644 (file)
@@ -1121,6 +1121,9 @@ def Test_assignment_dict()
   var dict4: dict<any> = {one: 1, two: '2'}
   var dict5: dict<blob> = {one: 0z01, two: 0z02}
 
+  # check the type is OK
+  var events: dict<string> = v:event
+
   # overwrite
   dict3['key'] = 'another'
   assert_equal(dict3, {key: 'another'})
@@ -2105,6 +2108,32 @@ def Test_var_declaration_fails()
       va foo = 123
   END
   v9.CheckDefAndScriptFailure(lines, 'E1065:', 1)
+
+  lines =<< trim END
+      var foo: func(number
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E110:', 1)
+
+  lines =<< trim END
+      var foo: func(number): func(
+  END
+  v9.CheckDefAndScriptFailure(lines, 'E110:', 1)
+
+  for type in ['num_ber',
+               'anys', 'ani',
+               'bools', 'boel',
+               'blobs', 'blub',
+               'channels', 'channol',
+               'dicts', 'duct',
+               'floats', 'floot',
+               'funcs', 'funk',
+               'jobs', 'jop',
+               'lists', 'last'
+               'numbers', 'numbar',
+               'strings', 'strung',
+               'voids', 'viod']
+    v9.CheckDefAndScriptFailure([$'var foo: {type}'], 'E1010:', 1)
+  endfor
 enddef
 
 def Test_var_declaration_inferred()
@@ -2118,6 +2147,34 @@ def Test_var_declaration_inferred()
       echo GetList()->extend(['x'])
   END
   v9.CheckScriptFailure(lines, 'E1013:', 6)
+
+  lines =<< trim END
+      vim9script
+      def GetNr(): number
+        return 5
+      enddef
+      def TestOne()
+        var some = [function('len'), GetNr]
+        g:res = typename(some)
+      enddef
+      TestOne()
+      assert_equal('list<func(): number>', g:res)
+
+      def TestTwo()
+        var some = [function('len'), GetNr]
+        g:res = typename(some)
+      enddef
+      TestTwo()
+      assert_equal('list<func(): number>', g:res)
+      unlet g:res
+
+      # FIXME: why is the type different?
+      var first = [function('len'), GetNr]
+      assert_equal('list<func(...): number>', typename(first))
+      var second = [GetNr, function('len')]
+      assert_equal('list<func(...): number>', typename(second))
+  END
+  v9.CheckScriptSuccess(lines)
 enddef
 
 def Test_script_local_in_legacy()
index fcf37d5f51f3e1ec2bb71e7b40613595483873b6..33a66151e7bde895e6ddaa85a3a54b500b16ffe3 100644 (file)
@@ -4051,6 +4051,63 @@ def Test_too_many_arguments()
     echo [0, 1, 2]->map((_) => 123)
   END
   v9.CheckDefAndScriptFailure(lines, ['E176', 'E1106: One argument too many'], 1)
+
+  lines =<< trim END
+      vim9script
+      def OneArgument(arg: string)
+        echo arg
+      enddef
+      var Ref = OneArgument
+      Ref('a', 'b')
+  END
+  v9.CheckScriptFailure(lines, 'E118:')
+enddef
+
+def Test_funcref_with_base()
+  var lines =<< trim END
+      vim9script
+      def TwoArguments(str: string, nr: number)
+        echo str nr
+      enddef
+      var Ref = TwoArguments
+      Ref('a', 12)
+      'b'->Ref(34)
+  END
+  v9.CheckScriptSuccess(lines)
+
+  lines =<< trim END
+      vim9script
+      def TwoArguments(str: string, nr: number)
+        echo str nr
+      enddef
+      var Ref = TwoArguments
+      'a'->Ref('b')
+  END
+  v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string', 6)
+
+  lines =<< trim END
+      vim9script
+      def TwoArguments(str: string, nr: number)
+        echo str nr
+      enddef
+      var Ref = TwoArguments
+      123->Ref(456)
+  END
+  v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number')
+
+  lines =<< trim END
+      vim9script
+      def TwoArguments(nr: number, str: string)
+        echo str nr
+      enddef
+      var Ref = TwoArguments
+      123->Ref('b')
+      def AndNowCompiled()
+        456->Ref('x')
+      enddef
+      AndNowCompiled()
+  END
+  v9.CheckScriptSuccess(lines)
 enddef
 
 def Test_closing_brace_at_start_of_line()
index 1b7615c47c47e391b4063fc5d4b912ad0272024f..47eaf6b2abeb6ba15f543419025342fd3bbf6b1c 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    5026,
 /**/
     5025,
 /**/
index 496f4cde21a2d058a13f3373032d1af5ddb60303..b7f590e106810aa9977aec696fb459d2418b41e2 100644 (file)
@@ -3001,6 +3001,7 @@ compile_def_function(
         * 0z1234->func() should not be confused with a zero line number
         * "++nr" and "--nr" are eval commands
         * in "$ENV->func()" the "$" is not a range
+        * "123->func()" is a method call
         */
        cmd = ea.cmd;
        if ((*cmd != '$' || starts_with_colon)
@@ -3008,7 +3009,8 @@ compile_def_function(
                    || !(*cmd == '\''
                        || (cmd[0] == '0' && cmd[1] == 'z')
                        || (cmd[0] != NUL && cmd[0] == cmd[1]
-                                           && (*cmd == '+' || *cmd == '-')))))
+                                           && (*cmd == '+' || *cmd == '-'))
+                       || number_method(cmd))))
        {
            ea.cmd = skip_range(ea.cmd, TRUE, NULL);
            if (ea.cmd > cmd)
index 436feda514fa8777e2777a083c6b513154cab847..28b282865448054bdafb4895f477c319f4453419 100644 (file)
@@ -244,48 +244,44 @@ alloc_func_type(type_T *ret_type, int argcount, garray_T *type_gap)
 
 /*
  * Get a function type, based on the return type "ret_type".
- * If "argcount" is -1 or 0 a predefined type can be used.
- * If "argcount" > 0 always create a new type, so that arguments can be added.
+ * "argcount" must be -1 or 0, a predefined type can be used.
  */
     type_T *
 get_func_type(type_T *ret_type, int argcount, garray_T *type_gap)
 {
     // recognize commonly used types
-    if (argcount <= 0)
+    if (ret_type == &t_unknown || ret_type == NULL)
     {
-       if (ret_type == &t_unknown || ret_type == NULL)
-       {
-           // (argcount == 0) is not possible
-           return &t_func_unknown;
-       }
-       if (ret_type == &t_void)
-       {
-           if (argcount == 0)
-               return &t_func_0_void;
-           else
-               return &t_func_void;
-       }
-       if (ret_type == &t_any)
-       {
-           if (argcount == 0)
-               return &t_func_0_any;
-           else
-               return &t_func_any;
-       }
-       if (ret_type == &t_number)
-       {
-           if (argcount == 0)
-               return &t_func_0_number;
-           else
-               return &t_func_number;
-       }
-       if (ret_type == &t_string)
-       {
-           if (argcount == 0)
-               return &t_func_0_string;
-           else
-               return &t_func_string;
-       }
+       // (argcount == 0) is not possible
+       return &t_func_unknown;
+    }
+    if (ret_type == &t_void)
+    {
+       if (argcount == 0)
+           return &t_func_0_void;
+       else
+           return &t_func_void;
+    }
+    if (ret_type == &t_any)
+    {
+       if (argcount == 0)
+           return &t_func_0_any;
+       else
+           return &t_func_any;
+    }
+    if (ret_type == &t_number)
+    {
+       if (argcount == 0)
+           return &t_func_0_number;
+       else
+           return &t_func_number;
+    }
+    if (ret_type == &t_string)
+    {
+       if (argcount == 0)
+           return &t_func_0_string;
+       else
+           return &t_func_string;
     }
 
     return alloc_func_type(ret_type, argcount, type_gap);
@@ -541,7 +537,7 @@ typval2type_vimvar(typval_T *tv, garray_T *type_gap)
 {
     if (tv->v_type == VAR_LIST)  // e.g. for v:oldfiles
        return &t_list_string;
-    if (tv->v_type == VAR_DICT)  // e.g. for v:completed_item
+    if (tv->v_type == VAR_DICT)  // e.g. for v:event
        return &t_dict_any;
     return typval2type(tv, get_copyID(), type_gap, TVTT_DO_MEMBER);
 }
@@ -1441,6 +1437,7 @@ vartype_name(vartype_T type)
 type_name(type_T *type, char **tofree)
 {
     char *name;
+    char *arg_free = NULL;
 
     *tofree = NULL;
     if (type == NULL)
@@ -1469,13 +1466,12 @@ type_name(type_T *type, char **tofree)
 
        ga_init2(&ga, 1, 100);
        if (ga_grow(&ga, 20) == FAIL)
-           return "[unknown]";
+           goto failed;
        STRCPY(ga.ga_data, "func(");
        ga.ga_len += 5;
 
        for (i = 0; i < type->tt_argcount; ++i)
        {
-           char *arg_free = NULL;
            char *arg_type;
            int  len;
 
@@ -1490,17 +1486,13 @@ type_name(type_T *type, char **tofree)
            }
            len = (int)STRLEN(arg_type);
            if (ga_grow(&ga, len + 8) == FAIL)
-           {
-               vim_free(arg_free);
-               ga_clear(&ga);
-               return "[unknown]";
-           }
+               goto failed;
            if (varargs && i == type->tt_argcount - 1)
                ga_concat(&ga, (char_u *)"...");
            else if (i >= type->tt_min_argcount)
                *((char *)ga.ga_data + ga.ga_len++) = '?';
            ga_concat(&ga, (char_u *)arg_type);
-           vim_free(arg_free);
+           VIM_CLEAR(arg_free);
        }
        if (type->tt_argcount < 0)
            // any number of arguments
@@ -1516,17 +1508,18 @@ type_name(type_T *type, char **tofree)
 
            len = (int)STRLEN(ret_name) + 4;
            if (ga_grow(&ga, len) == FAIL)
-           {
-               vim_free(ret_free);
-               ga_clear(&ga);
-               return "[unknown]";
-           }
+               goto failed;
            STRCPY((char *)ga.ga_data + ga.ga_len, "): ");
            STRCPY((char *)ga.ga_data + ga.ga_len + 3, ret_name);
            vim_free(ret_free);
        }
        *tofree = ga.ga_data;
        return ga.ga_data;
+
+failed:
+       vim_free(arg_free);
+       ga_clear(&ga);
+       return "[unknown]";
     }
 
     return name;