Skip to content

Commit

Permalink
patch 8.2.2753: Vim9: cannot ignore an item in assignment unpack
Browse files Browse the repository at this point in the history
Problem:    Vim9: cannot ignore an item in assignment unpack.
Solution:   Allow using an underscore.
  • Loading branch information
brammool committed Apr 10, 2021
1 parent e8e3078 commit f93bbd0
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 22 deletions.
19 changes: 12 additions & 7 deletions runtime/doc/vim9.txt
Expand Up @@ -335,6 +335,18 @@ The "g:" prefix is not needed for auto-load functions.
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*
Expand Down Expand Up @@ -368,13 +380,6 @@ The constant only applies to the value itself, not what it refers to. >
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 ~

Expand Down
2 changes: 1 addition & 1 deletion src/eval.c
Expand Up @@ -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;
Expand Down
12 changes: 7 additions & 5 deletions src/evalvars.c
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
8 changes: 8 additions & 0 deletions src/testdir/test_vim9_assign.vim
Expand Up @@ -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)

Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Expand Up @@ -750,6 +750,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2753,
/**/
2752,
/**/
Expand Down
9 changes: 5 additions & 4 deletions src/vim.h
Expand Up @@ -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
Expand Down
16 changes: 11 additions & 5 deletions src/vim9compile.c
Expand Up @@ -6369,6 +6369,17 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
{
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);

/*
Expand All @@ -6388,11 +6399,6 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
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)
{
Expand Down

0 comments on commit f93bbd0

Please sign in to comment.