changeset 24460:f0a3adf16f01 v8.2.2770

patch 8.2.2770: Vim9: type of loop variable is not used Commit: https://github.com/vim/vim/commit/fe090eb58fad1aaf83267d0b4ace9f024a5ba2bc Author: Bram Moolenaar <Bram@vim.org> Date: Thu Apr 15 21:48:32 2021 +0200 patch 8.2.2770: Vim9: type of loop variable is not used Problem: Vim9: type of loop variable is not used. Solution: Parse and check the variable type. (closes https://github.com/vim/vim/issues/8107)
author Bram Moolenaar <Bram@vim.org>
date Thu, 15 Apr 2021 22:00:05 +0200
parents 6a4b9b9acb7d
children 550096cdfa95
files src/testdir/test_vim9_script.vim src/version.c src/vim9compile.c
diffstat 3 files changed, 35 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -2343,6 +2343,12 @@ def Test_for_loop()
       endfor
       assert_equal(6, total)
 
+      var chars = ''
+      for s: string in 'foobar'
+        chars ..= s
+      endfor
+      assert_equal('foobar', chars)
+
       # unpack with type
       var res = ''
       for [n: number, s: string] in [[1, 'a'], [2, 'b']]
@@ -2408,6 +2414,12 @@ def Test_for_loop_fails()
       endfor
   END
   CheckDefAndScriptFailure2(lines, 'E1018:', 'E46:', 3)
+
+  lines =<< trim END
+      for nr: number in ['foo']
+      endfor
+  END
+  CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1)
 enddef
 
 def Test_for_loop_script_var()
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2770,
+/**/
     2769,
 /**/
     2768,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -7514,12 +7514,16 @@ compile_for(char_u *arg_start, cctx_T *c
 	return NULL;
     }
 
-    if (vartype->tt_type == VAR_LIST && vartype->tt_member->tt_type != VAR_ANY)
+    if (vartype->tt_type == VAR_STRING)
+	item_type = &t_string;
+    else if (vartype->tt_type == VAR_LIST
+				     && vartype->tt_member->tt_type != VAR_ANY)
     {
 	if (var_count == 1)
 	    item_type = vartype->tt_member;
 	else if (vartype->tt_member->tt_type == VAR_LIST
 		      && vartype->tt_member->tt_member->tt_type != VAR_ANY)
+	    // TODO: should get the type from 
 	    item_type = vartype->tt_member->tt_member;
     }
 
@@ -7557,12 +7561,19 @@ compile_for(char_u *arg_start, cctx_T *c
 	int		opt_flags = 0;
 	int		vimvaridx = -1;
 	type_T		*type = &t_any;
+	type_T		*lhs_type = &t_any;
+	where_T		where;
 
 	p = skip_var_one(arg, FALSE);
 	varlen = p - arg;
 	name = vim_strnsave(arg, varlen);
 	if (name == NULL)
 	    goto failed;
+	if (*p == ':')
+	{
+	    p = skipwhite(p + 1);
+	    lhs_type = parse_type(&p, cctx->ctx_type_list, TRUE);
+	}
 
 	// TODO: script var not supported?
 	if (get_var_dest(name, &dest, CMD_for, &opt_flags,
@@ -7589,8 +7600,15 @@ compile_for(char_u *arg_start, cctx_T *c
 	    }
 
 	    // Reserve a variable to store "var".
-	    // TODO: check for type
-	    var_lvar = reserve_local(cctx, arg, varlen, TRUE, &t_any);
+	    where.wt_index = var_count > 1 ? idx + 1 : 0;
+	    where.wt_variable = TRUE;
+	    if (lhs_type == &t_any)
+		lhs_type = item_type;
+	    else if (item_type != &t_unknown
+		       && !(var_count > 1 && item_type == &t_any)
+		       && 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)
 		// out of memory or used as an argument
 		goto failed;
@@ -7602,8 +7620,6 @@ compile_for(char_u *arg_start, cctx_T *c
 	    generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL);
 	}
 
-	if (*p == ':')
-	    p = skip_type(skipwhite(p + 1), FALSE);
 	if (*p == ',' || *p == ';')
 	    ++p;
 	arg = skipwhite(p);