summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-02-12 19:52:25 +0000
committerBram Moolenaar <Bram@vim.org>2022-02-12 19:52:25 +0000
commita749a42ed25534c88c636e5ab6603f1f97b857a4 (patch)
tree2458c780205a1f80efd0e579ed2f75346a4d2085
parent6e28703a8e41f775f64e442c5d11ce1ff599aa3f (diff)
downloadvim-git-8.2.4360.tar.gz
patch 8.2.4360: Vim9: allowing use of "s:" leads to inconsistenciesv8.2.4360
Problem: Vim9: allowing use of "s:" leads to inconsistencies. Solution: Disallow using "s:" in Vim9 script at the script level.
-rw-r--r--src/errors.h4
-rw-r--r--src/eval.c14
-rw-r--r--src/proto/userfunc.pro1
-rw-r--r--src/testdir/test_vim9_assign.vim59
-rw-r--r--src/testdir/test_vim9_builtin.vim4
-rw-r--r--src/testdir/test_vim9_cmd.vim7
-rw-r--r--src/testdir/test_vim9_disassemble.vim4
-rw-r--r--src/testdir/test_vim9_expr.vim8
-rw-r--r--src/testdir/test_vim9_func.vim12
-rw-r--r--src/testdir/test_vim9_import.vim12
-rw-r--r--src/testdir/test_vim9_script.vim53
-rw-r--r--src/testdir/vim9.vim12
-rw-r--r--src/userfunc.c18
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c2
15 files changed, 151 insertions, 61 deletions
diff --git a/src/errors.h b/src/errors.h
index c66d26d8d..ef9e08346 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -2828,7 +2828,7 @@ EXTERN char e_unknown_error_while_executing_str[]
INIT(= N_("E1099: Unknown error while executing %s"));
EXTERN char e_command_not_supported_in_vim9_script_missing_var_str[]
INIT(= N_("E1100: Command not supported in Vim9 script (missing :var?): %s"));
-EXTERN char e_cannot_declare_script_variable_in_function[]
+EXTERN char e_cannot_declare_script_variable_in_function_str[]
INIT(= N_("E1101: Cannot declare a script variable in a function: %s"));
EXTERN char e_lambda_function_not_found_str[]
INIT(= N_("E1102: Lambda function not found: %s"));
@@ -3232,4 +3232,6 @@ EXTERN char e_critical_error_in_python3_initialization_check_your_installation[]
#ifdef FEAT_EVAL
EXTERN char e_function_name_must_start_with_capital_str[]
INIT(= N_("E1267: Function name must start with a capital: %s"));
+EXTERN char e_cannot_use_s_colon_in_vim9_script_str[]
+ INIT(= N_("E1268: Cannot use s: in Vim9 script: %s"));
#endif
diff --git a/src/eval.c b/src/eval.c
index 81a1dd0a9..261a397aa 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -878,6 +878,14 @@ get_lval(
return lp->ll_name_end;
}
+ // Cannot use "s:var" at the Vim9 script level. "s: type" is OK.
+ if (in_vim9script() && at_script_level()
+ && name[0] == 's' && name[1] == ':' && !VIM_ISWHITE(name[2]))
+ {
+ semsg(_(e_cannot_use_s_colon_in_vim9_script_str), name);
+ return NULL;
+ }
+
// Find the end of the name.
p = find_name_end(name, &expr_start, &expr_end, fne_flags);
lp->ll_name_end = p;
@@ -3732,6 +3740,12 @@ eval7(
emsg(_(e_cannot_use_underscore_here));
ret = FAIL;
}
+ else if (evaluate && in_vim9script() && len > 2
+ && s[0] == 's' && s[1] == ':')
+ {
+ semsg(_(e_cannot_use_s_colon_in_vim9_script_str), s);
+ ret = FAIL;
+ }
else if ((in_vim9script() ? **arg : *skipwhite(*arg)) == '(')
{
// "name(..." recursive!
diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro
index 4e30d83c4..b8d14437d 100644
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -24,6 +24,7 @@ int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T
void save_funccal(funccal_entry_T *entry);
void restore_funccal(void);
funccall_T *get_current_funccal(void);
+int at_script_level(void);
void delete_script_functions(int sid);
void free_all_functions(void);
int builtin_function(char_u *name, int len);
diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim
index 7d3e2c135..d9b8f3a24 100644
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -6,6 +6,7 @@ source term_util.vim
let s:appendToMe = 'xxx'
let s:addToMe = 111
+let s:newVar = ''
let g:existing = 'yes'
let g:inc_counter = 1
let $SOME_ENV_VAR = 'some'
@@ -124,12 +125,12 @@ def Test_assignment()
END
v9.CheckScriptSuccess(lines)
- s:appendToMe ..= 'yyy'
- assert_equal('xxxyyy', s:appendToMe)
- s:addToMe += 222
- assert_equal(333, s:addToMe)
- s:newVar = 'new'
- assert_equal('new', s:newVar)
+ appendToMe ..= 'yyy'
+ assert_equal('xxxyyy', appendToMe)
+ addToMe += 222
+ assert_equal(333, addToMe)
+ newVar = 'new'
+ assert_equal('new', newVar)
set ts=7
var ts: number = &ts
@@ -1195,7 +1196,7 @@ def Test_assignment_default()
assert_equal(5678, nr)
enddef
-let scriptvar = 'init'
+let s:scriptvar = 'init'
def Test_assignment_var_list()
var lines =<< trim END
@@ -1243,17 +1244,17 @@ def Test_assignment_var_list()
END
v9.CheckDefAndScriptSuccess(lines)
- [g:globalvar, s:scriptvar, b:bufvar] = ['global', 'script', 'buf']
+ [g:globalvar, scriptvar, b:bufvar] = ['global', 'script', 'buf']
assert_equal('global', g:globalvar)
- assert_equal('script', s:scriptvar)
+ assert_equal('script', scriptvar)
assert_equal('buf', b:bufvar)
lines =<< trim END
vim9script
- var s:scriptvar = 'init'
- [g:globalvar, s:scriptvar, w:winvar] = ['global', 'script', 'win']
+ var scriptvar = 'init'
+ [g:globalvar, scriptvar, w:winvar] = ['global', 'script', 'win']
assert_equal('global', g:globalvar)
- assert_equal('script', s:scriptvar)
+ assert_equal('script', scriptvar)
assert_equal('win', w:winvar)
END
v9.CheckScriptSuccess(lines)
@@ -1398,7 +1399,7 @@ def Test_assignment_failure()
v9.CheckDefFailure(["var xnr = xnr + 1"], 'E1001:', 1)
v9.CheckScriptFailure(['vim9script', 'var xnr = xnr + 4'], 'E121:')
- v9.CheckScriptFailure(['vim9script', 'def Func()', 'var dummy = s:notfound', 'enddef', 'defcompile'], 'E1108:')
+ v9.CheckScriptFailure(['vim9script', 'def Func()', 'var dummy = notfound', 'enddef', 'defcompile'], 'E1001:')
v9.CheckDefFailure(['var name: list<string> = [123]'], 'expected list<string> but got list<number>')
v9.CheckDefFailure(['var name: list<number> = ["xx"]'], 'expected list<number> but got list<string>')
@@ -1719,9 +1720,9 @@ def Test_var_declaration()
g:var_uninit = name
name = 'text'
g:var_test = name
- # prefixing s: is optional
- s:name = 'prefixed'
- g:var_prefixed = s:name
+ # prefixing s: is not allowed
+ name = 'prefixed'
+ g:var_prefixed = name
const FOO: number = 123
assert_equal(123, FOO)
@@ -1764,9 +1765,9 @@ def Test_var_declaration()
var xyz: string # comment
# type is inferred
- var s:dict = {['a']: 222}
+ var dict = {['a']: 222}
def GetDictVal(key: any)
- g:dict_val = s:dict[key]
+ g:dict_val = dict[key]
enddef
GetDictVal('a')
@@ -1879,13 +1880,13 @@ def Test_var_declaration_fails()
enddef
def Test_script_local_in_legacy()
- # OK to define script-local later when prefixed with s:
+ # OK to define script-local later but before compiling
var lines =<< trim END
def SetLater()
- s:legvar = 'two'
+ legvar = 'two'
enddef
- defcompile
let s:legvar = 'one'
+ defcompile
call SetLater()
call assert_equal('two', s:legvar)
END
@@ -1902,7 +1903,7 @@ def Test_script_local_in_legacy()
END
v9.CheckScriptSuccess(lines)
- # Not OK to leave out s: prefix when script-local defined later
+ # Not OK to leave out s: prefix when script-local defined after compiling
lines =<< trim END
def SetLaterNoPrefix()
legvar = 'two'
@@ -1944,15 +1945,15 @@ def Test_var_type_check()
lines =<< trim END
vim9script
- var s:l: list<number>
- s:l = []
+ var l: list<number>
+ l = []
END
v9.CheckScriptSuccess(lines)
lines =<< trim END
vim9script
- var s:d: dict<number>
- s:d = {}
+ var d: dict<number>
+ d = {}
END
v9.CheckScriptSuccess(lines)
@@ -2124,7 +2125,7 @@ def Test_unlet()
'vim9script',
'var svar = 123',
'unlet s:svar',
- ], 'E1081:')
+ ], 'E1268:')
v9.CheckScriptFailure([
'vim9script',
'var svar = 123',
@@ -2267,14 +2268,14 @@ def Test_script_funcref_case()
lines =<< trim END
vim9script
- var s:Len = (s: string): number => len(s) + 2
+ var Len = (s: string): number => len(s) + 2
assert_equal(6, Len('asdf'))
END
v9.CheckScriptSuccess(lines)
lines =<< trim END
vim9script
- var s:len = (s: string): number => len(s) + 1
+ var len = (s: string): number => len(s) + 1
END
v9.CheckScriptFailure(lines, 'E704:')
enddef
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index 3ad6e0e62..23b9c4936 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -2001,9 +2001,9 @@ def Test_insert()
v9.CheckDefExecAndScriptFailure(lines, 'E1131:', 1)
assert_equal([1, 2, 3], insert([2, 3], 1))
- assert_equal([1, 2, 3], insert([2, 3], s:number_one))
+ assert_equal([1, 2, 3], insert([2, 3], number_one))
assert_equal([1, 2, 3], insert([1, 2], 3, 2))
- assert_equal([1, 2, 3], insert([1, 2], 3, s:number_two))
+ assert_equal([1, 2, 3], insert([1, 2], 3, number_two))
assert_equal(['a', 'b', 'c'], insert(['b', 'c'], 'a'))
assert_equal(0z1234, insert(0z34, 0x12))
diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim
index a9309bea7..e7cdcc3f0 100644
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -1718,7 +1718,12 @@ def Test_var_not_cmd()
lines =<< trim END
s:notexist:repl
END
- v9.CheckDefAndScriptFailure(lines, ['E488: Trailing characters: :repl', 'E121: Undefined variable: s:notexist'], 1)
+ v9.CheckDefAndScriptFailure(lines, ['E488: Trailing characters: :repl', 'E1268:'], 1)
+
+ lines =<< trim END
+ notexist:repl
+ END
+ v9.CheckDefAndScriptFailure(lines, ['E476:', 'E492:'], 1)
lines =<< trim END
s-pat-repl
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index 1e61853e0..ec7183660 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -300,11 +300,11 @@ def Test_disassemble_push()
vim9script
import autoload 'autoscript.vim'
- def s:AutoloadFunc()
+ def AutoloadFunc()
&operatorfunc = autoscript.Opfunc
enddef
- var res = execute('disass s:AutoloadFunc')
+ var res = execute('disass AutoloadFunc')
assert_match('<SNR>\d*_AutoloadFunc.*' ..
'&operatorfunc = autoscript.Opfunc\_s*' ..
'0 AUTOLOAD autoscript#Opfunc\_s*' ..
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index 87b801446..8399b69fa 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -2329,7 +2329,7 @@ def Test_expr8_lambda_vim9script()
v9.CheckDefAndScriptSuccess(lines)
enddef
-def Test_expr8_funcref()
+def Test_expr8funcref()
var lines =<< trim END
def RetNumber(): number
return 123
@@ -2344,7 +2344,7 @@ def Test_expr8_funcref()
func g:GlobalFunc()
return 'global'
endfunc
- func s:ScriptFunc()
+ func ScriptFunc()
return 'script'
endfunc
def Test()
@@ -2353,7 +2353,7 @@ def Test_expr8_funcref()
Ref = g:GlobalFunc
assert_equal('global', Ref())
- Ref = s:ScriptFunc
+ Ref = ScriptFunc
assert_equal('script', Ref())
Ref = ScriptFunc
assert_equal('script', Ref())
@@ -3347,7 +3347,7 @@ func Test_expr8_fails()
call v9.CheckDefAndScriptFailure(["var x = &notexist"], 'E113:', 1)
call v9.CheckDefAndScriptFailure(["&grepprg = [343]"], ['E1012:', 'E730:'], 1)
- call v9.CheckDefExecAndScriptFailure(["echo s:doesnt_exist"], 'E121:', 1)
+ call v9.CheckDefExecAndScriptFailure(["echo s:doesnt_exist"], ['E121:', 'E1268:'], 1)
call v9.CheckDefExecAndScriptFailure(["echo g:doesnt_exist"], 'E121:', 1)
call v9.CheckDefAndScriptFailure(["echo a:somevar"], ['E1075:', 'E121:'], 1)
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index 46e562d1e..ecc9c64df 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -713,7 +713,7 @@ def Test_nested_function()
lines =<< trim END
vim9script
- def s:_Func()
+ def _Func()
echo 'bad'
enddef
END
@@ -930,7 +930,7 @@ def Test_global_local_function()
def g:Funcy()
echo 'funcy'
enddef
- s:Funcy()
+ Funcy()
END
v9.CheckScriptFailure(lines, 'E117:')
enddef
@@ -1441,10 +1441,10 @@ enddef
def Test_use_script_func_name_with_prefix()
var lines =<< trim END
vim9script
- func s:Getit()
+ func g:Getit()
return 'it'
endfunc
- var Fn = s:Getit
+ var Fn = g:Getit
assert_equal('it', Fn())
END
v9.CheckScriptSuccess(lines)
@@ -2849,7 +2849,7 @@ def Test_nested_inline_lambda()
lines =<< trim END
vim9script
- def s:Func()
+ def Func()
range(10)
->mapnew((_, _) => ({
key: range(10)->mapnew((_, _) => {
@@ -3168,7 +3168,7 @@ def Test_invalid_function_name()
vim9script
def s: list<string>
END
- v9.CheckScriptFailure(lines, 'E129:')
+ v9.CheckScriptFailure(lines, 'E1268:')
lines =<< trim END
vim9script
diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim
index 652e4d36b..45f64b2c4 100644
--- a/src/testdir/test_vim9_import.vim
+++ b/src/testdir/test_vim9_import.vim
@@ -1124,7 +1124,7 @@ def Test_vim9_reload_noclear()
lines =<< trim END
vim9script noclear
g:loadCount += 1
- var s:reloaded = 'init'
+ var reloaded = 'init'
import './XExportReload' as exp
def Again(): string
@@ -1133,13 +1133,13 @@ def Test_vim9_reload_noclear()
exp.TheFunc()
- if exists('s:loaded') | finish | endif
- var s:loaded = true
+ if exists('loaded') | finish | endif
+ var loaded = true
- var s:notReloaded = 'yes'
- s:reloaded = 'first'
+ var notReloaded = 'yes'
+ reloaded = 'first'
def g:Values(): list<string>
- return [s:reloaded, s:notReloaded, Again(), Once(), exp.exported]
+ return [reloaded, notReloaded, Again(), Once(), exp.exported]
enddef
def Once(): string
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 1b77f3962..eec19d94f 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -69,7 +69,10 @@ def Test_delfunction()
'func CheckMe()',
' return 123',
'endfunc',
- 'assert_equal(123, s:CheckMe())',
+ 'func DoTest()',
+ ' call assert_equal(123, s:CheckMe())',
+ 'endfunc',
+ 'DoTest()',
])
# Check function in script namespace cannot be deleted
@@ -178,11 +181,55 @@ def Test_wrong_type()
v9.CheckDefFailure(['var Ref: string', 'var res = Ref()'], 'E1085:')
enddef
+def Test_script_namespace()
+ # defining a function or variable with s: is not allowed
+ var lines =<< trim END
+ vim9script
+ def s:Function()
+ enddef
+ END
+ v9.CheckScriptFailure(lines, 'E1268:')
+
+ for decl in ['var', 'const', 'final']
+ lines =<< trim END
+ vim9script
+ var s:var = 'var'
+ END
+ v9.CheckScriptFailure([
+ 'vim9script',
+ decl .. ' s:var = "var"',
+ ], 'E1268:')
+ endfor
+
+ # Calling a function or using a variable with s: is not allowed at script
+ # level
+ lines =<< trim END
+ vim9script
+ def Function()
+ enddef
+ s:Function()
+ END
+ v9.CheckScriptFailure(lines, 'E1268:')
+ lines =<< trim END
+ vim9script
+ def Function()
+ enddef
+ call s:Function()
+ END
+ v9.CheckScriptFailure(lines, 'E1268:')
+ lines =<< trim END
+ vim9script
+ var var = 'var'
+ echo s:var
+ END
+ v9.CheckScriptFailure(lines, 'E1268:')
+enddef
+
def Test_script_wrong_type()
var lines =<< trim END
vim9script
- var s:dict: dict<string>
- s:dict['a'] = ['x']
+ var dict: dict<string>
+ dict['a'] = ['x']
END
v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got list<string>', 3)
enddef
diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim
index 92ea0bad7..bb50db08e 100644
--- a/src/testdir/vim9.vim
+++ b/src/testdir/vim9.vim
@@ -73,8 +73,8 @@ endfunc
export def CheckScriptFailure(lines: list<string>, error: string, lnum = -3)
var cwd = getcwd()
- var fname = 'XScriptFailure' .. s:sequence
- s:sequence += 1
+ var fname = 'XScriptFailure' .. sequence
+ sequence += 1
writefile(lines, fname)
try
assert_fails('so ' .. fname, error, lines, lnum)
@@ -86,8 +86,8 @@ enddef
export def CheckScriptFailureList(lines: list<string>, errors: list<string>, lnum = -3)
var cwd = getcwd()
- var fname = 'XScriptFailure' .. s:sequence
- s:sequence += 1
+ var fname = 'XScriptFailure' .. sequence
+ sequence += 1
writefile(lines, fname)
try
assert_fails('so ' .. fname, errors, lines, lnum)
@@ -99,8 +99,8 @@ enddef
export def CheckScriptSuccess(lines: list<string>)
var cwd = getcwd()
- var fname = 'XScriptSuccess' .. s:sequence
- s:sequence += 1
+ var fname = 'XScriptSuccess' .. sequence
+ sequence += 1
writefile(lines, fname)
try
exe 'so ' .. fname
diff --git a/src/userfunc.c b/src/userfunc.c
index 59415dbd7..4eead2a63 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -3010,6 +3010,18 @@ get_current_funccal(void)
}
/*
+ * Return TRUE when currently at the script level:
+ * - not in a function
+ * - not executing an autocommand
+ * Note that when an autocommand sources a script the result is FALSE;
+ */
+ int
+at_script_level(void)
+{
+ return current_funccal == NULL && autocmd_match == NULL;
+}
+
+/*
* Mark all functions of script "sid" as deleted.
*/
void
@@ -4205,6 +4217,12 @@ define_function(exarg_T *eap, char_u *name_arg, garray_T *lines_to_free)
}
else
{
+ if (vim9script && p[0] == 's' && p[1] == ':')
+ {
+ semsg(_(e_cannot_use_s_colon_in_vim9_script_str), p);
+ return NULL;
+ }
+
name = save_function_name(&p, &is_global, eap->skip,
TFN_NO_AUTOLOAD | TFN_NEW_FUNC, &fudi);
paren = (vim_strchr(p, '(') != NULL);
diff --git a/src/version.c b/src/version.c
index aaafadf89..1c59ff9cb 100644
--- 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 */
/**/
+ 4360,
+/**/
4359,
/**/
4358,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 265ea665b..3a70f7a0f 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1394,7 +1394,7 @@ compile_lhs(
if (is_decl)
{
if (script_namespace)
- semsg(_(e_cannot_declare_script_variable_in_function),
+ semsg(_(e_cannot_declare_script_variable_in_function_str),
lhs->lhs_name);
else
semsg(_(e_variable_already_declared_in_script_str),