]> granicus.if.org Git - vim/commitdiff
patch 8.2.3117: Vim9: type not properly checked in for loop v8.2.3117
authorBram Moolenaar <Bram@vim.org>
Wed, 7 Jul 2021 19:21:30 +0000 (21:21 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 7 Jul 2021 19:21:30 +0000 (21:21 +0200)
Problem:    Vim9: type not properly checked in for loop.
Solution:   Have items() return a list of lists.  Add runtime type checks.
            (closes #8515)

src/evalfunc.c
src/globals.h
src/testdir/test_vim9_script.vim
src/version.c
src/vim9compile.c

index ec74fdeeae9d270332e63ff5c9c50e328fde715b..34eac6987cb364a527b5f58006b73eb9ee2cf710 100644 (file)
@@ -522,6 +522,11 @@ ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
     return &t_list_dict_any;
 }
     static type_T *
+ret_list_items(int argcount, type_T **argtypes UNUSED)
+{
+    return &t_list_list_any;
+}
+    static type_T *
 ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
 {
     return &t_dict_any;
@@ -1166,7 +1171,7 @@ static funcentry_T global_functions[] =
     {"isnan",          1, 1, FEARG_1,      arg1_float_or_nr,
                        ret_number_bool,    MATH_FUNC(f_isnan)},
     {"items",          1, 1, FEARG_1,      arg1_dict,
-                       ret_list_any,       f_items},
+                       ret_list_items,     f_items},
     {"job_getchannel", 1, 1, FEARG_1,      NULL,
                        ret_channel,        JOB_FUNC(f_job_getchannel)},
     {"job_info",       0, 1, FEARG_1,      NULL,
@@ -3687,6 +3692,7 @@ ret_f_function(int argcount, type_T **argtypes)
 {
     if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
        return &t_func_any;
+    // Need to check the type at runtime, the function may be defined later.
     return &t_func_unknown;
 }
 
index b6076df5bb820e154d95056ad3f2683e1a495559..54ecb8e1f0481f4aa8a0c41bd720aaaa4bd17ce8 100644 (file)
@@ -441,6 +441,7 @@ EXTERN type_T t_list_number INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_number, NULL
 EXTERN type_T t_list_string INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_string, NULL);
 EXTERN type_T t_list_job INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_job, NULL);
 EXTERN type_T t_list_dict_any INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_dict_any, NULL);
+EXTERN type_T t_list_list_any INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_list_any, NULL);
 
 EXTERN type_T t_dict_bool INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_bool, NULL);
 EXTERN type_T t_dict_number INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_number, NULL);
index f5dc26e46030c2a685097eccf31c1c8130ab522e..4abe4015ee01b1cf8fad5f961873dc918360bb1b 100644 (file)
@@ -2573,6 +2573,14 @@ def Test_for_loop_fails()
       endfor
   END
   CheckDefAndScriptFailure(lines, 'E1059:', 1)
+
+  lines =<< trim END
+      var d: dict<number> = {a: 1, b: 2}
+      for [k: job, v: job] in d->items()
+        echo k v
+      endfor
+  END
+  CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected job but got string', 2)
 enddef
 
 def Test_for_loop_script_var()
index 1deb3e4826738e67cf9216024a14a2f2b20abd8f..e1774a4037480116025c83d75f7911b1d173e9f5 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3117,
 /**/
     3116,
 /**/
index d63073676432efa3622f1ffd698961a5006a0609..3a717e487fef222237be3b7539ed6ffe5a7acb7c 100644 (file)
@@ -7932,8 +7932,11 @@ compile_for(char_u *arg_start, cctx_T *cctx)
            if (lhs_type == &t_any)
                lhs_type = item_type;
            else if (item_type != &t_unknown
-                      && !(var_list && item_type == &t_any)
-                      && check_type(lhs_type, item_type, TRUE, where) == FAIL)
+                       && ((var_list && item_type == &t_any)
+                         ? need_type(item_type, lhs_type,
+                                                    -1, 0, cctx, FALSE, FALSE)
+                         : check_type(lhs_type, item_type, TRUE, where))
+                       == FAIL)
                goto failed;
            var_lvar = reserve_local(cctx, arg, varlen, TRUE, lhs_type);
            if (var_lvar == NULL)