changeset 24426:78343859f42d v8.2.2753

patch 8.2.2753: Vim9: cannot ignore an item in assignment unpack Commit: https://github.com/vim/vim/commit/f93bbd026205f36915312193784f987ad49fb114 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Apr 10 22:35:43 2021 +0200 patch 8.2.2753: Vim9: cannot ignore an item in assignment unpack Problem: Vim9: cannot ignore an item in assignment unpack. Solution: Allow using an underscore.
author Bram Moolenaar <Bram@vim.org>
date Sat, 10 Apr 2021 22:45:04 +0200
parents 6e8954e66929
children e255d418a91d
files runtime/doc/vim9.txt src/eval.c src/evalvars.c src/testdir/test_vim9_assign.vim src/version.c src/vim.h src/vim9compile.c
diffstat 7 files changed, 46 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/vim9.txt
+++ b/runtime/doc/vim9.txt
@@ -335,6 +335,18 @@ The "g:" prefix is not needed for auto-l
 Since `&opt = value` is now assigning a value to option "opt", ":&" cannot be
 used to repeat a `:substitute` command.
 
+For an unpack assignment the underscore can be used to ignore a list item,
+similar to how a function argument can be ignored: >
+	[a, _, c] = theList
+	[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.
+
 
 Constants ~
 						*vim9-const* *vim9-final*
@@ -368,13 +380,6 @@ The constant only applies to the value i
 	NAMES[1] = ["Emma"]     # Error!
 	NAMES[1][0] = "Emma"    # OK, now females[0] == "Emma"
 
-<							*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.
-
 
 Omitting :call and :eval ~
 
--- a/src/eval.c
+++ b/src/eval.c
@@ -3514,7 +3514,7 @@ eval7(
 	{
 	    int	    flags = evalarg == NULL ? 0 : evalarg->eval_flags;
 
-	    if (in_vim9script() && len == 1 && *s == '_')
+	    if (evaluate && in_vim9script() && len == 1 && *s == '_')
 	    {
 		emsg(_(e_cannot_use_underscore_here));
 		ret = FAIL;
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -970,8 +970,8 @@ ex_let_vars(
     {
 	arg = skipwhite(arg + 1);
 	++var_idx;
-	arg = ex_let_one(arg, &item->li_tv, TRUE, flags, (char_u *)",;]",
-								  op, var_idx);
+	arg = ex_let_one(arg, &item->li_tv, TRUE,
+			  flags | ASSIGN_UNPACK, (char_u *)",;]", op, var_idx);
 	item = item->li_next;
 	if (arg == NULL)
 	    return FAIL;
@@ -996,8 +996,8 @@ ex_let_vars(
 	    l->lv_refcount = 1;
 	    ++var_idx;
 
-	    arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE, flags,
-						   (char_u *)"]", op, var_idx);
+	    arg = ex_let_one(skipwhite(arg + 1), &ltv, FALSE,
+			    flags | ASSIGN_UNPACK, (char_u *)"]", op, var_idx);
 	    clear_tv(&ltv);
 	    if (arg == NULL)
 		return FAIL;
@@ -3190,7 +3190,9 @@ set_var_const(
     var_in_vim9script = is_script_local && current_script_is_vim9();
     if (var_in_vim9script && name[0] == '_' && name[1] == NUL)
     {
-	emsg(_(e_cannot_use_underscore_here));
+	// For "[a, _] = list" the underscore is ignored.
+	if ((flags & ASSIGN_UNPACK) == 0)
+	    emsg(_(e_cannot_use_underscore_here));
 	goto failed;
     }
 
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -256,6 +256,14 @@ def Test_assign_unpack()
     [v1, v2] = [1, 2]
     assert_equal(1, v1)
     assert_equal(2, v2)
+
+    [v1, _, v2, _] = [1, 99, 2, 77]
+    assert_equal(1, v1)
+    assert_equal(2, v2)
+
+    [v1, v2; _] = [1, 2, 3, 4, 5]
+    assert_equal(1, v1)
+    assert_equal(2, v2)
   END
   CheckDefAndScriptSuccess(lines)
 
--- 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 */
 /**/
+    2753,
+/**/
     2752,
 /**/
     2751,
--- a/src/vim.h
+++ b/src/vim.h
@@ -2152,10 +2152,11 @@ typedef enum {
 } estack_arg_T;
 
 // Flags for assignment functions.
-#define ASSIGN_FINAL	1   // ":final"
-#define ASSIGN_CONST	2   // ":const"
-#define ASSIGN_NO_DECL	4   // "name = expr" without ":let"/":const"/":final"
-#define ASSIGN_DECL	8   // may declare variable if it does not exist
+#define ASSIGN_FINAL	0x01  // ":final"
+#define ASSIGN_CONST	0x02  // ":const"
+#define ASSIGN_NO_DECL	0x04  // "name = expr" without ":let"/":const"/":final"
+#define ASSIGN_DECL	0x08  // may declare variable if it does not exist
+#define ASSIGN_UNPACK	0x10  // using [a, b] = list
 
 #include "ex_cmds.h"	    // Ex command defines
 #include "spell.h"	    // spell checking stuff
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -6369,6 +6369,17 @@ compile_assignment(char_u *arg, exarg_T 
     {
 	int		instr_count = -1;
 
+	if (var_start[0] == '_' && !eval_isnamec(var_start[1]))
+	{
+	    // Ignore underscore in "[a, _, b] = list".
+	    if (var_count > 0)
+	    {
+		var_start = skipwhite(var_start + 2);
+		continue;
+	    }
+	    emsg(_(e_cannot_use_underscore_here));
+	    goto theend;
+	}
 	vim_free(lhs.lhs_name);
 
 	/*
@@ -6388,11 +6399,6 @@ compile_assignment(char_u *arg, exarg_T 
 	    semsg(_(e_cannot_assign_to_constant), lhs.lhs_name);
 	    goto theend;
 	}
-	if (is_decl && lhs.lhs_name[0] == '_' && lhs.lhs_name[1] == NUL)
-	{
-	    emsg(_(e_cannot_use_underscore_here));
-	    goto theend;
-	}
 
 	if (!heredoc)
 	{