]> granicus.if.org Git - vim/commitdiff
patch 8.2.3704: Vim9: cannot use a list declaration in a :def function v8.2.3704
authorBram Moolenaar <Bram@vim.org>
Tue, 30 Nov 2021 16:14:49 +0000 (16:14 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 30 Nov 2021 16:14:49 +0000 (16:14 +0000)
Problem:    Vim9: cannot use a list declaration in a :def function.
Solution:   Make it work.

runtime/doc/vim9.txt
src/errors.h
src/testdir/test_vim9_assign.vim
src/version.c
src/vim9compile.c

index 1782f179a3baa065994672890119e6291e9ab256..dc39559c07d104fa9cb4bf5e9a36b9e30a49ccd2 100644 (file)
@@ -420,12 +420,11 @@ similar to how a function argument can be ignored: >
 To ignore any remaining items: >
        [a, b; _] = longList
 
-<                                                      *E1092*
 Declaring more than one variable at a time, using the unpack notation, is
-currently not supported: >
-       var [v1, v2] = GetValues()  # Error!
-That is because the type needs to be inferred from the list item type, which
-isn't that easy.
+possible.  Each variable can have a type or infer it from the value: >
+       var [v1: number, v2] = GetValues()
+Use this only when there is a list with values, declaring one variable per
+line is much easier to read and change later.
 
 
 Constants ~
index 5cc98e7864905ce6c2ca98e47987a7725a6a5496..e09ef53dced5e09fdc74c2d5569c7c06ce261ca3 100644 (file)
@@ -366,8 +366,7 @@ EXTERN char e_cannot_assign_to_argument[]
        INIT(= N_("E1090: Cannot assign to argument %s"));
 EXTERN char e_function_is_not_compiled_str[]
        INIT(= N_("E1091: Function is not compiled: %s"));
-EXTERN char e_cannot_use_list_for_declaration[]
-       INIT(= N_("E1092: Cannot use a list for a declaration"));
+// E1092 unused
 EXTERN char e_expected_nr_items_but_got_nr[]
        INIT(= N_("E1093: Expected %d items but got %d"));
 EXTERN char e_import_can_only_be_used_in_script[]
index 394dfe663832cf2269fe6010f430b1f2900bd5a0..87924c62946865e9d664720209f090fe41c0c3df 100644 (file)
@@ -732,7 +732,6 @@ def Test_assignment_list()
   assert_equal(['sdf', 'asdf', 'end'], list3)
 
   CheckDefExecFailure(['var ll = [1, 2, 3]', 'll[-4] = 6'], 'E684:')
-  CheckDefExecFailure(['var [v1, v2] = [1, 2]'], 'E1092:')
 
   # type becomes list<any>
   var somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
@@ -753,6 +752,60 @@ def Test_assignment_list()
   CheckDefExecAndScriptFailure(lines, 'E1012:', 5)
 enddef
 
+def Test_list_declaration()
+  var [v1, v2] = [1, 2]
+  v1 += 3
+  assert_equal(4, v1)
+  v2 *= 3
+  assert_equal(6, v2)
+
+  var lines =<< trim END
+      var [v1, v2] = [1]
+  END
+  CheckDefExecAndScriptFailure2(lines, 'E1093: Expected 2 items but got 1', 'E688:')
+  lines =<< trim END
+      var testlist = [1]
+      var [v1, v2] = testlist
+  END
+  CheckDefExecAndScriptFailure2(lines, 'E1093: Expected 2 items but got 1', 'E688:')
+  lines =<< trim END
+      var [v1, v2] = [1, 2, 3]
+  END
+  CheckDefExecAndScriptFailure2(lines, 'E1093: Expected 2 items but got 3', 'E687:')
+  lines =<< trim END
+      var testlist = [1, 2, 3]
+      var [v1, v2] = testlist
+  END
+  CheckDefExecAndScriptFailure2(lines, 'E1093: Expected 2 items but got 3', 'E687:')
+
+  var [vnr, vstr] = [123, 'text']
+  vnr += 3
+  assert_equal(126, vnr)
+  vstr ..= 'end'
+  assert_equal('textend', vstr)
+
+  var [vnr2: number, vstr2: string] = [123, 'text']
+  vnr2 += 3
+  assert_equal(126, vnr2)
+  vstr2 ..= 'end'
+  assert_equal('textend', vstr2)
+
+  var [vnr3: number; vlist: list<string>] = [123, 'foo', 'bar']
+  vnr3 += 5
+  assert_equal(128, vnr3)
+  assert_equal(['foo', 'bar'], vlist)
+
+  lines =<< trim END
+      var [vnr2: number, vstr2: number] = [123, 'text']
+  END
+  CheckDefExecAndScriptFailure2(lines, 'E1163: Variable 2: type mismatch, expected number but got string', 'E1012: Type mismatch; expected number but got string')
+  lines =<< trim END
+      var testlist = [234, 'text']
+      var [vnr2: number, vstr2: number] = testlist
+  END
+  CheckDefExecAndScriptFailure2(lines, 'E1163: Variable 2: type mismatch, expected number but got string', 'E1012: Type mismatch; expected number but got string')
+enddef
+
 def PartFuncBool(b: bool): string
   return 'done'
 enddef
index a190af5c9e011112c409f7dc3532ff5eae41932e..32efc5c83f86585e9925731be0179da6ca68bc0e 100644 (file)
@@ -753,6 +753,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3704,
 /**/
     3703,
 /**/
index e5e806cb60dcb2f9cf7c03b4f9834a8223e130be..58149ed5c6f267a48cb4f6395b132d30b8d0bc7b 100644 (file)
@@ -144,6 +144,7 @@ typedef struct {
                                      // any "[expr]" or ".name"
     char_u         *lhs_dest_end;  // end of the destination, including
                                    // "[expr]" or ".name".
+    char_u         *lhs_end;       // end including any type
 
     int                    lhs_has_index;  // has "[expr]" or ".name"
 
@@ -6299,6 +6300,7 @@ compile_lhs(
        --lhs->lhs_dest_end;
     if (is_decl && var_end == var_start + 2 && var_end[-1] == ':')
        --var_end;
+    lhs->lhs_end = lhs->lhs_dest_end;
 
     // compute the length of the destination without "[expr]" or ".name"
     lhs->lhs_varlen = var_end - var_start;
@@ -6435,7 +6437,7 @@ compile_lhs(
        }
     }
 
-    // handle "a:name" as a name, not index "name" on "a"
+    // handle "a:name" as a name, not index "name" in "a"
     if (lhs->lhs_varlen > 1 || var_start[lhs->lhs_varlen] != ':')
        var_end = lhs->lhs_dest_end;
 
@@ -6456,6 +6458,7 @@ compile_lhs(
            if (lhs->lhs_type == NULL)
                return FAIL;
            lhs->lhs_has_type = TRUE;
+           lhs->lhs_end = p;
        }
        else if (lhs->lhs_lvar != NULL)
            lhs->lhs_type = lhs->lhs_lvar->lv_type;
@@ -6896,13 +6899,6 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
     if (p == NULL)
        return *arg == '[' ? arg : NULL;
 
-    if (var_count > 0 && is_decl)
-    {
-       // TODO: should we allow this, and figure out type inference from list
-       // members?
-       emsg(_(e_cannot_use_list_for_declaration));
-       return NULL;
-    }
     lhs.lhs_name = NULL;
 
     sp = p;
@@ -7330,7 +7326,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
        cctx->ctx_lnum = save_lnum;
 
        if (var_idx + 1 < var_count)
-           var_start = skipwhite(lhs.lhs_dest_end + 1);
+           var_start = skipwhite(lhs.lhs_end + 1);
     }
 
     // For "[var, var] = expr" drop the "expr" value.