]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.4360: Vim9: allowing use of "s:" leads to inconsistencies v8.2.4360
authorBram Moolenaar <Bram@vim.org>
Sat, 12 Feb 2022 19:52:25 +0000 (19:52 +0000)
committerBram Moolenaar <Bram@vim.org>
Sat, 12 Feb 2022 19:52:25 +0000 (19:52 +0000)
Problem:    Vim9: allowing use of "s:" leads to inconsistencies.
Solution:   Disallow using "s:" in Vim9 script at the script level.

15 files changed:
src/errors.h
src/eval.c
src/proto/userfunc.pro
src/testdir/test_vim9_assign.vim
src/testdir/test_vim9_builtin.vim
src/testdir/test_vim9_cmd.vim
src/testdir/test_vim9_disassemble.vim
src/testdir/test_vim9_expr.vim
src/testdir/test_vim9_func.vim
src/testdir/test_vim9_import.vim
src/testdir/test_vim9_script.vim
src/testdir/vim9.vim
src/userfunc.c
src/version.c
src/vim9compile.c

index c66d26d8d99ce5f9653407d38ecd8af4c29fdeea..ef9e0834617fd1083fb7f9dad5da89058a4bcae4 100644 (file)
@@ -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
index 81a1dd0a97b449758a3574ffecc35c1d84fde15f..261a397aa94bfe33524a8302f15b9fb341db2be0 100644 (file)
@@ -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!
index 4e30d83c4c555b004d6bc9f61c2cd919540dc918..b8d14437dec721876efd2a4bdbc90003b606daec 100644 (file)
@@ -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);
index 7d3e2c13562af29457c930783376422ffde0b139..d9b8f3a24b35f9db5774fc131a2091f67bc9b54e 100644 (file)
@@ -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
index 3ad6e0e62d89fe9b026b03f0402616cddd67e724..23b9c4936b53dea2a16a7f3db6320d1b94dd87fd 100644 (file)
@@ -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))
 
index a9309bea7f162423befa275fc89bac14daf50c23..e7cdcc3f09c5079ba56797117258873ce47b2538 100644 (file)
@@ -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
index 1e61853e086772617b366ee3edcc4c5bec6f25ce..ec71836606ea7313470b42ebb647dae9ed8c347c 100644 (file)
@@ -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*' ..
index 87b801446ab06214eb25b4f4efa52c0287cc9c31..8399b69fa87ab580432e11b596ed5ec0dde91fec 100644 (file)
@@ -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)
index 46e562d1ed42920cc0ac948a3e399c90b741caf8..ecc9c64df5254003845da10a6832b560b9e715bb 100644 (file)
@@ -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
index 652e4d36b633b55f8e1009ad90365d89e88a6b3e..45f64b2c400faaceab5d67e129b296a69f27116d 100644 (file)
@@ -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
index 1b77f3962332ffe797e5e43a6266dbb1daca8511..eec19d94fbb22736fd524141e427c0bc55a35523 100644 (file)
@@ -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
index 92ea0bad73d9c8a6c8d1e0f4324abc0dce6d7302..bb50db08e93d3238747eadf08b6ff3b86f119086 100644 (file)
@@ -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
index 59415dbd731ebda2cc1cf2b0fd8a61693c56c510..4eead2a630b2aef679ab47b90412ca50c3385aa4 100644 (file)
@@ -3009,6 +3009,18 @@ get_current_funccal(void)
     return current_funccal;
 }
 
+/*
+ * 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.
  */
@@ -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);
index aaafadf89de709ef80da6aa11646434b1b7c94a1..1c59ff9cb5a0a86e642d750f2cc91763fce1a4e9 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4360,
 /**/
     4359,
 /**/
index 265ea665b8c24cab1a0873108267eaf6687babb1..3a70f7a0ffe28e436bcdc9225028e6792573bca5 100644 (file)
@@ -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),