# HG changeset patch # User Bram Moolenaar # Date 1609532104 -3600 # Node ID a8e7acf71fa47b68d02c8313ecd0e0053fe0cf6d # Parent f04821549e6f255d6a6d47134311e67bb0022183 patch 8.2.2268: Vim9: list unpack seen as declaration Commit: https://github.com/vim/vim/commit/3862ea3f620f02569c2d816ca9ceeeac3a0ad901 Author: Bram Moolenaar Date: Fri Jan 1 21:05:55 2021 +0100 patch 8.2.2268: Vim9: list unpack seen as declaration Problem: Vim9: list unpack seen as declaration. Solution: Check for "var". (closes https://github.com/vim/vim/issues/7594) diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -1748,7 +1748,7 @@ next_for_item(void *fi_void, char_u *arg { forinfo_T *fi = (forinfo_T *)fi_void; int result; - int flag = in_vim9script() ? ASSIGN_NO_DECL : 0; + int flag = in_vim9script() ? ASSIGN_DECL : 0; listitem_T *item; if (fi->fi_blob != NULL) diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -912,7 +912,7 @@ ex_let_vars( int copy, // copy values from "tv", don't move int semicolon, // from skip_var_list() int var_count, // from skip_var_list() - int flags, // ASSIGN_FINAL, ASSIGN_CONST, ASSIGN_NO_DECL + int flags, // ASSIGN_FINAL, ASSIGN_CONST, etc. char_u *op) { char_u *arg = arg_start; @@ -1267,7 +1267,7 @@ ex_let_one( char_u *arg, // points to variable name typval_T *tv, // value to assign to variable int copy, // copy value from "tv" - int flags, // ASSIGN_CONST, ASSIGN_FINAL, ASSIGN_NO_DECL + int flags, // ASSIGN_CONST, ASSIGN_FINAL, etc. char_u *endchars, // valid chars after variable name or NULL char_u *op) // "+", "-", "." or NULL { @@ -1279,7 +1279,7 @@ ex_let_one( int opt_flags; char_u *tofree = NULL; - if (in_vim9script() && (flags & ASSIGN_NO_DECL) == 0 + if (in_vim9script() && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0 && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0 && vim_strchr((char_u *)"$@&", *arg) != NULL) { @@ -1476,7 +1476,8 @@ ex_let_one( lval_T lv; p = get_lval(arg, tv, &lv, FALSE, FALSE, - (flags & ASSIGN_NO_DECL) ? GLV_NO_DECL : 0, FNE_CHECK_START); + (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) + ? GLV_NO_DECL : 0, FNE_CHECK_START); if (p != NULL && lv.ll_name != NULL) { if (endchars != NULL && vim_strchr(endchars, @@ -3053,7 +3054,7 @@ set_var( typval_T *tv, int copy) // make copy of value in "tv" { - set_var_const(name, NULL, tv, copy, ASSIGN_NO_DECL); + set_var_const(name, NULL, tv, copy, ASSIGN_DECL); } /* @@ -3067,7 +3068,7 @@ set_var_const( type_T *type, typval_T *tv_arg, int copy, // make copy of value in "tv" - int flags) // ASSIGN_CONST, ASSIGN_FINAL, ASSIGN_NO_DECL + int flags) // ASSIGN_CONST, ASSIGN_FINAL, etc. { typval_T *tv = tv_arg; typval_T bool_tv; @@ -3087,7 +3088,7 @@ set_var_const( if (vim9script && !is_script_local - && (flags & ASSIGN_NO_DECL) == 0 + && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0 && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0 && name[1] == ':') { @@ -3126,7 +3127,7 @@ set_var_const( if (is_script_local && vim9script) { - if ((flags & ASSIGN_NO_DECL) == 0) + if ((flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0) { semsg(_(e_redefining_script_item_str), name); goto failed; @@ -3200,8 +3201,15 @@ set_var_const( clear_tv(&di->di_tv); } - else // add a new variable + else { + // add a new variable + if (vim9script && is_script_local && (flags & ASSIGN_NO_DECL)) + { + semsg(_(e_unknown_variable_str), name); + goto failed; + } + // Can't add "v:" or "a:" variable. if (ht == &vimvarht || ht == get_funccal_args_ht()) { 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 @@ -262,6 +262,12 @@ def Test_assign_unpack() CheckDefFailure(lines, 'E1031:', 3) lines =<< trim END + [v1, v2] = [1, 2] + END + CheckDefFailure(lines, 'E1089', 1) + CheckScriptFailure(['vim9script'] + lines, 'E1089', 2) + + lines =<< trim END var v1: number var v2: number [v1, v2] = '' @@ -759,6 +765,8 @@ def Test_assignment_default() assert_equal(5678, nr) enddef +let scriptvar = 'init' + def Test_assignment_var_list() var lines =<< trim END var v1: string @@ -794,10 +802,9 @@ def Test_assignment_var_list() assert_equal('some', $SOME_VAR) assert_equal('other', $OTHER_VAR) - [g:globalvar, s:scriptvar, b:bufvar, w:winvar, t:tabvar, v:errmsg] = - ['global', 'script', 'buf', 'win', 'tab', 'error'] + [g:globalvar, b:bufvar, w:winvar, t:tabvar, v:errmsg] = + ['global', 'buf', 'win', 'tab', 'error'] assert_equal('global', g:globalvar) - assert_equal('script', s:scriptvar) assert_equal('buf', b:bufvar) assert_equal('win', w:winvar) assert_equal('tab', t:tabvar) @@ -805,6 +812,21 @@ def Test_assignment_var_list() unlet g:globalvar END CheckDefAndScriptSuccess(lines) + + [g:globalvar, s:scriptvar, b:bufvar] = ['global', 'script', 'buf'] + assert_equal('global', g:globalvar) + assert_equal('script', s:scriptvar) + assert_equal('buf', b:bufvar) + + lines =<< trim END + vim9script + var s:scriptvar = 'init' + [g:globalvar, s:scriptvar, w:winvar] = ['global', 'script', 'win'] + assert_equal('global', g:globalvar) + assert_equal('script', s:scriptvar) + assert_equal('win', w:winvar) + END + CheckScriptSuccess(lines) enddef def Test_assignment_vim9script() @@ -1182,7 +1204,7 @@ def Test_var_declaration() g:other_var = other # type is inferred - s:dict = {['a']: 222} + var s:dict = {['a']: 222} def GetDictVal(key: any) g:dict_val = s:dict[key] enddef 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 */ /**/ + 2268, +/**/ 2267, /**/ 2266, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -2146,6 +2146,7 @@ typedef enum { #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 #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 @@ -5634,6 +5634,11 @@ compile_assignment(char_u *arg, exarg_T semsg(_(e_cannot_use_operator_on_new_variable), name); goto theend; } + if (!is_decl) + { + semsg(_(e_unknown_variable_str), name); + goto theend; + } // new local variable if ((type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL) @@ -6140,6 +6145,7 @@ compile_unletlock(char_u *arg, exarg_T * return NULL; } + // TODO: this doesn't work for local variables ex_unletlock(eap, p, 0, GLV_NO_AUTOLOAD, compile_unlet, cctx); return eap->nextcmd == NULL ? (char_u *)"" : eap->nextcmd; } diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -806,7 +806,7 @@ store_var(char_u *name, typval_T *tv) funccal_entry_T entry; save_funccal(&entry); - set_var_const(name, NULL, tv, FALSE, ASSIGN_NO_DECL); + set_var_const(name, NULL, tv, FALSE, ASSIGN_DECL); restore_funccal(); }