patch 9.1.1013: Vim9: Regression caused by patch v9.1.0646 Commit: https://github.com/vim/vim/commit/6289f9159102e0855bedc566636b5e7ca6ced72c Author: Yegappan Lakshmanan <yegap...@yahoo.com> Date: Tue Jan 14 17:13:36 2025 +0100
patch 9.1.1013: Vim9: Regression caused by patch v9.1.0646 Problem: Vim9: Regression caused by patch v9.1.0646 Solution: Translate the function name before invoking it in call() (Yegappan Lakshmanan) fixes: #16430 closes: #16445 Signed-off-by: Yegappan Lakshmanan <yegap...@yahoo.com> Signed-off-by: Christian Brabandt <c...@256bit.org> diff --git a/src/evalfunc.c b/src/evalfunc.c index d81480b50..ef30792ad 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -3739,7 +3739,6 @@ f_call(typval_T *argvars, typval_T *rettv) char_u *func; partial_T *partial = NULL; dict_T *selfdict = NULL; - char_u *dot; char_u *tofree = NULL; if (in_vim9script() @@ -3765,36 +3764,26 @@ f_call(typval_T *argvars, typval_T *rettv) if (func == NULL || *func == NUL) return; // type error, empty name or null function - dot = vim_strchr(func, '.'); - if (dot != NULL) + char_u *p = func; + tofree = trans_function_name(&p, NULL, FALSE, TFN_INT|TFN_QUIET); + if (tofree == NULL) { - imported_T *import = find_imported(func, dot - func, TRUE); - - if (import != NULL && SCRIPT_ID_VALID(import->imp_sid)) - { - scriptitem_T *si = SCRIPT_ITEM(import->imp_sid); - - if (si->sn_autoload_prefix != NULL) - { - // Turn "import.Func" into "scriptname#Func". - tofree = concat_str(si->sn_autoload_prefix, dot + 1); - if (tofree == NULL) - return; - func = tofree; - } - } + emsg_funcname(e_unknown_function_str, func); + return; } + func = tofree; if (argvars[2].v_type != VAR_UNKNOWN) { if (check_for_dict_arg(argvars, 2) == FAIL) - return; + goto done; selfdict = argvars[2].vval.v_dict; } (void)func_call(func, &argvars[1], partial, selfdict, rettv); +done: vim_free(tofree); } diff --git a/src/option.c b/src/option.c index 52f996975..653b87cae 100644 --- a/src/option.c +++ b/src/option.c @@ -8786,15 +8786,33 @@ option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED) vim_free(cb.cb_name); free_tv(tv); - if (in_vim9script() && funcname && (vim_strchr(optval, '.') != NULL)) + char_u *dot = NULL; + if (in_vim9script() && funcname + && ((dot = vim_strchr(optval, '.')) != NULL)) { - // When a Vim9 imported function name is used, it is expanded by the - // call to get_callback() above to <SNR>_funcname. Revert the name to - // back to "import.funcname". if (optcb->cb_free_name) vim_free(optcb->cb_name); - optcb->cb_name = vim_strsave(optval); - optcb->cb_free_name = TRUE; + + imported_T *import = find_imported(optval, dot - optval, FALSE); + if (import != NULL && SCRIPT_ID_VALID(import->imp_sid) + && !(import->imp_flags & IMP_FLAGS_AUTOLOAD)) + { + char_u fnamebuf[MAX_FUNC_NAME_LEN]; + + // Imported non-autoloaded function. Replace the import script + // name (import.funcname) with the script ID (<SNR>123_funcname) + vim_snprintf((char *)fnamebuf, sizeof(fnamebuf), "<SNR>%d_%s", + import->imp_sid, dot + 1); + optcb->cb_name = vim_strsave(fnamebuf); + optcb->cb_free_name = TRUE; + } + else + { + // Imported autoloaded function. Store the function name as + // "import.funcname". + optcb->cb_name = vim_strsave(optval); + optcb->cb_free_name = TRUE; + } } // when using Vim9 style "import.funcname" it needs to be expanded to // "import#funcname". diff --git a/src/testdir/test_user_func.vim b/src/testdir/test_user_func.vim index 992329bc7..99ac90662 100644 --- a/src/testdir/test_user_func.vim +++ b/src/testdir/test_user_func.vim @@ -427,7 +427,7 @@ func Test_script_local_func() " Try to call a script local function in global scope let lines =<< trim [CODE] :call assert_fails('call s:Xfunc()', 'E81:') - :call assert_fails('let x = call("<SID>Xfunc", [])', 'E120:') + :call assert_fails('let x = call("<SID>Xfunc", [])', ['E81:', 'E117:']) :call writefile(v:errors, 'Xresult') :qall diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 6103453a2..c82608b46 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -540,7 +540,7 @@ def Test_call_imports() const Imported = i_imp.Imported const foo = i_imp.foo - assert_fails('call("i_imp.foo", [])', 'E117:') # foo is not a function + assert_fails('call("i_imp.foo", [])', ['E46:', 'E117:']) # foo is not a function assert_fails('call("foo", [])', 'E117:') # foo is not a function assert_fails('call("i_xxx.foo", [])', 'E117:') # i_xxx not imported file END diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 2dc925a35..b4e25c39a 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -3611,4 +3611,26 @@ def Test_disassemble_interface_variable_access() unlet g:instr enddef +" Disassemble the code generated for accessing a script-local funcref +def Test_disassemble_using_script_local_funcref() + var lines =<< trim END + vim9script + def Noop() + enddef + export var Setup = Noop + export def Run() + Setup() + enddef + g:instr = execute('disassemble Run') + END + v9.CheckScriptSuccess(lines) + assert_match('<SNR>\d\+_Run\_s*' .. + 'Setup()\_s*' .. + '0 LOADSCRIPT Setup-0 from .*\_s*' .. + '1 PCALL (argc 0)\_s*' .. + '2 DROP\_s*' .. + '3 RETURN void\_s*', g:instr) + unlet g:instr +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 4188f82e5..38832e99d 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -4714,6 +4714,47 @@ def Test_comment_after_inner_block() v9.CheckScriptSuccess(lines) enddef +" Test for calling an imported funcref which is modified in the current script +def Test_call_modified_import_func() + var lines =<< trim END + vim9script + + export var done = 0 + + def Noop() + enddef + + export var Setup = Noop + + export def Run() + done = 0 + Setup() + done += 1 + enddef + END + writefile(lines, 'XcallModifiedImportFunc.vim', 'D') + + lines =<< trim END + vim9script + + import './XcallModifiedImportFunc.vim' as imp + + var setup = 0 + + imp.Run() + + imp.Setup = () => { + ++setup + } + + imp.Run() + + assert_equal(1, setup) + assert_equal(1, imp.done) + END + v9.CheckScriptSuccess(lines) +enddef + " The following messes up syntax highlight, keep near the end. if has('python3') def Test_python3_command() diff --git a/src/userfunc.c b/src/userfunc.c index b4ee0a267..06be445af 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -2308,49 +2308,6 @@ find_func_with_prefix(char_u *name, int sid) return NULL; } -/* - * Find a function by name, return pointer to it. - * The name may be a local script variable, VAR_FUNC. or it may be a fully - * qualified import name such as 'i_imp.FuncName'. - * - * When VAR_FUNC, the import might either direct or autoload. - * When 'i_imp.FuncName' it is direct, autoload is rewritten as i_imp#FuncName - * in f_call and subsequently found. - */ - static ufunc_T * -find_func_imported(char_u *name, int flags) -{ - ufunc_T *func = NULL; - char_u *dot = name; // Find a dot, '.', in the name - - // Either run into '.' or the end of the string - while (eval_isnamec(*dot)) - ++dot; - - if (*dot == '.') - { - imported_T *import = find_imported(name, dot - name, FALSE); - if (import != NULL) - func = find_func_with_sid(dot + 1, import->imp_sid); - } - else if (*dot == NUL) // looking at the entire string - { - hashtab_T *ht = get_script_local_ht(); - if (ht != NULL) - { - hashitem_T *hi = hash_find(ht, name); - if (!HASHITEM_EMPTY(hi)) - { - dictitem_T *di = HI2DI(hi); - if (di->di_tv.v_type == VAR_FUNC - && di->di_tv.vval.v_string != NULL) - func = find_func_even_dead(di->di_tv.vval.v_string, flags); - } - } - } - return func; -} - /* * Find a function by name, return pointer to it in ufuncs. * When "flags" has FFED_IS_GLOBAL don't find script-local or imported @@ -2400,15 +2357,8 @@ find_func_even_dead(char_u *name, int flags) } // Find autoload function if this is an autoload script. - func = find_func_with_prefix(name[0] == 's' && name[1] == ':' + return find_func_with_prefix(name[0] == 's' && name[1] == ':' ? name + 2 : name, current_sctx.sc_sid); - if (func != NULL) - return func; - - // Find a script-local "VAR_FUNC" or i_"imp.Func", so vim9script). - if (in_vim9script()) - func = find_func_imported(name, flags); - return func; } /* diff --git a/src/version.c b/src/version.c index 9dddabc05..2cf4f4697 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1013, /**/ 1012, /**/ -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1tXjns-00Bqjl-OC%40256bit.org.