From c2f17f7e64bb1bf872dbc6f3b8f0d8751e275287 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 21 Feb 2022 13:13:50 +0000 Subject: [PATCH] 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. --- src/evalfunc.c | 4 +++- src/proto/userfunc.pro | 1 + src/testdir/test_vim9_import.vim | 40 ++++++++++++++++++++++++++++++++ src/userfunc.c | 39 +++++++++++++++++++++++++++---- src/version.c | 2 ++ src/vim9type.c | 2 +- 6 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index ce51fc017..cb038e4c8 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -570,7 +570,7 @@ arg_map_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context) || 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, typval_T *rettv, int is_funcref) // 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 index b8d14437d..ad5785501 100644 --- 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 index 90e81c1eb..c9ae612ca 100644 --- 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 index 3e0d021ba..3a66d2732 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1958,17 +1958,29 @@ find_func_even_dead(char_u *name, int flags) 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) @@ -4067,6 +4079,23 @@ get_scriptlocal_funcname(char_u *funcname) return newname; } +/* + * 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 index 777476d80..2a8afcec9 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 4429, /**/ 4428, /**/ diff --git a/src/vim9type.c b/src/vim9type.c index 62be6ac61..dcfc998c5 100644 --- a/src/vim9type.c +++ b/src/vim9type.c @@ -457,7 +457,7 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags) { 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 { -- 2.40.0