changeset 25162:c44d6ac81c42 v8.2.3117

patch 8.2.3117: Vim9: type not properly checked in for loop Commit: https://github.com/vim/vim/commit/efc5db5215b4efc424b2de34613525d729a05c93 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Jul 7 21:21:30 2021 +0200 patch 8.2.3117: Vim9: type not properly checked in for loop Problem: Vim9: type not properly checked in for loop. Solution: Have items() return a list of lists. Add runtime type checks. (closes #8515)
author Bram Moolenaar <Bram@vim.org>
date Wed, 07 Jul 2021 21:30:03 +0200
parents 84c7dc0fdcd2
children 0fc3365fc931
files src/evalfunc.c src/globals.h src/testdir/test_vim9_script.vim src/version.c src/vim9compile.c
diffstat 5 files changed, 23 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -522,6 +522,11 @@ ret_list_dict_any(int argcount UNUSED, t
     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 **ar
 {
     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;
 }
 
--- a/src/globals.h
+++ b/src/globals.h
@@ -441,6 +441,7 @@ EXTERN type_T t_list_number INIT6(VAR_LI
 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);
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -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()
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3117,
+/**/
     3116,
 /**/
     3115,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -7932,8 +7932,11 @@ compile_for(char_u *arg_start, cctx_T *c
 	    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)