mirror of
https://github.com/vim/vim.git
synced 2025-09-07 22:03:36 -04:00
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>
This commit is contained in:
parent
30377e0fe0
commit
6289f91591
@ -3739,7 +3739,6 @@ f_call(typval_T *argvars, typval_T *rettv)
|
|||||||
char_u *func;
|
char_u *func;
|
||||||
partial_T *partial = NULL;
|
partial_T *partial = NULL;
|
||||||
dict_T *selfdict = NULL;
|
dict_T *selfdict = NULL;
|
||||||
char_u *dot;
|
|
||||||
char_u *tofree = NULL;
|
char_u *tofree = NULL;
|
||||||
|
|
||||||
if (in_vim9script()
|
if (in_vim9script()
|
||||||
@ -3765,36 +3764,26 @@ f_call(typval_T *argvars, typval_T *rettv)
|
|||||||
if (func == NULL || *func == NUL)
|
if (func == NULL || *func == NUL)
|
||||||
return; // type error, empty name or null function
|
return; // type error, empty name or null function
|
||||||
|
|
||||||
dot = vim_strchr(func, '.');
|
char_u *p = func;
|
||||||
if (dot != NULL)
|
tofree = trans_function_name(&p, NULL, FALSE, TFN_INT|TFN_QUIET);
|
||||||
{
|
|
||||||
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)
|
if (tofree == NULL)
|
||||||
|
{
|
||||||
|
emsg_funcname(e_unknown_function_str, func);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
func = tofree;
|
func = tofree;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argvars[2].v_type != VAR_UNKNOWN)
|
if (argvars[2].v_type != VAR_UNKNOWN)
|
||||||
{
|
{
|
||||||
if (check_for_dict_arg(argvars, 2) == FAIL)
|
if (check_for_dict_arg(argvars, 2) == FAIL)
|
||||||
return;
|
goto done;
|
||||||
|
|
||||||
selfdict = argvars[2].vval.v_dict;
|
selfdict = argvars[2].vval.v_dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)func_call(func, &argvars[1], partial, selfdict, rettv);
|
(void)func_call(func, &argvars[1], partial, selfdict, rettv);
|
||||||
|
|
||||||
|
done:
|
||||||
vim_free(tofree);
|
vim_free(tofree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
src/option.c
26
src/option.c
@ -8786,16 +8786,34 @@ option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED)
|
|||||||
vim_free(cb.cb_name);
|
vim_free(cb.cb_name);
|
||||||
free_tv(tv);
|
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)
|
if (optcb->cb_free_name)
|
||||||
vim_free(optcb->cb_name);
|
vim_free(optcb->cb_name);
|
||||||
|
|
||||||
|
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_name = vim_strsave(optval);
|
||||||
optcb->cb_free_name = TRUE;
|
optcb->cb_free_name = TRUE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// when using Vim9 style "import.funcname" it needs to be expanded to
|
// when using Vim9 style "import.funcname" it needs to be expanded to
|
||||||
// "import#funcname".
|
// "import#funcname".
|
||||||
expand_autload_callback(optcb);
|
expand_autload_callback(optcb);
|
||||||
|
@ -427,7 +427,7 @@ func Test_script_local_func()
|
|||||||
" Try to call a script local function in global scope
|
" Try to call a script local function in global scope
|
||||||
let lines =<< trim [CODE]
|
let lines =<< trim [CODE]
|
||||||
:call assert_fails('call s:Xfunc()', 'E81:')
|
: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')
|
:call writefile(v:errors, 'Xresult')
|
||||||
:qall
|
:qall
|
||||||
|
|
||||||
|
@ -540,7 +540,7 @@ def Test_call_imports()
|
|||||||
const Imported = i_imp.Imported
|
const Imported = i_imp.Imported
|
||||||
const foo = i_imp.foo
|
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("foo", [])', 'E117:') # foo is not a function
|
||||||
assert_fails('call("i_xxx.foo", [])', 'E117:') # i_xxx not imported file
|
assert_fails('call("i_xxx.foo", [])', 'E117:') # i_xxx not imported file
|
||||||
END
|
END
|
||||||
|
@ -3611,4 +3611,26 @@ def Test_disassemble_interface_variable_access()
|
|||||||
unlet g:instr
|
unlet g:instr
|
||||||
enddef
|
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
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@ -4714,6 +4714,47 @@ def Test_comment_after_inner_block()
|
|||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
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.
|
" The following messes up syntax highlight, keep near the end.
|
||||||
if has('python3')
|
if has('python3')
|
||||||
def Test_python3_command()
|
def Test_python3_command()
|
||||||
|
@ -2308,49 +2308,6 @@ find_func_with_prefix(char_u *name, int sid)
|
|||||||
return NULL;
|
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.
|
* Find a function by name, return pointer to it in ufuncs.
|
||||||
* When "flags" has FFED_IS_GLOBAL don't find script-local or imported
|
* 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.
|
// 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);
|
? 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1013,
|
||||||
/**/
|
/**/
|
||||||
1012,
|
1012,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user