changeset 21576:f4252efe370e v8.2.1338

patch 8.2.1338: Vim9: assigning to script-local variable doesn't check type Commit: https://github.com/vim/vim/commit/8e4c8c853e3ffbd9258f89180692879ec6bce72b Author: Bram Moolenaar <Bram@vim.org> Date: Sat Aug 1 15:38:38 2020 +0200 patch 8.2.1338: Vim9: assigning to script-local variable doesn't check type Problem: Vim9: assigning to script-local variable doesn't check type. Solution: Use the type. (issue https://github.com/vim/vim/issues/6591)
author Bram Moolenaar <Bram@vim.org>
date Sat, 01 Aug 2020 15:45:06 +0200
parents 69d8fbc507a1
children c17665b3de40
files src/testdir/test_vim9_script.vim src/version.c src/vim9compile.c src/vim9execute.c
diffstat 4 files changed, 57 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -251,6 +251,29 @@ def Test_assignment_dict()
 
   # type becomes dict<any>
   let somedict = rand() > 0 ? #{a: 1, b: 2} : #{a: 'a', b: 'b'}
+
+  # assignment to script-local dict
+  let lines =<< trim END
+    vim9script
+    let test: dict<any> = {}
+    def FillDict(): dict<any>
+      test['a'] = 43
+      return test
+    enddef
+    assert_equal(#{a: 43}, FillDict())
+  END
+  call CheckScriptSuccess(lines)
+
+  lines =<< trim END
+    vim9script
+    let test: dict<any>
+    def FillDict(): dict<any>
+      test['a'] = 43
+      return test
+    enddef
+    FillDict()
+  END
+  call CheckScriptFailure(lines, 'E1103:')
 enddef
 
 def Test_assignment_local()
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1338,
+/**/
     1337,
 /**/
     1336,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -5070,6 +5070,8 @@ compile_assignment(char_u *arg, exarg_T 
     char_u	*ret = NULL;
     int		var_count = 0;
     int		var_idx;
+    int		scriptvar_sid = 0;
+    int		scriptvar_idx = -1;
     int		semicolon = 0;
     garray_T	*instr = &cctx->ctx_instr;
     garray_T    *stack = &cctx->ctx_type_stack;
@@ -5333,7 +5335,8 @@ compile_assignment(char_u *arg, exarg_T 
 	    }
 	    else
 	    {
-		int idx;
+		int	    idx;
+		imported_T  *import = NULL;
 
 		for (idx = 0; reserved[idx] != NULL; ++idx)
 		    if (STRCMP(reserved[idx], name) == 0)
@@ -5374,9 +5377,11 @@ compile_assignment(char_u *arg, exarg_T 
 		}
 		else if ((varlen > 1 && STRNCMP(var_start, "s:", 2) == 0)
 			|| lookup_script(var_start, varlen) == OK
-			|| find_imported(var_start, varlen, cctx) != NULL)
+			|| (import = find_imported(var_start, varlen, cctx))
+								       != NULL)
 		{
-		    dest = dest_script;
+		    char_u	*rawname = name + (name[1] == ':' ? 2 : 0);
+
 		    if (is_decl)
 		    {
 			if ((varlen > 1 && STRNCMP(var_start, "s:", 2) == 0))
@@ -5387,6 +5392,21 @@ compile_assignment(char_u *arg, exarg_T 
 									 name);
 			goto theend;
 		    }
+		    dest = dest_script;
+
+		    // existing script-local variables should have a type
+		    scriptvar_sid = current_sctx.sc_sid;
+		    if (import != NULL)
+			scriptvar_sid = import->imp_sid;
+		    scriptvar_idx = get_script_item_idx(scriptvar_sid,
+								rawname, TRUE);
+		    if (scriptvar_idx >= 0)
+		    {
+			scriptitem_T *si = SCRIPT_ITEM(scriptvar_sid);
+			svar_T	     *sv = ((svar_T *)si->sn_var_vals.ga_data)
+							       + scriptvar_idx;
+			type = sv->sv_type;
+		    }
 		}
 		else if (name[1] == ':' && name[2] != NUL)
 		{
@@ -5766,21 +5786,7 @@ compile_assignment(char_u *arg, exarg_T 
 		    break;
 		case dest_script:
 		    {
-			char_u	    *rawname = name + (name[1] == ':' ? 2 : 0);
-			imported_T  *import = NULL;
-			int	    sid = current_sctx.sc_sid;
-			int	    idx;
-
-			if (name[1] != ':')
-			{
-			    import = find_imported(name, 0, cctx);
-			    if (import != NULL)
-				sid = import->imp_sid;
-			}
-
-			idx = get_script_item_idx(sid, rawname, TRUE);
-			// TODO: specific type
-			if (idx < 0)
+			if (scriptvar_idx < 0)
 			{
 			    char_u *name_s = name;
 
@@ -5796,14 +5802,14 @@ compile_assignment(char_u *arg, exarg_T 
 				    vim_snprintf((char *)name_s, len,
 								 "s:%s", name);
 			    }
-			    generate_OLDSCRIPT(cctx, ISN_STORES, name_s, sid,
-								       &t_any);
+			    generate_OLDSCRIPT(cctx, ISN_STORES, name_s,
+							  scriptvar_sid, type);
 			    if (name_s != name)
 				vim_free(name_s);
 			}
 			else
 			    generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT,
-							     sid, idx, &t_any);
+					   scriptvar_sid, scriptvar_idx, type);
 		    }
 		    break;
 		case dest_local:
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -1422,6 +1422,11 @@ call_def_function(
 		    dict_T	*dict = tv_dict->vval.v_dict;
 		    dictitem_T	*di;
 
+		    if (dict == NULL)
+		    {
+			emsg(_(e_dictnull));
+			goto on_error;
+		    }
 		    if (key == NULL)
 			key = (char_u *)"";
 		    tv = STACK_TV_BOT(-3);