]> granicus.if.org Git - vim/commitdiff
patch 8.2.4390: Vim9: list from declaration with inferred type not set v8.2.4390
authorBram Moolenaar <Bram@vim.org>
Tue, 15 Feb 2022 15:37:11 +0000 (15:37 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 15 Feb 2022 15:37:11 +0000 (15:37 +0000)
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".

src/testdir/test_vim9_assign.vim
src/testdir/test_vim9_builtin.vim
src/testdir/test_vim9_disassemble.vim
src/version.c
src/vim9compile.c

index 8a00cebab747de3b0f805404ac8bd05dcb4009da..9c988c96ffab9747bb992b630ea8f3b3065e1577 100644 (file)
@@ -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
index 23b9c4936b53dea2a16a7f3db6320d1b94dd87fd..09cfd707d960f60a00fafca8b57e817876bb25c4 100644 (file)
@@ -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()
index ec71836606ea7313470b42ebb647dae9ed8c347c..91464a7687a22421722a579c08f5df9fe594223e 100644 (file)
@@ -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*' ..
index 7bf2ddb9ac5c7a017f099795bd6a9be2cdaf3412..8edb112beebf6a19d14a9c6fa81f867dd3dfd6c7 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4390,
 /**/
     4389,
 /**/
index a0efafc1ea0337e70aa66ef9fe9a85c177422e02..0eb41e4c132b6f73b932e1394e34f44b10f8178c 100644 (file)
@@ -2002,6 +2002,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
        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 *eap, cmdidx_T cmdidx, cctx_T *cctx)
                            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 *eap, cmdidx_T cmdidx, cctx_T *cctx)
                                                                         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 *eap, cmdidx_T cmdidx, cctx_T *cctx)
            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)