To: vim_dev@googlegroups.com Subject: Patch 8.2.4447 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4447 Problem: Vim9: can still use s:var in a compiled function. Solution: Disallow using s:var for Vim9 script. (closes #9824) Files: runtime/doc/vim9.txt, src/vim9expr.c, src/vim9compile.c, src/testdir/test_vim9_assign.vim *** ../vim-8.2.4446/runtime/doc/vim9.txt 2022-02-11 20:33:11.942342190 +0000 --- runtime/doc/vim9.txt 2022-02-22 20:32:22.624277283 +0000 *************** *** 217,250 **** Functions and variables are script-local by default ~ *vim9-scopes* When using `:function` or `:def` to specify a new function at the script level ! in a Vim9 script, the function is local to the script, as if "s:" was ! prefixed. Using the "s:" prefix is optional. To define a global function or ! variable the "g:" prefix must be used. For functions in an autoload script ! the "name#" prefix is sufficient. > def ThisFunction() # script-local - def s:ThisFunction() # script-local def g:ThatFunction() # global ! def scriptname#function() # autoload ! When using `:function` or `:def` to specify a nested function inside a `:def` function and no namespace was given, this nested function is local to the code ! block it is defined in. In a `:def` function it is not possible to define a ! script-local function. It is possible to define a global function by using ! the "g:" prefix. When referring to a function and no "s:" or "g:" prefix is used, Vim will search for the function: - in the function scope, in block scopes - in the script scope, possibly imported - - in the list of global functions - However, it is recommended to always use "g:" to refer to a global function - for clarity. Since a script-local function reference can be used without "s:" the name must start with an upper case letter even when using the "s:" prefix. In legacy script "s:funcref" could be used, because it could not be referred to with "funcref". In Vim9 script it can, therefore "s:Funcref" must be used to avoid that the name interferes with builtin functions. In all cases the function must be defined before used. That is when it is called, when `:defcompile` causes it to be compiled, or when code that calls --- 219,256 ---- Functions and variables are script-local by default ~ *vim9-scopes* When using `:function` or `:def` to specify a new function at the script level ! in a Vim9 script, the function is local to the script. Like prefixing "s:" in ! legacy script. To define a global function or variable the "g:" prefix must ! be used. For functions in a script that is to be imported and in an autoload ! script "export" needs to be used. > def ThisFunction() # script-local def g:ThatFunction() # global ! export def Function() # for import and import autoload ! < *E1058* *E1075* When using `:function` or `:def` to specify a nested function inside a `:def` function and no namespace was given, this nested function is local to the code ! block it is defined in. It is not possible to define a script-local function. ! It is possible to define a global function by using the "g:" prefix. When referring to a function and no "s:" or "g:" prefix is used, Vim will search for the function: - in the function scope, in block scopes - in the script scope, possibly imported Since a script-local function reference can be used without "s:" the name must start with an upper case letter even when using the "s:" prefix. In legacy script "s:funcref" could be used, because it could not be referred to with "funcref". In Vim9 script it can, therefore "s:Funcref" must be used to avoid that the name interferes with builtin functions. + *vim9-s-namespace* + The use of the "s:" prefix is not supported at the Vim9 script level. All + functions and variables without a prefix are script-local. + + In :def functions the use of "s:" depends on the script: Script-local + variables and functions in a legacy script do use "s:", while in a Vim9 script + they do not use "s:". This matches what you see in the rest of the file. + + In legacy functions the use of "s:" for script items is required, as before. In all cases the function must be defined before used. That is when it is called, when `:defcompile` causes it to be compiled, or when code that calls *** ../vim-8.2.4446/src/vim9expr.c 2022-02-13 21:51:02.392484124 +0000 --- src/vim9expr.c 2022-02-22 20:09:10.571464839 +0000 *************** *** 422,429 **** { case 'v': res = generate_LOADV(cctx, name, error); break; ! case 's': if (is_expr && ASCII_ISUPPER(*name) ! && find_func(name, FALSE) != NULL) res = generate_funcref(cctx, name, FALSE); else res = compile_load_scriptvar(cctx, name, --- 422,436 ---- { case 'v': res = generate_LOADV(cctx, name, error); break; ! case 's': if (current_script_is_vim9()) ! { ! semsg(_(e_cannot_use_s_colon_in_vim9_script_str), ! *arg); ! vim_free(name); ! return FAIL; ! } ! if (is_expr && ASCII_ISUPPER(*name) ! && find_func(name, FALSE) != NULL) res = generate_funcref(cctx, name, FALSE); else res = compile_load_scriptvar(cctx, name, *** ../vim-8.2.4446/src/vim9compile.c 2022-02-20 18:26:43.107537899 +0000 --- src/vim9compile.c 2022-02-22 20:24:39.813438043 +0000 *************** *** 1331,1336 **** --- 1331,1342 ---- char_u *rawname = lhs->lhs_name + (lhs->lhs_name[1] == ':' ? 2 : 0); + if (script_namespace && current_script_is_vim9()) + { + semsg(_(e_cannot_use_s_colon_in_vim9_script_str), + var_start); + return FAIL; + } if (is_decl) { if (script_namespace) *** ../vim-8.2.4446/src/testdir/test_vim9_assign.vim 2022-02-17 19:44:04.271319375 +0000 --- src/testdir/test_vim9_assign.vim 2022-02-22 20:25:55.053227080 +0000 *************** *** 220,226 **** enddef defcompile END ! v9.CheckScriptFailure(lines, 'E1089:') g:inc_counter += 1 assert_equal(2, g:inc_counter) --- 220,226 ---- enddef defcompile END ! v9.CheckScriptFailure(lines, 'E1268:') g:inc_counter += 1 assert_equal(2, g:inc_counter) *************** *** 2460,2465 **** --- 2460,2508 ---- g:StopVimInTerminal(buf) enddef + def Test_using_s_var_in_function() + var lines =<< trim END + vim9script + var scriptlevel = 123 + def SomeFunc() + echo s:scriptlevel + enddef + SomeFunc() + END + v9.CheckScriptFailure(lines, 'E1268:') + + # OK in legacy script + lines =<< trim END + let s:scriptlevel = 123 + def s:SomeFunc() + echo s:scriptlevel + enddef + call s:SomeFunc() + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var scriptlevel = 123 + def SomeFunc() + s:scriptlevel = 456 + enddef + SomeFunc() + END + v9.CheckScriptFailure(lines, 'E1268:') + + # OK in legacy script + lines =<< trim END + let s:scriptlevel = 123 + def s:SomeFunc() + s:scriptlevel = 456 + enddef + call s:SomeFunc() + call assert_equal(456, s:scriptlevel) + END + v9.CheckScriptSuccess(lines) + enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker *** ../vim-8.2.4446/src/version.c 2022-02-22 19:39:07.590366896 +0000 --- src/version.c 2022-02-22 20:02:33.812043828 +0000 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 4447, /**/ -- % cat /usr/include/long_life.h long life(double fun); /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///