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 <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/evalfunc.c b/src/evalfunc.c
index d81480b..ef30792 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -3739,7 +3739,6 @@
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 @@
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 52f9969..653b87c 100644
--- a/src/option.c
+++ b/src/option.c
@@ -8786,15 +8786,33 @@
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 992329b..99ac906 100644
--- a/src/testdir/test_user_func.vim
+++ b/src/testdir/test_user_func.vim
@@ -427,7 +427,7 @@
" 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 6103453..c82608b 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -540,7 +540,7 @@
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 2dc925a..b4e25c3 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -3611,4 +3611,26 @@
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 4188f82..38832e9 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
Binary files differ
diff --git a/src/userfunc.c b/src/userfunc.c
index b4ee0a2..06be445 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -2309,49 +2309,6 @@
}
/*
- * 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
* functions.
@@ -2400,15 +2357,8 @@
}
// 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 9dddabc..2cf4f46 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1013,
+/**/
1012,
/**/
1011,