]> granicus.if.org Git - vim/commitdiff
patch 8.2.0650: Vim9: script function can be deleted v8.2.0650
authorBram Moolenaar <Bram@vim.org>
Mon, 27 Apr 2020 20:47:51 +0000 (22:47 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 27 Apr 2020 20:47:51 +0000 (22:47 +0200)
Problem:    Vim9: script function can be deleted.
Solution:   Disallow deleting script function.  Delete functions when sourcing
            a script again.

12 files changed:
src/evalfunc.c
src/proto/userfunc.pro
src/scriptfile.c
src/testdir/test_vim9_expr.vim
src/testdir/test_vim9_func.vim
src/testdir/test_vim9_script.vim
src/testing.c
src/userfunc.c
src/version.c
src/vim9compile.c
src/vim9execute.c
src/vim9script.c

index 8cd137a4dd6b9f5901c8e09a6821e66ef954ca3c..02943c717a87b3a44d5b295e1ce239d77e56af37 100644 (file)
@@ -2679,6 +2679,7 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
     int                use_string = FALSE;
     partial_T   *arg_pt = NULL;
     char_u     *trans_name = NULL;
+    int                is_global = FALSE;
 
     if (argvars[0].v_type == VAR_FUNC)
     {
@@ -2702,21 +2703,10 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
     if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
     {
        name = s;
-       trans_name = trans_function_name(&name, FALSE,
+       trans_name = trans_function_name(&name, &is_global, FALSE,
             TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
        if (*name != NUL)
            s = NULL;
-       else if (trans_name != NULL
-               && ASCII_ISUPPER(*s)
-               && current_sctx.sc_version == SCRIPT_VERSION_VIM9
-               && find_func(trans_name, NULL) == NULL)
-       {
-           // With Vim9 script "MyFunc" can be script-local to the current
-           // script or global.  The script-local name is not found, assume
-           // global.
-           vim_free(trans_name);
-           trans_name = vim_strsave(s);
-       }
     }
 
     if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
@@ -2724,8 +2714,8 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
        semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
     // Don't check an autoload name for existence here.
     else if (trans_name != NULL && (is_funcref
-                               ? find_func(trans_name, NULL) == NULL
-                               : !translated_function_exists(trans_name)))
+                        ? find_func(trans_name, is_global, NULL) == NULL
+                        : !translated_function_exists(trans_name, is_global)))
        semsg(_("E700: Unknown function: %s"), s);
     else
     {
@@ -2862,7 +2852,7 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
                }
                else if (is_funcref)
                {
-                   pt->pt_func = find_func(trans_name, NULL);
+                   pt->pt_func = find_func(trans_name, is_global, NULL);
                    func_ptr_ref(pt->pt_func);
                    vim_free(name);
                }
index 19097fe2ecfacbd9109be065bd9f4934936bc3c1..81d69386f08bbb81cd9e3cce8daa944da9c494d1 100644 (file)
@@ -7,11 +7,12 @@ char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_au
 void emsg_funcname(char *ermsg, char_u *name);
 int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe);
 char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error);
-ufunc_T *find_func(char_u *name, cctx_T *cctx);
+ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx);
 int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
 void save_funccal(funccal_entry_T *entry);
 void restore_funccal(void);
 funccall_T *get_current_funccal(void);
+void delete_script_functions(int sid);
 void free_all_functions(void);
 int builtin_function(char_u *name, int len);
 int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv);
@@ -19,11 +20,11 @@ int get_callback_depth(void);
 int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars);
 void user_func_error(int error, char_u *name);
 int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe);
-char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial);
+char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial);
 char_u *untrans_function_name(char_u *name);
 void ex_function(exarg_T *eap);
 int eval_fname_script(char_u *p);
-int translated_function_exists(char_u *name);
+int translated_function_exists(char_u *name, int is_global);
 int has_varargs(ufunc_T *ufunc);
 int function_exists(char_u *name, int no_deref);
 char_u *get_expanded_name(char_u *name, int check);
index 3b7652d1fb3127458d0e864ee37142afcfe80cec..0756116b107e3787ff669ceaf4e60df659e6d479 100644 (file)
@@ -1275,6 +1275,7 @@ do_source(
        hashitem_T      *hi;
        dictitem_T      *di;
        int             todo;
+       int             is_vim9 = si->sn_version == SCRIPT_VERSION_VIM9;
 
        // loading the same script again
        si->sn_had_command = FALSE;
@@ -1293,6 +1294,10 @@ do_source(
 
        // old imports are no longer valid
        free_imports(sid);
+
+       // in Vim9 script functions are marked deleted
+       if (is_vim9)
+           delete_script_functions(sid);
     }
     else
     {
index 42a99261fb59f2bbc683d0797c4ca199394382d0..463227257a76d654d697c7036ba0079785024a69 100644 (file)
@@ -207,12 +207,12 @@ def Test_expr4_equal()
   assert_equal(true, g:adict == #{bbb: 8, aaa: 2})
   assert_equal(false, #{ccc: 9, aaa: 2} == g:adict)
 
-  assert_equal(true, function('Test_expr4_equal') == function('Test_expr4_equal'))
-  assert_equal(false, function('Test_expr4_equal') == function('Test_expr4_is'))
+  assert_equal(true, function('g:Test_expr4_equal') == function('g:Test_expr4_equal'))
+  assert_equal(false, function('g:Test_expr4_equal') == function('g:Test_expr4_is'))
 
-  assert_equal(true, function('Test_expr4_equal', [123]) == function('Test_expr4_equal', [123]))
-  assert_equal(false, function('Test_expr4_equal', [123]) == function('Test_expr4_is', [123]))
-  assert_equal(false, function('Test_expr4_equal', [123]) == function('Test_expr4_equal', [999]))
+  assert_equal(true, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_equal', [123]))
+  assert_equal(false, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_is', [123]))
+  assert_equal(false, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_equal', [999]))
 enddef
 
 " test != comperator
@@ -274,12 +274,12 @@ def Test_expr4_notequal()
   assert_equal(false, g:adict != #{bbb: 8, aaa: 2})
   assert_equal(true, #{ccc: 9, aaa: 2} != g:adict)
 
-  assert_equal(false, function('Test_expr4_equal') != function('Test_expr4_equal'))
-  assert_equal(true, function('Test_expr4_equal') != function('Test_expr4_is'))
+  assert_equal(false, function('g:Test_expr4_equal') != function('g:Test_expr4_equal'))
+  assert_equal(true, function('g:Test_expr4_equal') != function('g:Test_expr4_is'))
 
-  assert_equal(false, function('Test_expr4_equal', [123]) != function('Test_expr4_equal', [123]))
-  assert_equal(true, function('Test_expr4_equal', [123]) != function('Test_expr4_is', [123]))
-  assert_equal(true, function('Test_expr4_equal', [123]) != function('Test_expr4_equal', [999]))
+  assert_equal(false, function('g:Test_expr4_equal', [123]) != function('g:Test_expr4_equal', [123]))
+  assert_equal(true, function('g:Test_expr4_equal', [123]) != function('g:Test_expr4_is', [123]))
+  assert_equal(true, function('g:Test_expr4_equal', [123]) != function('g:Test_expr4_equal', [999]))
 enddef
 
 " test > comperator
@@ -929,15 +929,15 @@ endfunc
 
 def Test_expr7_trailing()
   " user function call
-  assert_equal(123, CallMe(123))
-  assert_equal(123, CallMe(  123))
-  assert_equal(123, CallMe(123  ))
-  assert_equal('yesno', CallMe2('yes', 'no'))
-  assert_equal('yesno', CallMe2( 'yes', 'no' ))
-  assert_equal('nothing', CallMe('nothing'))
+  assert_equal(123, g:CallMe(123))
+  assert_equal(123, g:CallMe(  123))
+  assert_equal(123, g:CallMe(123  ))
+  assert_equal('yesno', g:CallMe2('yes', 'no'))
+  assert_equal('yesno', g:CallMe2( 'yes', 'no' ))
+  assert_equal('nothing', g:CallMe('nothing'))
 
   " partial call
-  let Part = function('CallMe')
+  let Part = function('g:CallMe')
   assert_equal('yes', Part('yes'))
 
   " funcref call, using list index
index f3721ba9f91c5816152cc014b785787f2b2e9a2a..2ee91f1abd2eac8755c05fbf3553890075d2acd5 100644 (file)
@@ -353,7 +353,7 @@ endfunc
 def Test_delfunc()
   let lines =<< trim END
     vim9script
-    def GoneSoon()
+    def g:GoneSoon()
       echo 'hello'
     enddef
 
@@ -361,7 +361,7 @@ def Test_delfunc()
       GoneSoon()
     enddef
 
-    delfunc GoneSoon
+    delfunc g:GoneSoon
     CallGoneSoon()
   END
   writefile(lines, 'XToDelFunc')
index 218ef774025e213df1918383c24df2c5363de8e4..0ab170ef12834ce89d44eb6dffabfef66540038d 100644 (file)
@@ -53,7 +53,7 @@ def Test_assignment()
   endif
   let Funky1: func
   let Funky2: func = function('len')
-  let Party2: func = funcref('Test_syntax')
+  let Party2: func = funcref('g:Test_syntax')
 
   # type becomes list<any>
   let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
@@ -282,6 +282,49 @@ def Test_unlet()
   assert_equal('', $ENVVAR)
 enddef
 
+def Test_delfunction()
+  " Check function is defined in script namespace
+  CheckScriptSuccess([
+      'vim9script',
+      'func CheckMe()',
+      '  return 123',
+      'endfunc',
+      'assert_equal(123, s:CheckMe())',
+      ])
+
+  " Check function in script namespace cannot be deleted
+  CheckScriptFailure([
+      'vim9script',
+      'func DeleteMe1()',
+      'endfunc',
+      'delfunction DeleteMe1',
+      ], 'E1084:')
+  CheckScriptFailure([
+      'vim9script',
+      'func DeleteMe2()',
+      'endfunc',
+      'def DoThat()',
+      '  delfunction DeleteMe2',
+      'enddef',
+      'DoThat()',
+      ], 'E1084:')
+  CheckScriptFailure([
+      'vim9script',
+      'def DeleteMe3()',
+      'enddef',
+      'delfunction DeleteMe3',
+      ], 'E1084:')
+  CheckScriptFailure([
+      'vim9script',
+      'def DeleteMe4()',
+      'enddef',
+      'def DoThat()',
+      '  delfunction DeleteMe4',
+      'enddef',
+      'DoThat()',
+      ], 'E1084:')
+enddef
+
 func Test_wrong_type()
   call CheckDefFailure(['let var: list<nothing>'], 'E1010:')
   call CheckDefFailure(['let var: list<list<nothing>>'], 'E1010:')
@@ -649,7 +692,7 @@ def Test_vim9script_fails()
   assert_fails('export something', 'E1043')
 enddef
 
-def Test_vim9script_reload()
+def Test_vim9script_reload_import()
   let lines =<< trim END
     vim9script
     const var = ''
@@ -700,6 +743,47 @@ def Test_vim9script_reload()
   delete('Ximport.vim')
 enddef
 
+def Test_vim9script_reload_delfunc()
+  let first_lines =<< trim END
+    vim9script
+    def FuncYes(): string
+      return 'yes'
+    enddef
+  END
+  let middle_lines =<< trim END
+    def FuncNo(): string
+      return 'no'
+    enddef
+  END
+  let final_lines =<< trim END
+    def g:DoCheck(no_exists: bool)
+      assert_equal('yes', FuncYes())
+      if no_exists
+        assert_equal('no', FuncNo())
+      else
+        assert_fails('call FuncNo()', 'E117:')
+      endif
+    enddef
+  END
+
+  # FuncNo() is defined
+  writefile(first_lines + middle_lines + final_lines, 'Xreloaded.vim')
+  source Xreloaded.vim
+  g:DoCheck(true)
+
+  # FuncNo() is not redefined
+  writefile(first_lines + final_lines, 'Xreloaded.vim')
+  source Xreloaded.vim
+  g:DoCheck(false)
+
+  # FuncNo() is back
+  writefile(first_lines + middle_lines + final_lines, 'Xreloaded.vim')
+  source Xreloaded.vim
+  g:DoCheck(true)
+
+  delete('Xreloaded.vim')
+enddef
+
 def Test_import_absolute()
   let import_lines = [
         'vim9script',
@@ -1445,15 +1529,15 @@ def Test_vim9_comment()
 
   CheckScriptSuccess([
       'vim9script',
-      'func DeleteMe()',
+      'func g:DeleteMeA()',
       'endfunc',
-      'delfunction DeleteMe # comment',
+      'delfunction g:DeleteMeA # comment',
       ])
   CheckScriptFailure([
       'vim9script',
-      'func DeleteMe()',
+      'func g:DeleteMeB()',
       'endfunc',
-      'delfunction DeleteMe# comment',
+      'delfunction g:DeleteMeB# comment',
       ], 'E488:')
 
   CheckScriptSuccess([
index 35c268349b81c4e1a4a7a054e252121e38d98d49..604d39b74c3e89b04cd55ce6fa8e642ecc323992 100644 (file)
@@ -789,7 +789,7 @@ f_test_refcount(typval_T *argvars, typval_T *rettv)
            {
                ufunc_T *fp;
 
-               fp = find_func(argvars[0].vval.v_string, NULL);
+               fp = find_func(argvars[0].vval.v_string, FALSE, NULL);
                if (fp != NULL)
                    retval = fp->uf_refcount;
            }
index 6005af1f5983ea936fa616db463ab48f32320b99..993697e46d6231967be97251f54136b34f470aab 100644 (file)
@@ -25,6 +25,7 @@
 #define FC_DEAD            0x80        // function kept only for reference to dfunc
 #define FC_EXPORT   0x100      // "export def Func()"
 #define FC_NOARGS   0x200      // no a: variables in lambda
+#define FC_VIM9            0x400       // defined in vim9 script file
 
 /*
  * All user-defined functions are found in this hashtable.
@@ -710,16 +711,17 @@ find_func_with_sid(char_u *name, int sid)
 
 /*
  * Find a function by name, return pointer to it in ufuncs.
+ * When "is_global" is true don't find script-local or imported functions.
  * Return NULL for unknown function.
  */
     static ufunc_T *
-find_func_even_dead(char_u *name, cctx_T *cctx)
+find_func_even_dead(char_u *name, int is_global, cctx_T *cctx)
 {
     hashitem_T *hi;
     ufunc_T    *func;
     imported_T *imported;
 
-    if (in_vim9script())
+    if (in_vim9script() && !is_global)
     {
        // Find script-local function before global one.
        func = find_func_with_sid(name, current_sctx.sc_sid);
@@ -750,9 +752,9 @@ find_func_even_dead(char_u *name, cctx_T *cctx)
  * Return NULL for unknown or dead function.
  */
     ufunc_T *
-find_func(char_u *name, cctx_T *cctx)
+find_func(char_u *name, int is_global, cctx_T *cctx)
 {
-    ufunc_T    *fp = find_func_even_dead(name, cctx);
+    ufunc_T    *fp = find_func_even_dead(name, is_global, cctx);
 
     if (fp != NULL && (fp->uf_flags & FC_DEAD) == 0)
        return fp;
@@ -1575,6 +1577,38 @@ get_current_funccal(void)
     return current_funccal;
 }
 
+/*
+ * Mark all functions of script "sid" as deleted.
+ */
+    void
+delete_script_functions(int sid)
+{
+    hashitem_T *hi;
+    ufunc_T    *fp;
+    long_u     todo;
+    char       buf[30];
+    size_t     len;
+
+    buf[0] = K_SPECIAL;
+    buf[1] = KS_EXTRA;
+    buf[2] = (int)KE_SNR;
+    sprintf(buf + 3, "%d_", sid);
+    len = STRLEN(buf);
+
+    todo = func_hashtab.ht_used;
+    for (hi = func_hashtab.ht_array; todo > 0; ++hi)
+       if (!HASHITEM_EMPTY(hi))
+       {
+           if (STRNCMP(fp->uf_name, buf, len) == 0)
+           {
+               fp = HI2UF(hi);
+               fp->uf_flags |= FC_DEAD;
+               func_clear(fp, TRUE);
+           }
+           --todo;
+       }
+}
+
 #if defined(EXITFREE) || defined(PROTO)
     void
 free_all_functions(void)
@@ -1884,22 +1918,22 @@ call_func(
             * User defined function.
             */
            if (fp == NULL)
-               fp = find_func(rfname, NULL);
+               fp = find_func(rfname, FALSE, NULL);
 
            // Trigger FuncUndefined event, may load the function.
            if (fp == NULL
                    && apply_autocmds(EVENT_FUNCUNDEFINED,
-                                                    rfname, rfname, TRUE, NULL)
+                                                   rfname, rfname, TRUE, NULL)
                    && !aborting())
            {
                // executed an autocommand, search for the function again
-               fp = find_func(rfname, NULL);
+               fp = find_func(rfname, FALSE, NULL);
            }
            // Try loading a package.
            if (fp == NULL && script_autoload(rfname, TRUE) && !aborting())
            {
                // loaded a package, search for the function again
-               fp = find_func(rfname, NULL);
+               fp = find_func(rfname, FALSE, NULL);
            }
            if (fp == NULL)
            {
@@ -1908,7 +1942,7 @@ call_func(
                // If using Vim9 script try not local to the script.
                // TODO: should not do this if the name started with "s:".
                if (p != NULL)
-                   fp = find_func(p, NULL);
+                   fp = find_func(p, FALSE, NULL);
            }
 
            if (fp != NULL && (fp->uf_flags & FC_DELETED))
@@ -2079,6 +2113,8 @@ list_func_head(ufunc_T *fp, int indent)
  * Get a function name, translating "<SID>" and "<SNR>".
  * Also handles a Funcref in a List or Dictionary.
  * Returns the function name in allocated memory, or NULL for failure.
+ * Set "*is_global" to TRUE when the function must be global, unless
+ * "is_global" is NULL.
  * flags:
  * TFN_INT:        internal function name OK
  * TFN_QUIET:      be quiet
@@ -2089,6 +2125,7 @@ list_func_head(ufunc_T *fp, int indent)
     char_u *
 trans_function_name(
     char_u     **pp,
+    int                *is_global,
     int                skip,           // only find the end, don't evaluate
     int                flags,
     funcdict_T *fdp,           // return: info about dictionary used
@@ -2239,7 +2276,11 @@ trans_function_name(
     {
        // skip over "s:" and "g:"
        if (lead == 2 || (lv.ll_name[0] == 'g' && lv.ll_name[1] == ':'))
+       {
+           if (is_global != NULL && lv.ll_name[0] == 'g')
+               *is_global = TRUE;
            lv.ll_name += 2;
+       }
        len = (int)(end - lv.ll_name);
     }
 
@@ -2347,6 +2388,7 @@ ex_function(exarg_T *eap)
     int                saved_did_emsg;
     int                saved_wait_return = need_wait_return;
     char_u     *name = NULL;
+    int                is_global = FALSE;
     char_u     *p;
     char_u     *arg;
     char_u     *line_arg = NULL;
@@ -2463,7 +2505,8 @@ ex_function(exarg_T *eap)
      * g:func      global function name, same as "func"
      */
     p = eap->arg;
-    name = trans_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi, NULL);
+    name = trans_function_name(&p, &is_global, eap->skip,
+                                                TFN_NO_AUTOLOAD, &fudi, NULL);
     paren = (vim_strchr(p, '(') != NULL);
     if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
     {
@@ -2503,7 +2546,7 @@ ex_function(exarg_T *eap)
            *p = NUL;
        if (!eap->skip && !got_int)
        {
-           fp = find_func(name, NULL);
+           fp = find_func(name, is_global, NULL);
            if (fp == NULL && ASCII_ISUPPER(*eap->arg))
            {
                char_u *up = untrans_function_name(name);
@@ -2511,7 +2554,7 @@ ex_function(exarg_T *eap)
                // With Vim9 script the name was made script-local, if not
                // found try again with the original name.
                if (up != NULL)
-                   fp = find_func(up, NULL);
+                   fp = find_func(up, FALSE, NULL);
            }
 
            if (fp != NULL)
@@ -2675,7 +2718,7 @@ ex_function(exarg_T *eap)
        {
            if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL)
                emsg(_(e_funcdict));
-           else if (name != NULL && find_func(name, NULL) != NULL)
+           else if (name != NULL && find_func(name, is_global, NULL) != NULL)
                emsg_funcname(e_funcexts, name);
        }
 
@@ -2825,7 +2868,7 @@ ex_function(exarg_T *eap)
                if (*p == '!')
                    p = skipwhite(p + 1);
                p += eval_fname_script(p);
-               vim_free(trans_function_name(&p, TRUE, 0, NULL, NULL));
+               vim_free(trans_function_name(&p, NULL, TRUE, 0, NULL, NULL));
                if (*skipwhite(p) == '(')
                {
                    if (nesting == MAX_FUNC_NESTING - 1)
@@ -2963,7 +3006,7 @@ ex_function(exarg_T *eap)
            goto erret;
        }
 
-       fp = find_func_even_dead(name, NULL);
+       fp = find_func_even_dead(name, is_global, NULL);
        if (fp != NULL)
        {
            int dead = fp->uf_flags & FC_DEAD;
@@ -3208,6 +3251,8 @@ ex_function(exarg_T *eap)
     fp->uf_varargs = varargs;
     if (sandbox)
        flags |= FC_SANDBOX;
+    if (in_vim9script() && !ASCII_ISUPPER(*fp->uf_name))
+       flags |= FC_VIM9;
     fp->uf_flags = flags;
     fp->uf_calls = 0;
     fp->uf_cleared = FALSE;
@@ -3261,11 +3306,11 @@ eval_fname_script(char_u *p)
 }
 
     int
-translated_function_exists(char_u *name)
+translated_function_exists(char_u *name, int is_global)
 {
     if (builtin_function(name, -1))
        return has_internal_func(name);
-    return find_func(name, NULL) != NULL;
+    return find_func(name, is_global, NULL) != NULL;
 }
 
 /*
@@ -3289,17 +3334,18 @@ function_exists(char_u *name, int no_deref)
     char_u  *p;
     int            n = FALSE;
     int            flag;
+    int            is_global = FALSE;
 
     flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
     if (no_deref)
        flag |= TFN_NO_DEREF;
-    p = trans_function_name(&nm, FALSE, flag, NULL, NULL);
+    p = trans_function_name(&nm, &is_global, FALSE, flag, NULL, NULL);
     nm = skipwhite(nm);
 
     // Only accept "funcname", "funcname ", "funcname (..." and
     // "funcname(...", not "funcname!...".
     if (p != NULL && (*nm == NUL || *nm == '('))
-       n = translated_function_exists(p);
+       n = translated_function_exists(p, is_global);
     vim_free(p);
     return n;
 }
@@ -3310,12 +3356,14 @@ get_expanded_name(char_u *name, int check)
 {
     char_u     *nm = name;
     char_u     *p;
+    int                is_global = FALSE;
 
-    p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL, NULL);
+    p = trans_function_name(&nm, &is_global, FALSE,
+                                               TFN_INT|TFN_QUIET, NULL, NULL);
 
-    if (p != NULL && *nm == NUL)
-       if (!check || translated_function_exists(p))
-           return p;
+    if (p != NULL && *nm == NUL
+                      && (!check || translated_function_exists(p, is_global)))
+       return p;
 
     vim_free(p);
     return NULL;
@@ -3376,9 +3424,10 @@ ex_delfunction(exarg_T *eap)
     char_u     *p;
     char_u     *name;
     funcdict_T fudi;
+    int                is_global = FALSE;
 
     p = eap->arg;
-    name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
+    name = trans_function_name(&p, &is_global, eap->skip, 0, &fudi, NULL);
     vim_free(fudi.fd_newkey);
     if (name == NULL)
     {
@@ -3397,7 +3446,7 @@ ex_delfunction(exarg_T *eap)
        *p = NUL;
 
     if (!eap->skip)
-       fp = find_func(name, NULL);
+       fp = find_func(name, is_global, NULL);
     vim_free(name);
 
     if (!eap->skip)
@@ -3413,6 +3462,11 @@ ex_delfunction(exarg_T *eap)
            semsg(_("E131: Cannot delete function %s: It is in use"), eap->arg);
            return;
        }
+       if (fp->uf_flags & FC_VIM9)
+       {
+           semsg(_("E1084: Cannot delete Vim9 script function %s"), eap->arg);
+           return;
+       }
 
        if (fudi.fd_dict != NULL)
        {
@@ -3452,7 +3506,7 @@ func_unref(char_u *name)
 
     if (name == NULL || !func_name_refcount(name))
        return;
-    fp = find_func(name, NULL);
+    fp = find_func(name, FALSE, NULL);
     if (fp == NULL && isdigit(*name))
     {
 #ifdef EXITFREE
@@ -3495,7 +3549,7 @@ func_ref(char_u *name)
 
     if (name == NULL || !func_name_refcount(name))
        return;
-    fp = find_func(name, NULL);
+    fp = find_func(name, FALSE, NULL);
     if (fp != NULL)
        ++fp->uf_refcount;
     else if (isdigit(*name))
@@ -3611,7 +3665,8 @@ ex_call(exarg_T *eap)
        return;
     }
 
-    tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial);
+    tofree = trans_function_name(&arg, NULL, eap->skip,
+                                                    TFN_INT, &fudi, &partial);
     if (fudi.fd_newkey != NULL)
     {
        // Still need to give an error message for missing key.
@@ -3969,7 +4024,7 @@ make_partial(dict_T *selfdict_in, typval_T *rettv)
                                              : rettv->vval.v_partial->pt_name;
        // Translate "s:func" to the stored function name.
        fname = fname_trans_sid(fname, fname_buf, &tofree, &error);
-       fp = find_func(fname, NULL);
+       fp = find_func(fname, FALSE, NULL);
        vim_free(tofree);
     }
 
@@ -4391,7 +4446,7 @@ set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
     if (fp_in == NULL)
     {
        fname = fname_trans_sid(name, fname_buf, &tofree, &error);
-       fp = find_func(fname, NULL);
+       fp = find_func(fname, FALSE, NULL);
     }
     if (fp != NULL)
     {
index fa91a2bc04b7fc104195c788174c65fba0a9d285..d58ef8ac0548dfc318cfc80eb065e2692db2629c 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    650,
 /**/
     649,
 /**/
index 0e9abac0e48a188e98428a386405c5338ffb0bf0..89a86779a633e38e38f214de79d0a216d7a62ecb 100644 (file)
@@ -2210,7 +2210,7 @@ compile_load_scriptvar(
     static int
 generate_funcref(cctx_T *cctx, char_u *name)
 {
-    ufunc_T *ufunc = find_func(name, cctx);
+    ufunc_T *ufunc = find_func(name, FALSE, cctx);
 
     if (ufunc == NULL)
        return FAIL;
@@ -2452,7 +2452,7 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init)
     }
 
     // If we can find the function by name generate the right call.
-    ufunc = find_func(name, cctx);
+    ufunc = find_func(name, FALSE, cctx);
     if (ufunc != NULL)
     {
        res = generate_CALL(cctx, ufunc, argcount);
index 9ea7dafad3535706e54a6082ebe75320239a950f..5251d4848619f98fb36f3556e5a0692980fc642b 100644 (file)
@@ -400,7 +400,7 @@ call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
        return call_bfunc(func_idx, argcount, ectx);
     }
 
-    ufunc = find_func(name, NULL);
+    ufunc = find_func(name, FALSE, NULL);
     if (ufunc != NULL)
        return call_ufunc(ufunc, argcount, ectx, iptr);
 
@@ -1944,8 +1944,9 @@ ex_disassemble(exarg_T *eap)
     int                current;
     int                line_idx = 0;
     int                prev_current = 0;
+    int                is_global = FALSE;
 
-    fname = trans_function_name(&arg, FALSE,
+    fname = trans_function_name(&arg, &is_global, FALSE,
             TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
     if (fname == NULL)
     {
@@ -1953,14 +1954,14 @@ ex_disassemble(exarg_T *eap)
        return;
     }
 
-    ufunc = find_func(fname, NULL);
+    ufunc = find_func(fname, is_global, NULL);
     if (ufunc == NULL)
     {
        char_u *p = untrans_function_name(fname);
 
        if (p != NULL)
            // Try again without making it script-local.
-           ufunc = find_func(p, NULL);
+           ufunc = find_func(p, FALSE, NULL);
     }
     vim_free(fname);
     if (ufunc == NULL)
index e74a7b9cbb932d018a42792706ab8a95fad697e6..afd6a4af97815a1efb453c325de53d05c0a2c026 100644 (file)
@@ -217,7 +217,7 @@ find_exported(
        funcname[1] = KS_EXTRA;
        funcname[2] = (int)KE_SNR;
        sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
-       *ufunc = find_func(funcname, NULL);
+       *ufunc = find_func(funcname, FALSE, NULL);
        if (funcname != buffer)
            vim_free(funcname);