# HG changeset patch # User Bram Moolenaar # Date 1645449304 -3600 # Node ID 292a6bd86c30132a22be9c9d7a6dd5aeec9f803e # Parent c8db1c5f9303f423f74359120d5d812d9c50c643 patch 8.2.4429: using script-local function from the wrong script Commit: https://github.com/vim/vim/commit/c2f17f7e64bb1bf872dbc6f3b8f0d8751e275287 Author: Bram Moolenaar Date: Mon Feb 21 13:13:50 2022 +0000 patch 8.2.4429: using script-local function from the wrong script Problem: Using script-local function from the wrong script when using a partial. (Yegappan Lakshmanan) Solution: Include the script ID in the partial name. diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -570,7 +570,7 @@ arg_map_func(type_T *type, type_T *decl_ || context->arg_types[0].type_curr->tt_type == VAR_BLOB || context->arg_types[0].type_curr->tt_type == VAR_LIST) args[0] = &t_number; - else if (context->arg_types[0].type_curr->tt_type == VAR_DICT) + else if (context->arg_types[0].type_decl->tt_type == VAR_DICT) args[0] = &t_string; if (args[0] != NULL) args[1] = expected_ret; @@ -4366,6 +4366,8 @@ common_function(typval_T *argvars, typva // would also work, but some plugins depend on the name being // printable text. name = get_scriptlocal_funcname(s); + else if (trans_name != NULL && *trans_name == K_SPECIAL) + name = alloc_printable_func_name(trans_name); else name = vim_strsave(s); diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -38,6 +38,7 @@ char_u *printable_func_name(ufunc_T *fp) char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial, type_T **type); char_u *untrans_function_name(char_u *name); char_u *get_scriptlocal_funcname(char_u *funcname); +char_u *alloc_printable_func_name(char_u *fname); char_u *save_function_name(char_u **name, int *is_global, int skip, int flags, funcdict_T *fudi); void list_functions(regmatch_T *regmatch); ufunc_T *define_function(exarg_T *eap, char_u *name_arg, garray_T *lines_to_free); diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim --- a/src/testdir/test_vim9_import.vim +++ b/src/testdir/test_vim9_import.vim @@ -423,6 +423,46 @@ def Test_import_funcref() delete('Xlib.vim') enddef +def Test_import_duplicate_function() + # Function Hover() exists in both scripts, partial should refer to the right + # one. + var lines =<< trim END + vim9script + + def Hover(d: dict): string + return 'found it' + enddef + + export def NewLspServer(): dict + var d: dict = {} + d->extend({hover: function('Hover', [d])}) + return d + enddef + + NewLspServer() + END + writefile(lines, 'Xserver.vim') + + lines =<< trim END + vim9script + + import './Xserver.vim' as server + + export def Hover() + enddef + + def AddServer() + var d: dict = server.NewLspServer() + assert_equal('found it', d.hover()) + enddef + AddServer() + END + v9.CheckScriptSuccess(lines) + + delete('Xserver.vim') +enddef + + def Test_import_fails() writefile([], 'Xfoo.vim') var lines =<< trim END diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1958,17 +1958,29 @@ find_func_even_dead(char_u *name, int fl if ((flags & FFED_IS_GLOBAL) == 0) { - int find_script_local = in_vim9script() && eval_isnamec1(*name) - && (name[1] != ':' || *name == 's'); - - if (find_script_local) + // Find script-local function before global one. + if (in_vim9script() && eval_isnamec1(*name) + && (name[1] != ':' || *name == 's')) { - // Find script-local function before global one. func = find_func_with_sid(name[0] == 's' && name[1] == ':' ? name + 2 : name, current_sctx.sc_sid); if (func != NULL) return func; } + if (in_vim9script() && STRNCMP(name, "", 5) == 0) + { + char_u *p = name + 5; + long sid; + + // printable "123_Name" form + sid = getdigits(&p); + if (*p == '_') + { + func = find_func_with_sid(p + 1, (int)sid); + if (func != NULL) + return func; + } + } } if ((flags & FFED_NO_GLOBAL) == 0) @@ -4068,6 +4080,23 @@ get_scriptlocal_funcname(char_u *funcnam } /* + * Return script-local "fname" with the 3-byte sequence replaced by + * printable in allocated memory. + */ + char_u * +alloc_printable_func_name(char_u *fname) +{ + char_u *n = alloc(STRLEN(fname + 3) + 6); + + if (n != NULL) + { + STRCPY(n, ""); + STRCPY(n + 5, fname + 3); + } + return n; +} + +/* * Call trans_function_name(), except that a lambda is returned as-is. * Returns the name in allocated memory. */ diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4429, +/**/ 4428, /**/ 4427, diff --git a/src/vim9type.c b/src/vim9type.c --- a/src/vim9type.c +++ b/src/vim9type.c @@ -457,7 +457,7 @@ typval2type_int(typval_T *tv, int copyID { type->tt_argcount -= tv->vval.v_partial->pt_argc; type->tt_min_argcount -= tv->vval.v_partial->pt_argc; - if (type->tt_argcount == 0) + if (type->tt_argcount <= 0) type->tt_args = NULL; else {