Compare commits

...

4 Commits

Author SHA1 Message Date
Bram Moolenaar
1dcf55d4f1 patch 8.2.2195: failing tests for :const
Problem:    Failing tests for :const.
Solution:   Add missing check for ASSIGN_FINAL.
2020-12-22 22:07:30 +01:00
Bram Moolenaar
89b474dd4f 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 #7526)
2020-12-22 21:19:39 +01:00
Bram Moolenaar
3bdc90b7df patch 8.2.2193: Vim9: can change constant in :def function
Problem:    Vim9: can change constant in :def function.
Solution:   Check if a variable is locked. (issue #7526)
2020-12-22 20:35:40 +01:00
Bram Moolenaar
e5492609b3 patch 8.2.2192: Codecov on github actions fails
Problem:    Codecov on github actions fails.
Solution:   Revert to codecov script. (Ozaki Kiichi, closes #7529)
2020-12-22 19:05:33 +01:00
10 changed files with 121 additions and 37 deletions

View File

@@ -214,11 +214,9 @@ jobs:
- name: Codecov
if: matrix.coverage && success()
uses: codecov/codecov-action@v1
with:
flags: ${{ matrix.features }}-${{ matrix.compiler }}-${{ matrix.extra }}
fail_ci_if_error: true
working-directory: ${{ env.SRCDIR }}
run: |
cd "${SRCDIR}"
bash <(curl -s https://codecov.io/bash) -F "${{ matrix.features }}-${{ matrix.compiler }}-${{ matrix.extra }}"
- name: ASan logs
if: contains(matrix.extra, 'asan') && !cancelled()

View File

@@ -9,7 +9,7 @@ SRC_ALL = \
.lgtm.yml \
.travis.yml \
.cirrus.yml \
.github/workflows/ci-windows.yaml \
.github/workflows/ci.yml \
.github/workflows/codeql-analysis.yml \
.github/CODEOWNERS \
appveyor.yml \

View File

@@ -1334,7 +1334,7 @@ set_var_lval(
{
typval_T tv;
if (flags & ASSIGN_CONST)
if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
{
emsg(_(e_cannot_mod));
*endp = cc;
@@ -1372,7 +1372,7 @@ set_var_lval(
listitem_T *ll_li = lp->ll_li;
int ll_n1 = lp->ll_n1;
if (flags & ASSIGN_CONST)
if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
{
emsg(_("E996: Cannot lock a range"));
return;
@@ -1431,7 +1431,7 @@ set_var_lval(
/*
* Assign to a List or Dictionary item.
*/
if (flags & ASSIGN_CONST)
if (flags & (ASSIGN_CONST | ASSIGN_FINAL))
{
emsg(_("E996: Cannot lock a list or dict"));
return;

View File

@@ -738,25 +738,27 @@ 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)
{
emsg(_(e_cannot_use_let_in_vim9_script));
return;
}
if (eap->cmdidx == CMD_const && !vim9script && !eap->forceit)
// 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 +911,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 +1266,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 +1279,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 +1289,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 +1341,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 +1425,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 +3059,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 +3080,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 +3110,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;
@@ -3125,13 +3129,7 @@ set_var_const(
goto failed;
}
// Check in this order for backwards compatibility:
// - Whether the variable is read-only
// - Whether the variable value is locked
// - Whether the variable is locked
if (var_check_ro(di->di_flags, name, FALSE)
|| value_check_lock(di->di_tv.v_lock, name, FALSE)
|| var_check_lock(di->di_flags, name, FALSE))
if (var_check_permission(di, name) == FAIL)
goto failed;
}
else
@@ -3212,7 +3210,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
@@ -3230,7 +3228,8 @@ set_var_const(
init_tv(tv);
}
// ":const var = val" locks the value
// ":const var = value" locks the value
// ":final var = value" locks "var"
if (flags & ASSIGN_CONST)
// Like :lockvar! name: lock the value and what it contains, but only
// if the reference count is up to one. That locks only literal
@@ -3242,6 +3241,22 @@ failed:
clear_tv(tv_arg);
}
/*
* Check in this order for backwards compatibility:
* - Whether the variable is read-only
* - Whether the variable value is locked
* - Whether the variable is locked
*/
int
var_check_permission(dictitem_T *di, char_u *name)
{
if (var_check_ro(di->di_flags, name, FALSE)
|| value_check_lock(di->di_tv.v_lock, name, FALSE)
|| var_check_lock(di->di_flags, name, FALSE))
return FAIL;
return OK;
}
/*
* Return TRUE if di_flags "flags" indicates variable "name" is read-only.
* Also give an error message.

View File

@@ -70,6 +70,7 @@ void vars_clear_ext(hashtab_T *ht, int free_val);
void delete_var(hashtab_T *ht, hashitem_T *hi);
void set_var(char_u *name, typval_T *tv, int copy);
void set_var_const(char_u *name, type_T *type, typval_T *tv_arg, int copy, int flags);
int var_check_permission(dictitem_T *di, char_u *name);
int var_check_ro(int flags, char_u *name, int use_gettext);
int var_check_lock(int flags, char_u *name, int use_gettext);
int var_check_fixed(int flags, char_u *name, int use_gettext);

View File

@@ -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()
@@ -1159,6 +1189,22 @@ def Test_var_declaration_fails()
END
CheckScriptFailure(lines, 'E1125:')
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

View File

@@ -1022,6 +1022,17 @@ def Test_vim9script_call_fail_const()
writefile(lines, 'Xcall_const.vim')
assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc')
delete('Xcall_const.vim')
lines =<< trim END
const g:Aconst = 77
def Change()
# comment
g:Aconst = 99
enddef
call Change()
unlet g:Aconst
END
CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2)
enddef
" Test that inside :function a Python function can be defined, :def is not

View File

@@ -750,6 +750,14 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2195,
/**/
2194,
/**/
2193,
/**/
2192,
/**/
2191,
/**/

View File

@@ -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

View File

@@ -1693,8 +1693,10 @@ call_def_function(
case ISN_STOREW:
case ISN_STORET:
{
dictitem_T *di;
hashtab_T *ht;
dictitem_T *di;
hashtab_T *ht;
char_u *name = iptr->isn_arg.string + 2;
switch (iptr->isn_type)
{
case ISN_STOREG:
@@ -1714,11 +1716,14 @@ call_def_function(
}
--ectx.ec_stack.ga_len;
di = find_var_in_ht(ht, 0, iptr->isn_arg.string + 2, TRUE);
di = find_var_in_ht(ht, 0, name, TRUE);
if (di == NULL)
store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
else
{
SOURCING_LNUM = iptr->isn_lnum;
if (var_check_permission(di, name) == FAIL)
goto on_error;
clear_tv(&di->di_tv);
di->di_tv = *STACK_TV_BOT(0);
}