# HG changeset patch # User Bram Moolenaar # Date 1618087504 -7200 # Node ID 78343859f42d5a6487f2fb5af11624ea110b74f2 # Parent 6e8954e66929450032bafe55d026b09905af1943 patch 8.2.2753: Vim9: cannot ignore an item in assignment unpack Commit: https://github.com/vim/vim/commit/f93bbd026205f36915312193784f987ad49fb114 Author: Bram Moolenaar 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. diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt --- 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 ~ diff --git a/src/eval.c b/src/eval.c --- 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; diff --git a/src/evalvars.c b/src/evalvars.c --- 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), <v, FALSE, flags, - (char_u *)"]", op, var_idx); + arg = ex_let_one(skipwhite(arg + 1), <v, FALSE, + flags | ASSIGN_UNPACK, (char_u *)"]", op, var_idx); clear_tv(<v); 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; } diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim --- 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) diff --git a/src/version.c b/src/version.c --- 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, diff --git a/src/vim.h b/src/vim.h --- 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 diff --git a/src/vim9compile.c b/src/vim9compile.c --- 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) {