]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.3866: Vim9: type checking global variables is inconsistent v8.2.3866
authorBram Moolenaar <Bram@vim.org>
Tue, 21 Dec 2021 12:32:17 +0000 (12:32 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 21 Dec 2021 12:32:17 +0000 (12:32 +0000)
Problem:    Vim9: type checking global variables is inconsistent.
Solution:   Use the "unknown" type in more places.

src/evalfunc.c
src/globals.h
src/testdir/test_vim9_func.vim
src/version.c
src/vim9cmds.c
src/vim9expr.c
src/vim9instr.c

index d8c621d54bd19f7006a1477fbd5cede1971e0748..39b94deb977c6a40d9b870c5268213c48863fa6e 100644 (file)
@@ -228,7 +228,9 @@ check_arg_type(
 arg_float_or_nr(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-                 || type->tt_type == VAR_FLOAT || type->tt_type == VAR_NUMBER)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_FLOAT
+           || type->tt_type == VAR_NUMBER)
        return OK;
     arg_type_mismatch(&t_number, type, context->arg_idx + 1);
     return FAIL;
@@ -313,7 +315,9 @@ arg_bool(type_T *type, argcontext_T *context)
 arg_list_or_blob(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-                    || type->tt_type == VAR_LIST || type->tt_type == VAR_BLOB)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_LIST
+           || type->tt_type == VAR_BLOB)
        return OK;
     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
     return FAIL;
@@ -326,7 +330,9 @@ arg_list_or_blob(type_T *type, argcontext_T *context)
 arg_string_or_nr(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-           || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_STRING
+           || type->tt_type == VAR_NUMBER)
        return OK;
     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
     return FAIL;
@@ -339,7 +345,9 @@ arg_string_or_nr(type_T *type, argcontext_T *context)
 arg_buffer(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-           || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_STRING
+           || type->tt_type == VAR_NUMBER)
        return OK;
     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
     return FAIL;
@@ -352,6 +360,7 @@ arg_buffer(type_T *type, argcontext_T *context)
 arg_buffer_or_dict_any(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_UNKNOWN
            || type->tt_type == VAR_STRING
            || type->tt_type == VAR_NUMBER
            || type->tt_type == VAR_DICT)
@@ -367,7 +376,9 @@ arg_buffer_or_dict_any(type_T *type, argcontext_T *context)
 arg_lnum(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-           || type->tt_type == VAR_STRING || type->tt_type == VAR_NUMBER)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_STRING
+           || type->tt_type == VAR_NUMBER)
        return OK;
     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
     return FAIL;
@@ -379,7 +390,9 @@ arg_lnum(type_T *type, argcontext_T *context)
     static int
 arg_string_or_list_string(type_T *type, argcontext_T *context)
 {
-    if (type->tt_type == VAR_ANY || type->tt_type == VAR_STRING)
+    if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_STRING)
        return OK;
     if (type->tt_type != VAR_LIST)
     {
@@ -401,7 +414,9 @@ arg_string_or_list_string(type_T *type, argcontext_T *context)
 arg_string_or_list_any(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-           || type->tt_type == VAR_STRING || type->tt_type == VAR_LIST)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_STRING
+           || type->tt_type == VAR_LIST)
        return OK;
     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
     return FAIL;
@@ -414,7 +429,9 @@ arg_string_or_list_any(type_T *type, argcontext_T *context)
 arg_string_or_blob(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-           || type->tt_type == VAR_STRING || type->tt_type == VAR_BLOB)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_STRING
+           || type->tt_type == VAR_BLOB)
        return OK;
     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
     return FAIL;
@@ -427,7 +444,9 @@ arg_string_or_blob(type_T *type, argcontext_T *context)
 arg_list_or_dict(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-                    || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_LIST
+           || type->tt_type == VAR_DICT)
        return OK;
     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
     return FAIL;
@@ -440,9 +459,10 @@ arg_list_or_dict(type_T *type, argcontext_T *context)
 arg_list_or_dict_or_blob(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-                    || type->tt_type == VAR_LIST
-                    || type->tt_type == VAR_DICT
-                    || type->tt_type == VAR_BLOB)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_LIST
+           || type->tt_type == VAR_DICT
+           || type->tt_type == VAR_BLOB)
        return OK;
     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
     return FAIL;
@@ -455,10 +475,11 @@ arg_list_or_dict_or_blob(type_T *type, argcontext_T *context)
 arg_list_or_dict_or_blob_or_string(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-                    || type->tt_type == VAR_LIST
-                    || type->tt_type == VAR_DICT
-                    || type->tt_type == VAR_BLOB
-                    || type->tt_type == VAR_STRING)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_LIST
+           || type->tt_type == VAR_DICT
+           || type->tt_type == VAR_BLOB
+           || type->tt_type == VAR_STRING)
        return OK;
     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
     return FAIL;
@@ -471,9 +492,10 @@ arg_list_or_dict_or_blob_or_string(type_T *type, argcontext_T *context)
 arg_string_list_or_blob(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-                    || type->tt_type == VAR_LIST
-                    || type->tt_type == VAR_BLOB
-                    || type->tt_type == VAR_STRING)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_LIST
+           || type->tt_type == VAR_BLOB
+           || type->tt_type == VAR_STRING)
        return OK;
     arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
     return FAIL;
@@ -495,6 +517,7 @@ arg_job(type_T *type, argcontext_T *context)
 arg_chan_or_job(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_UNKNOWN
            || type->tt_type == VAR_CHANNEL
            || type->tt_type == VAR_JOB)
        return OK;
@@ -557,9 +580,10 @@ arg_item_of_prev(type_T *type, argcontext_T *context)
 arg_str_or_nr_or_list(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-               || type->tt_type == VAR_STRING
-               || type->tt_type == VAR_NUMBER
-               || type->tt_type == VAR_LIST)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_STRING
+           || type->tt_type == VAR_NUMBER
+           || type->tt_type == VAR_LIST)
        return OK;
     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
     return FAIL;
@@ -572,8 +596,9 @@ arg_str_or_nr_or_list(type_T *type, argcontext_T *context)
 arg_dict_any_or_string(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
-               || type->tt_type == VAR_DICT
-               || type->tt_type == VAR_STRING)
+           || type->tt_type == VAR_UNKNOWN
+           || type->tt_type == VAR_DICT
+           || type->tt_type == VAR_STRING)
        return OK;
     arg_type_mismatch(&t_string, type, context->arg_idx + 1);
     return FAIL;
@@ -603,6 +628,7 @@ arg_extend3(type_T *type, argcontext_T *context)
 arg_get1(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_UNKNOWN
            || type->tt_type == VAR_BLOB
            || type->tt_type == VAR_LIST
            || type->tt_type == VAR_DICT
@@ -622,6 +648,7 @@ arg_get1(type_T *type, argcontext_T *context)
 arg_len1(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_UNKNOWN
            || type->tt_type == VAR_STRING
            || type->tt_type == VAR_NUMBER
            || type->tt_type == VAR_BLOB
@@ -657,6 +684,7 @@ arg_remove2(type_T *type, argcontext_T *context)
 arg_repeat1(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_UNKNOWN
            || type->tt_type == VAR_STRING
            || type->tt_type == VAR_NUMBER
            || type->tt_type == VAR_LIST)
@@ -674,6 +702,7 @@ arg_repeat1(type_T *type, argcontext_T *context)
 arg_slice1(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_UNKNOWN
            || type->tt_type == VAR_LIST
            || type->tt_type == VAR_BLOB
            || type->tt_type == VAR_STRING)
@@ -691,6 +720,7 @@ arg_slice1(type_T *type, argcontext_T *context)
 arg_count1(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_UNKNOWN
            || type->tt_type == VAR_STRING
            || type->tt_type == VAR_LIST
            || type->tt_type == VAR_DICT)
@@ -708,6 +738,7 @@ arg_count1(type_T *type, argcontext_T *context)
 arg_cursor1(type_T *type, argcontext_T *context)
 {
     if (type->tt_type == VAR_ANY
+           || type->tt_type == VAR_UNKNOWN
            || type->tt_type == VAR_NUMBER
            || type->tt_type == VAR_STRING
            || type->tt_type == VAR_LIST)
index c69306a6d611078f4260a45eb9907f590bb1f9e8..45561dee3bba8f8abf639c64ff630b2f87053263 100644 (file)
@@ -404,9 +404,16 @@ EXTERN int garbage_collect_at_exit INIT(= FALSE);
 
 
 // Commonly used types.
+// "unknown" is used for when the type is really unknown, e.g. global
+// variables.  Also for when a function may or may not return something.
 EXTERN type_T t_unknown INIT6(VAR_UNKNOWN, 0, 0, TTFLAG_STATIC, NULL, NULL);
+
+// "any" is used for when the type is mixed.  Excludes "void".
 EXTERN type_T t_any INIT6(VAR_ANY, 0, 0, TTFLAG_STATIC, NULL, NULL);
+
+// "void" is used for a function not returning anything.
 EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, TTFLAG_STATIC, NULL, NULL);
+
 EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, TTFLAG_STATIC, NULL, NULL);
 EXTERN type_T t_special INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL);
 EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC, NULL, NULL);
index d17d010e886dfdaefd2ba9eafe90c850efc62b66..81fa7e49c7b94916c71e1deb8c2bfdb8e7002772 100644 (file)
@@ -547,6 +547,39 @@ def Test_call_default_args()
       defcompile
   END
   CheckScriptFailure(lines, 'E1001: Variable not found: b')
+
+  # using script variable requires matching type or type cast
+  lines =<< trim END
+      vim9script
+      var a: any
+      def Func(arg: string = a)
+        echo arg
+      enddef
+      defcompile
+  END
+  CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got any')
+
+  lines =<< trim END
+      vim9script
+      var a: any
+      def Func(arg: string = <string>a)
+        echo arg
+      enddef
+      a = 'works'
+      Func()
+  END
+  CheckScriptSuccess(lines)
+
+  # using global variable does not require type cast
+  lines =<< trim END
+      vim9script
+      def Func(arg: string = g:str)
+        echo arg
+      enddef
+      g:str = 'works'
+      Func()
+  END
+  CheckScriptSuccess(lines)
 enddef
 
 def FuncWithComment(  # comment
index 90b35d3884bd35f18b5c9d23eaf553d6363dee95..2c46608df8422012a98ef4eef506e24e14d19a8e 100644 (file)
@@ -749,6 +749,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3866,
 /**/
     3865,
 /**/
index 6d8935a9c3f050fc09fcb0f54b00b010c474dc7d..5c7a9387978533598bd768baf8c2f4c0c86fa997 100644 (file)
@@ -843,8 +843,11 @@ compile_for(char_u *arg_start, cctx_T *cctx)
        // If we know the type of "var" and it is a not a supported type we can
        // give an error now.
        vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
-       if (vartype->tt_type != VAR_LIST && vartype->tt_type != VAR_STRING
-               && vartype->tt_type != VAR_BLOB && vartype->tt_type != VAR_ANY)
+       if (vartype->tt_type != VAR_LIST
+               && vartype->tt_type != VAR_STRING
+               && vartype->tt_type != VAR_BLOB
+               && vartype->tt_type != VAR_ANY
+               && vartype->tt_type != VAR_UNKNOWN)
        {
            semsg(_(e_for_loop_on_str_not_supported),
                                               vartype_name(vartype->tt_type));
index 66d0fc441f91a2ce00d01f403612cea1ee2a8ca0..6fe8e2af1ff044c7f1cb5a1d537029c3b1315a0e 100644 (file)
@@ -90,7 +90,7 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
     vartype = (*typep)->tt_type;
     idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
     // If the index is a string, the variable must be a Dict.
-    if (*typep == &t_any && idxtype == &t_string)
+    if ((*typep == &t_any || *typep == &t_unknown) && idxtype == &t_string)
        vartype = VAR_DICT;
     if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB)
     {
@@ -156,7 +156,7 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
                return FAIL;
        }
     }
-    else if (vartype == VAR_LIST || *typep == &t_any)
+    else if (vartype == VAR_LIST || *typep == &t_any || *typep == &t_unknown)
     {
        if (is_slice)
        {
@@ -415,7 +415,7 @@ compile_load(
                // Global, Buffer-local, Window-local and Tabpage-local
                // variables can be defined later, thus we don't check if it
                // exists, give an error at runtime.
-               res = generate_LOAD(cctx, isn_type, 0, name, &t_any);
+               res = generate_LOAD(cctx, isn_type, 0, name, &t_unknown);
            }
        }
     }
@@ -1428,7 +1428,10 @@ bool_on_stack(cctx_T *cctx)
     if (type == &t_bool)
        return OK;
 
-    if (type == &t_any || type == &t_number || type == &t_number_bool)
+    if (type == &t_any
+           || type == &t_unknown
+           || type == &t_number
+           || type == &t_number_bool)
        // Number 0 and 1 are OK to use as a bool.  "any" could also be a bool.
        // This requires a runtime type check.
        return generate_COND2BOOL(cctx);
@@ -2155,9 +2158,10 @@ compile_expr7t(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
 
        generate_ppconst(cctx, ppconst);
        actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
-       if (check_type(want_type, actual, FALSE, where) == FAIL)
+       if (check_type_maybe(want_type, actual, FALSE, where) != OK)
        {
-           if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) == FAIL)
+           if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE)
+                                                                      == FAIL)
                return FAIL;
        }
     }
index 48c90dc441d0b7a4b6912bb65356abda4b089f02..06d6b9004875206d61cb1575c66727cb2d1ba6e7 100644 (file)
@@ -168,9 +168,10 @@ may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
     static int
 check_number_or_float(vartype_T type1, vartype_T type2, char_u *op)
 {
-    if (!((type1 == VAR_NUMBER || type1 == VAR_FLOAT || type1 == VAR_ANY)
+    if (!((type1 == VAR_NUMBER || type1 == VAR_FLOAT
+                                  || type1 == VAR_ANY || type1 == VAR_UNKNOWN)
            && (type2 == VAR_NUMBER || type2 == VAR_FLOAT
-                                                        || type2 == VAR_ANY)))
+                                || type2 == VAR_ANY || type2 == VAR_UNKNOWN)))
     {
        if (*op == '+')
            emsg(_(e_wrong_argument_type_for_plus));
@@ -204,7 +205,9 @@ generate_add_instr(
 
     if (vartype != VAR_LIST && vartype != VAR_BLOB
            && type1->tt_type != VAR_ANY
+           && type1->tt_type != VAR_UNKNOWN
            && type2->tt_type != VAR_ANY
+           && type2->tt_type != VAR_UNKNOWN
            && check_number_or_float(
                        type1->tt_type, type2->tt_type, (char_u *)"+") == FAIL)
        return FAIL;
@@ -293,8 +296,10 @@ generate_two_op(cctx_T *cctx, char_u *op)
                  break;
 
        case '%': if ((type1->tt_type != VAR_ANY
+                             && type1->tt_type != VAR_UNKNOWN
                                               && type1->tt_type != VAR_NUMBER)
                          || (type2->tt_type != VAR_ANY
+                             && type2->tt_type != VAR_UNKNOWN
                                              && type2->tt_type != VAR_NUMBER))
                  {
                      emsg(_(e_percent_requires_number_arguments));
@@ -1528,7 +1533,7 @@ generate_PCALL(
 
     RETURN_OK_IF_SKIP(cctx);
 
-    if (type->tt_type == VAR_ANY)
+    if (type->tt_type == VAR_ANY || type->tt_type == VAR_UNKNOWN)
        ret_type = &t_any;
     else if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL)
     {
@@ -1620,7 +1625,7 @@ generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len)
 
     // check for dict type
     type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
-    if (type->tt_type != VAR_DICT && type != &t_any)
+    if (type->tt_type != VAR_DICT && type != &t_any && type != &t_unknown)
     {
        char *tofree;