changeset 27728:fdc841530372 v8.2.4390

patch 8.2.4390: Vim9: list from declaration with inferred type not set Commit: https://github.com/vim/vim/commit/e88c6b7a5d8b24f8aa9a3e976b78654bae293ae4 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Feb 15 15:37:11 2022 +0000 patch 8.2.4390: Vim9: list from declaration with inferred type not set Problem: Vim9: list from declaration with inferred type does not set the type on the value. Solution: When inferring the type in a variable declaration also set the type of the list or dictionary. (closes #9705) Do not set the type when the member is "any".
author Bram Moolenaar <Bram@vim.org>
date Tue, 15 Feb 2022 16:45:03 +0100
parents c4306b7b871d
children 596e8f64acc2
files src/testdir/test_vim9_assign.vim src/testdir/test_vim9_builtin.vim src/testdir/test_vim9_disassemble.vim src/version.c src/vim9compile.c
diffstat 5 files changed, 41 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -1885,6 +1885,19 @@ def Test_var_declaration_fails()
   v9.CheckDefFailure(['const foo: number'], 'E1021:')
 enddef
 
+def Test_var_declaration_inferred()
+  # check that type is set on the list so that extend() fails
+  var lines =<< trim END
+      vim9script
+      def GetList(): list<number>
+        var l = [1, 2, 3]
+        return l
+      enddef
+      echo GetList()->extend(['x'])
+  END
+  v9.CheckScriptFailure(lines, 'E1013:', 6)
+enddef
+
 def Test_script_local_in_legacy()
   # OK to define script-local later but before compiling
   var lines =<< trim END
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -1129,6 +1129,7 @@ def Test_extend_with_error_function()
       def Test()
         var d: dict<any> = {}
         d->extend({A: 10, Func: function('F', [])})
+        d.Func()
       enddef
 
       Test()
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -427,6 +427,7 @@ def Test_disassemble_store_index()
         '\d PUSHS "dd"\_s*' ..
         '\d NEWDICT size 0\_s*' ..
         '\d NEWDICT size 1\_s*' ..
+        '\d SETTYPE dict<dict<unknown>>\_s*' ..
         '\d STORE $0\_s*' ..
         'd.dd\[0\] = 0\_s*' ..
         '\d PUSHNR 0\_s*' ..
@@ -457,7 +458,6 @@ def Test_disassemble_list_assign()
         '\d STORE $1\_s*' ..
         'var l: list<any>\_s*' ..
         '\d NEWLIST size 0\_s*' ..
-        '\d SETTYPE list<any>\_s*' ..
         '\d STORE $2\_s*' ..
         '\[x, y; l\] = g:stringlist\_s*' ..
         '\d LOADG g:stringlist\_s*' ..
@@ -470,7 +470,6 @@ def Test_disassemble_list_assign()
         '\d\+ CHECKTYPE string stack\[-1\] arg 2\_s*' ..
         '\d\+ STORE $1\_s*' ..
         '\d\+ SLICE 2\_s*' ..
-        '\d\+ SETTYPE list<any>\_s*' ..
         '\d\+ STORE $2\_s*' ..
         '\d\+ RETURN void',
         res)
@@ -615,13 +614,14 @@ def s:LockLocal()
   lockvar d.a
 enddef
 
-def Test_disassemble_locl_local()
+def Test_disassemble_lock_local()
   var res = execute('disass s:LockLocal')
   assert_match('<SNR>\d*_LockLocal\_s*' ..
         'var d = {a: 1}\_s*' ..
         '\d PUSHS "a"\_s*' ..
         '\d PUSHNR 1\_s*' ..
         '\d NEWDICT size 1\_s*' ..
+        '\d SETTYPE dict<number>\_s*' ..
         '\d STORE $0\_s*' ..
         'lockvar d.a\_s*' ..
         '\d LOAD $0\_s*' ..
@@ -1626,6 +1626,7 @@ def Test_disassemble_list_index()
         '\d PUSHNR 2\_s*' ..
         '\d PUSHNR 3\_s*' ..
         '\d NEWLIST size 3\_s*' ..
+        '\d SETTYPE list<number>\_s*' ..
         '\d STORE $0\_s*' ..
         'var res = l\[1]\_s*' ..
         '\d LOAD $0\_s*' ..
@@ -1650,13 +1651,15 @@ def Test_disassemble_list_slice()
         '\d PUSHNR 2\_s*' ..
         '\d PUSHNR 3\_s*' ..
         '\d NEWLIST size 3\_s*' ..
+        '\d SETTYPE list<number>\_s*' ..
         '\d STORE $0\_s*' ..
         'var res = l\[1 : 8]\_s*' ..
         '\d LOAD $0\_s*' ..
         '\d PUSHNR 1\_s*' ..
         '\d PUSHNR 8\_s*' ..
-        '\d LISTSLICE\_s*' ..
-        '\d STORE $1\_s*',
+        '\d\+ LISTSLICE\_s*' ..
+        '\d\+ SETTYPE list<number>\_s*' ..
+        '\d\+ STORE $1\_s*',
         instr)
   assert_equal([2, 3], ListSlice())
 enddef
@@ -1675,6 +1678,7 @@ def Test_disassemble_dict_member()
         '\d PUSHS "item"\_s*' ..
         '\d PUSHNR 1\_s*' ..
         '\d NEWDICT size 1\_s*' ..
+        '\d SETTYPE dict<number>\_s*' ..
         '\d STORE $0\_s*' ..
         'var res = d.item\_s*' ..
         '\d\+ LOAD $0\_s*' ..
@@ -2541,6 +2545,7 @@ def Test_disassemble_dict_stack()
           '\d PUSHS "func"\_s*' ..
           '\d PUSHFUNC "<80><fd>R\d\+_Legacy"\_s*' ..
           '\d NEWDICT size 1\_s*' ..
+          '\d SETTYPE dict<func(...): any>\_s*' ..
           '\d STORE $0\_s*' ..
 
           'var v = d.func()\_s*' ..
--- 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 */
 /**/
+    4390,
+/**/
     4389,
 /**/
     4388,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2002,6 +2002,7 @@ compile_assignment(char_u *arg, exarg_T 
 	int	instr_count = -1;
 	int	save_lnum;
 	int	skip_store = FALSE;
+	type_T	*inferred_type = NULL;
 
 	if (var_start[0] == '_' && !eval_isnamec(var_start[1]))
 	{
@@ -2126,7 +2127,10 @@ compile_assignment(char_u *arg, exarg_T 
 			    else if (rhs_type == &t_unknown)
 				lhs.lhs_lvar->lv_type = &t_any;
 			    else
+			    {
 				lhs.lhs_lvar->lv_type = rhs_type;
+				inferred_type = rhs_type;
+			    }
 			}
 		    }
 		    else if (*op == '=')
@@ -2146,7 +2150,7 @@ compile_assignment(char_u *arg, exarg_T 
 									 cctx))
 			    use_type = lhs.lhs_member_type;
 			if (need_type_where(rhs_type, use_type, -1, where,
-				    cctx, FALSE, is_const) == FAIL)
+						cctx, FALSE, is_const) == FAIL)
 			    goto theend;
 		    }
 		}
@@ -2315,10 +2319,20 @@ compile_assignment(char_u *arg, exarg_T 
 	    if ((lhs.lhs_type->tt_type == VAR_DICT
 					  || lhs.lhs_type->tt_type == VAR_LIST)
 		    && lhs.lhs_type->tt_member != NULL
+		    && lhs.lhs_type->tt_member != &t_any
 		    && lhs.lhs_type->tt_member != &t_unknown)
 		// Set the type in the list or dict, so that it can be checked,
 		// also in legacy script.
 		generate_SETTYPE(cctx, lhs.lhs_type);
+	    else if (inferred_type != NULL
+		    && (inferred_type->tt_type == VAR_DICT
+					|| inferred_type->tt_type == VAR_LIST)
+		    && inferred_type->tt_member != NULL
+		    && inferred_type->tt_member != &t_unknown
+		    && inferred_type->tt_member != &t_any)
+		// Set the type in the list or dict, so that it can be checked,
+		// also in legacy script.
+		generate_SETTYPE(cctx, inferred_type);
 
 	    if (!skip_store && generate_store_lhs(cctx, &lhs,
 						 instr_count, is_decl) == FAIL)