summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-02-21 13:13:50 +0000
committerBram Moolenaar <Bram@vim.org>2022-02-21 13:13:50 +0000
commitc2f17f7e64bb1bf872dbc6f3b8f0d8751e275287 (patch)
tree229b6c9923d3eb383f9dbd254104a661c348b42d
parent0f6e28f686dbb59ab3b562408ab9b2234797b9b1 (diff)
downloadvim-git-c2f17f7e64bb1bf872dbc6f3b8f0d8751e275287.tar.gz
patch 8.2.4429: using script-local function from the wrong scriptv8.2.4429
Problem: Using script-local function from the wrong script when using a partial. (Yegappan Lakshmanan) Solution: Include the script ID in the partial name.
-rw-r--r--src/evalfunc.c4
-rw-r--r--src/proto/userfunc.pro1
-rw-r--r--src/testdir/test_vim9_import.vim40
-rw-r--r--src/userfunc.c39
-rw-r--r--src/version.c2
-rw-r--r--src/vim9type.c2
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<any>): string
+ return 'found it'
+ enddef
+
+ export def NewLspServer(): dict<any>
+ var d: dict<any> = {}
+ 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<any> = 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, "<SNR>", 5) == 0)
+ {
+ char_u *p = name + 5;
+ long sid;
+
+ // printable "<SNR>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 *funcname)
}
/*
+ * Return script-local "fname" with the 3-byte sequence replaced by
+ * printable <SNR> 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, "<SNR>");
+ 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
@@ -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
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
{