]> granicus.if.org Git - vim/commitdiff
patch 8.2.4429: using script-local function from the wrong script v8.2.4429
authorBram Moolenaar <Bram@vim.org>
Mon, 21 Feb 2022 13:13:50 +0000 (13:13 +0000)
committerBram Moolenaar <Bram@vim.org>
Mon, 21 Feb 2022 13:13:50 +0000 (13:13 +0000)
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
src/proto/userfunc.pro
src/testdir/test_vim9_import.vim
src/userfunc.c
src/version.c
src/vim9type.c

index ce51fc017d5dbce4e252b2f92954b5c5d72d9ad7..cb038e4c8dadb146f68fe8f8baa934ce540c0e17 100644 (file)
@@ -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);
 
index b8d14437dec721876efd2a4bdbc90003b606daec..ad578550146d9b79a1aa8c3068b78b3412c1c0d4 100644 (file)
@@ -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);
index 90e81c1eb441b6f6c27be48c16308b3c4d46bb3f..c9ae612ca0f443751c28280934a1de9f071d6e72 100644 (file)
@@ -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
index 3e0d021ba8933022e37ff521eaf0fb9b70666ca2..3a66d273248dd671b29a66bc9f636f6058e419e4 100644 (file)
@@ -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)
@@ -4067,6 +4079,23 @@ get_scriptlocal_funcname(char_u *funcname)
     return newname;
 }
 
+/*
+ * 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.
index 777476d80dce52cc94b66ea01cfe4a6be81edd6f..2a8afcec9d2d23021bca83be7e72cbd9aa7f169e 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4429,
 /**/
     4428,
 /**/
index 62be6ac619d984121fa36de556451839779e6ee2..dcfc998c5701e4071fdc3673b77f11b0700d6f8a 100644 (file)
@@ -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
                        {