# HG changeset patch # User Bram Moolenaar # Date 1608669004 -3600 # Node ID 40f1d3f0c53e3717430e7b81e704a45ead448f1e # Parent c9123e2447bc74fe19de477d82900c1c13c77299 patch 8.2.2194: Vim9: cannot use :const or :final at the script level Commit: https://github.com/vim/vim/commit/89b474dd4f0de878b4c48eeb9e223f0c22ee1442 Author: Bram Moolenaar Date: Tue Dec 22 21:19:39 2020 +0100 patch 8.2.2194: Vim9: cannot use :const or :final at the script level Problem: Vim9: cannot use :const or :final at the script level. Solution: Support using :const and :final. (closes https://github.com/vim/vim/issues/7526) diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -738,14 +738,14 @@ ex_let(exarg_T *eap) int first = TRUE; int concat; int has_assign; - int flags = eap->cmdidx == CMD_const ? ASSIGN_CONST : 0; + int flags = 0; int vim9script = in_vim9script(); if (eap->cmdidx == CMD_final && !vim9script) { - // In legacy Vim script ":final" is short for ":finally". - ex_finally(eap); - return; + // In legacy Vim script ":final" is short for ":finally". + ex_finally(eap); + return; } if (eap->cmdidx == CMD_let && vim9script) { @@ -756,7 +756,12 @@ ex_let(exarg_T *eap) // In legacy Vim script ":const" works like ":final". eap->cmdidx = CMD_final; - // detect Vim9 assignment without ":let" or ":const" + if (eap->cmdidx == CMD_const) + flags |= ASSIGN_CONST; + else if (eap->cmdidx == CMD_final) + flags |= ASSIGN_FINAL; + + // Vim9 assignment without ":let", ":const" or ":final" if (eap->arg == eap->cmd) flags |= ASSIGN_NO_DECL; @@ -909,7 +914,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_CONST, ASSIGN_NO_DECL + int flags, // ASSIGN_FINAL, ASSIGN_CONST, ASSIGN_NO_DECL char_u *op) { char_u *arg = arg_start; @@ -1264,7 +1269,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_NO_DECL + int flags, // ASSIGN_CONST, ASSIGN_FINAL, ASSIGN_NO_DECL char_u *endchars, // valid chars after variable name or NULL char_u *op) // "+", "-", "." or NULL { @@ -1277,6 +1282,7 @@ ex_let_one( char_u *tofree = NULL; if (in_vim9script() && (flags & ASSIGN_NO_DECL) == 0 + && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0 && vim_strchr((char_u *)"$@&", *arg) != NULL) { vim9_declare_error(arg); @@ -1286,7 +1292,7 @@ ex_let_one( // ":let $VAR = expr": Set environment variable. if (*arg == '$') { - if (flags & ASSIGN_CONST) + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_("E996: Cannot lock an environment variable")); return NULL; @@ -1338,7 +1344,7 @@ ex_let_one( // ":let &g:option = expr": Set global option value. else if (*arg == '&') { - if (flags & ASSIGN_CONST) + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_(e_const_option)); return NULL; @@ -1422,7 +1428,7 @@ ex_let_one( // ":let @r = expr": Set register contents. else if (*arg == '@') { - if (flags & ASSIGN_CONST) + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_("E996: Cannot lock a register")); return NULL; @@ -3056,7 +3062,7 @@ set_var_const( type_T *type, typval_T *tv_arg, int copy, // make copy of value in "tv" - int flags) // ASSIGN_CONST, ASSIGN_NO_DECL + int flags) // ASSIGN_CONST, ASSIGN_FINAL, ASSIGN_NO_DECL { typval_T *tv = tv_arg; typval_T bool_tv; @@ -3077,6 +3083,7 @@ set_var_const( if (vim9script && !is_script_local && (flags & ASSIGN_NO_DECL) == 0 + && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0 && name[1] == ':') { vim9_declare_error(name); @@ -3106,7 +3113,7 @@ set_var_const( { if ((di->di_flags & DI_FLAGS_RELOAD) == 0) { - if (flags & ASSIGN_CONST) + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) { emsg(_(e_cannot_mod)); goto failed; @@ -3206,7 +3213,7 @@ set_var_const( goto failed; } di->di_flags = DI_FLAGS_ALLOC; - if (flags & ASSIGN_CONST) + if (flags & (ASSIGN_CONST | ASSIGN_FINAL)) di->di_flags |= DI_FLAGS_LOCK; // A Vim9 script-local variable is also added to sn_all_vars and 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 @@ -1127,6 +1127,30 @@ def Test_var_declaration() const FOO: number = 123 assert_equal(123, FOO) + const FOOS = 'foos' + assert_equal('foos', FOOS) + final FLIST = [1] + assert_equal([1], FLIST) + FLIST[0] = 11 + assert_equal([11], FLIST) + + const g:FOO: number = 321 + assert_equal(321, g:FOO) + const g:FOOS = 'gfoos' + assert_equal('gfoos', g:FOOS) + final g:FLIST = [2] + assert_equal([2], g:FLIST) + g:FLIST[0] = 22 + assert_equal([22], g:FLIST) + + const w:FOO: number = 46 + assert_equal(46, w:FOO) + const w:FOOS = 'wfoos' + assert_equal('wfoos', w:FOOS) + final w:FLIST = [3] + assert_equal([3], w:FLIST) + w:FLIST[0] = 33 + assert_equal([33], w:FLIST) var s:other: number other = 1234 @@ -1150,6 +1174,12 @@ def Test_var_declaration() unlet g:var_test unlet g:var_prefixed unlet g:other_var + unlet g:FOO + unlet g:FOOS + unlet g:FLIST + unlet w:FOO + unlet w:FOOS + unlet w:FLIST enddef def Test_var_declaration_fails() @@ -1161,6 +1191,22 @@ def Test_var_declaration_fails() lines =<< trim END vim9script + const g:constvar = 'string' + g:constvar = 'xx' + END + CheckScriptFailure(lines, 'E741:') + unlet g:constvar + + lines =<< trim END + vim9script + final w:finalvar = [9] + w:finalvar = [8] + END + CheckScriptFailure(lines, 'E1122:') + unlet w:finalvar + + lines =<< trim END + vim9script const var: string END CheckScriptFailure(lines, 'E1021:') diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -1032,7 +1032,7 @@ def Test_vim9script_call_fail_const() call Change() unlet g:Aconst END - CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2) + CheckScriptFailure(lines, 'E1122: Variable is locked: Aconst', 2) enddef " Test that inside :function a Python function can be defined, :def is not 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 */ /**/ + 2194, +/**/ 2193, /**/ 2192, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -2144,7 +2144,7 @@ typedef enum { // Flags for assignment functions. #define ASSIGN_FINAL 1 // ":final" #define ASSIGN_CONST 2 // ":const" -#define ASSIGN_NO_DECL 4 // "name = expr" without ":let" or ":const" +#define ASSIGN_NO_DECL 4 // "name = expr" without ":let"/":const"/":final" #include "ex_cmds.h" // Ex command defines #include "spell.h" // spell checking stuff