]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.0527: Vim9: function types insufficiently tested v8.2.0527
authorBram Moolenaar <Bram@vim.org>
Tue, 7 Apr 2020 18:53:39 +0000 (20:53 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 7 Apr 2020 18:53:39 +0000 (20:53 +0200)
Problem:    Vim9: function types insufficiently tested.
Solution:   Add more tests.  Fix white space check.  Add "test_vim9" target.

src/Makefile
src/testdir/Make_all.mak
src/testdir/Makefile
src/testdir/test_vim9_func.vim
src/version.c
src/vim9compile.c

index 704721b5f20de1ad2d2442cc28561621cf89b30c..c32ea0840b03ff769887c76bf467821126901549 100644 (file)
@@ -2301,7 +2301,7 @@ test1 \
 #      export TEST_FILTER=Test_terminal_wipe_buffer
 # A partial match also works:
 #      export TEST_FILTER=wipe_buffer
-$(NEW_TESTS):
+$(NEW_TESTS) test_vim9:
        cd testdir; $(MAKE) $@ VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
 
 newtests:
index 8ca7831683ddb2fe0d595a9b4351c668f6f01082..63d97e862b132af5566e5d513ad1d4323df2c76a 100644 (file)
@@ -43,6 +43,19 @@ SCRIPTS_WIN32 =
 # Tests for the GUI.
 SCRIPTS_GUI =
 
+# Tests for Vim9 script.
+TEST_VIM9 = \
+       test_vim9_disassemble \
+       test_vim9_expr \
+       test_vim9_func \
+       test_vim9_script
+
+TEST_VIM9_RES = \
+       test_vim9_disassemble.res \
+       test_vim9_expr.res \
+       test_vim9_func.res \
+       test_vim9_script.res
+
 # Individual tests, including the ones part of test_alot.
 # Please keep sorted up to test_alot.
 NEW_TESTS = \
@@ -272,10 +285,7 @@ NEW_TESTS = \
        test_utf8 \
        test_utf8_comparisons \
        test_vartabs \
-       test_vim9_disassemble \
-       test_vim9_expr \
-       test_vim9_func \
-       test_vim9_script \
+       $(TEST_VIM9) \
        test_viminfo \
        test_vimscript \
        test_virtualedit \
@@ -482,10 +492,7 @@ NEW_TESTS_RES = \
        test_user_func.res \
        test_usercommands.res \
        test_vartabs.res \
-       test_vim9_disassemble.res \
-       test_vim9_expr.res \
-       test_vim9_func.res \
-       test_vim9_script.res \
+       $(TEST_VIM9_RES) \
        test_viminfo.res \
        test_vimscript.res \
        test_virtualedit.res \
index 746c849938b1b4686b61c838a6838264853722da..b2eaecbf403d1fca404b360bbc27fca1e1aa8c2d 100644 (file)
@@ -79,6 +79,16 @@ $(NEW_TESTS):
                exit 1; \
        fi
 
+# Run only tests specific for Vim9 script
+test_vim9:
+       rm -f test_vim9_*.res test.log messages
+       @MAKEFLAGS=--no-print-directory $(MAKE) -f Makefile $(TEST_VIM9_RES) VIMPROG=$(VIMPROG) XXDPROG=$(XXDPROG) SCRIPTSOURCE=$(SCRIPTSOURCE)
+       @cat messages
+       @MAKEFLAGS=--no-print-directory $(MAKE) -f Makefile report VIMPROG=$(VIMPROG) XXDPROG=$(XXDPROG) SCRIPTSOURCE=$(SCRIPTSOURCE)
+       @if test -f test.log; then \
+               exit 1; \
+       fi
+
 RM_ON_RUN = test.out X* viminfo
 RM_ON_START = tiny.vim small.vim mbyte.vim mzscheme.vim test.ok benchmark.out
 RUN_VIM = VIMRUNTIME=$(SCRIPTSOURCE) $(VALGRIND) $(VIMPROG) -f $(GUI_FLAG) -u unix.vim $(NO_INITS) -s dotest.in
index 5554b2d7e1649468cb2a11dbb524ba99c8da2034..fb2180fc93037a69b3f85689eee0e5e99ce595db 100644 (file)
@@ -373,6 +373,11 @@ def FuncNoArgRetNumber(): number
   return 1234
 enddef
 
+def FuncNoArgRetString(): string
+  funcResult = 45
+  return 'text'
+enddef
+
 def FuncOneArgNoRet(arg: number)
   funcResult = arg
 enddef
@@ -382,6 +387,10 @@ def FuncOneArgRetNumber(arg: number): number
   return arg
 enddef
 
+def FuncOneArgRetString(arg: string): string
+  return arg
+enddef
+
 def FuncOneArgRetAny(arg: any): any
   return arg
 enddef
@@ -415,6 +424,32 @@ def Test_func_type()
   assert_equal(13, funcResult)
 enddef
 
+def Test_func_type_part()
+  let RefVoid: func: void
+  RefVoid = FuncNoArgNoRet
+  RefVoid = FuncOneArgNoRet
+  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
+  CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string')
+
+  let RefAny: func(): any
+  RefAny = FuncNoArgRetNumber
+  RefAny = FuncNoArgRetString
+  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): any but got func()')
+  CheckDefFailure(['let RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1013: type mismatch, expected func(): any but got func(number)')
+
+  let RefNr: func: number
+  RefNr = FuncNoArgRetNumber
+  RefNr = FuncOneArgRetNumber
+  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()')
+  CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string')
+
+  let RefStr: func: string
+  RefStr = FuncNoArgRetString
+  RefStr = FuncOneArgRetString
+  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): string but got func()')
+  CheckDefFailure(['let RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func(): string but got func(): number')
+enddef
+
 def Test_func_type_fails()
   CheckDefFailure(['let ref1: func()'], 'E704:')
 
index bcf333b8d22cc6decd3b7e6f86d09ca864b1ba27..f08ca11d3f451ba073a2f45ef46a2cf8fcffa263 100644 (file)
@@ -738,6 +738,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    527,
 /**/
     526,
 /**/
index 359007a38a5edf58cc966b39db270fe1a5460162..18fbdd36ed882a758bb79cb0fc01e363f43a9bfd 100644 (file)
@@ -314,6 +314,11 @@ 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)
+       {
+           // (argcount == 0) is not possible
+           return &t_func_unknown;
+       }
        if (ret_type == &t_void)
        {
            if (argcount == 0)
@@ -350,6 +355,7 @@ get_func_type(type_T *ret_type, int argcount, garray_T *type_gap)
        return &t_any;
     type->tt_type = VAR_FUNC;
     type->tt_member = ret_type;
+    type->tt_argcount = argcount;
     type->tt_args = NULL;
     return type;
 }
@@ -1589,7 +1595,7 @@ parse_type(char_u **arg, garray_T *type_gap)
            if (len == 4 && STRNCMP(*arg, "func", len) == 0)
            {
                type_T  *type;
-               type_T  *ret_type = &t_any;
+               type_T  *ret_type = &t_unknown;
                int     argcount = -1;
                int     flags = 0;
                int     first_optional = -1;
@@ -1657,7 +1663,7 @@ parse_type(char_u **arg, garray_T *type_gap)
                {
                    // parse return type
                    ++*arg;
-                   if (!VIM_ISWHITE(*p))
+                   if (!VIM_ISWHITE(**arg))
                        semsg(_(e_white_after), ":");
                    *arg = skipwhite(*arg);
                    ret_type = parse_type(arg, type_gap);
@@ -2405,7 +2411,10 @@ check_type(type_T *expected, type_T *actual, int give_msg)
 {
     int ret = OK;
 
-    if (expected->tt_type != VAR_UNKNOWN && expected->tt_type != VAR_ANY)
+    // When expected is "unknown" we accept any actual type.
+    // When expected is "any" we accept any actual type except "void".
+    if (expected->tt_type != VAR_UNKNOWN
+           && (expected->tt_type != VAR_ANY || actual->tt_type == VAR_VOID))
     {
        if (expected->tt_type != actual->tt_type)
        {
@@ -2421,8 +2430,7 @@ check_type(type_T *expected, type_T *actual, int give_msg)
        }
        else if (expected->tt_type == VAR_FUNC)
        {
-           if (expected->tt_member != &t_any
-                                         && expected->tt_member != &t_unknown)
+           if (expected->tt_member != &t_unknown)
                ret = check_type(expected->tt_member, actual->tt_member, FALSE);
            if (ret == OK && expected->tt_argcount != -1
                    && (actual->tt_argcount < expected->tt_min_argcount
@@ -4044,36 +4052,39 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
        if (r == FAIL)
            goto theend;
 
-       stack = &cctx->ctx_type_stack;
-       stacktype = stack->ga_len == 0 ? &t_void
-                             : ((type_T **)stack->ga_data)[stack->ga_len - 1];
-       if (idx >= 0 && (is_decl || !has_type))
+       if (cctx->ctx_skip != TRUE)
        {
-           lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
-           if (new_local && !has_type)
+           stack = &cctx->ctx_type_stack;
+           stacktype = stack->ga_len == 0 ? &t_void
+                             : ((type_T **)stack->ga_data)[stack->ga_len - 1];
+           if (idx >= 0 && (is_decl || !has_type))
            {
-               if (stacktype->tt_type == VAR_VOID)
-               {
-                   emsg(_("E1031: Cannot use void value"));
-                   goto theend;
-               }
-               else
+               lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
+               if (new_local && !has_type)
                {
-                   // An empty list or dict has a &t_void member, for a
-                   // variable that implies &t_any.
-                   if (stacktype == &t_list_empty)
-                       lvar->lv_type = &t_list_any;
-                   else if (stacktype == &t_dict_empty)
-                       lvar->lv_type = &t_dict_any;
+                   if (stacktype->tt_type == VAR_VOID)
+                   {
+                       emsg(_("E1031: Cannot use void value"));
+                       goto theend;
+                   }
                    else
-                       lvar->lv_type = stacktype;
+                   {
+                       // An empty list or dict has a &t_void member, for a
+                       // variable that implies &t_any.
+                       if (stacktype == &t_list_empty)
+                           lvar->lv_type = &t_list_any;
+                       else if (stacktype == &t_dict_empty)
+                           lvar->lv_type = &t_dict_any;
+                       else
+                           lvar->lv_type = stacktype;
+                   }
                }
+               else if (need_type(stacktype, lvar->lv_type, -1, cctx) == FAIL)
+                   goto theend;
            }
-           else if (need_type(stacktype, lvar->lv_type, -1, cctx) == FAIL)
+           else if (*p != '=' && check_type(type, stacktype, TRUE) == FAIL)
                goto theend;
        }
-       else if (*p != '=' && check_type(type, stacktype, TRUE) == FAIL)
-           goto theend;
     }
     else if (cmdidx == CMD_const)
     {