]> granicus.if.org Git - vim/commitdiff
patch 7.4.2137 v7.4.2137
authorBram Moolenaar <Bram@vim.org>
Mon, 1 Aug 2016 13:40:54 +0000 (15:40 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 1 Aug 2016 13:40:54 +0000 (15:40 +0200)
Problem:    Using function() with a name will find another function when it is
            redefined.
Solution:   Add funcref().  Refer to lambda using a partial.  Fix several
            reference counting issues.

16 files changed:
runtime/doc/eval.txt
src/channel.c
src/eval.c
src/evalfunc.c
src/if_mzsch.c
src/if_py_both.h
src/misc2.c
src/proto/eval.pro
src/proto/userfunc.pro
src/regexp.c
src/structs.h
src/testdir/test_expr.vim
src/testdir/test_lambda.vim
src/userfunc.c
src/version.c
src/vim.h

index 8dfbb3a28e77d969b14e391ef003e402086a5605..7e0b73c6123b4d8b61acc51d7b0e2725904b0b49 100644 (file)
@@ -1,4 +1,4 @@
-*eval.txt*     For Vim version 7.4.  Last change: 2016 Jul 29
+*eval.txt*     For Vim version 7.4.  Last change: 2016 Jul 31
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -1240,7 +1240,9 @@ function returns: >
        :let Bar = Foo(4)
        :echo Bar(6)
 <      5
-See also |:func-closure|.
+
+See also |:func-closure|.  Lambda and closure support can be checked with: >
+       if has('lambda')
 
 Examples for using a lambda expression with |sort()|, |map()| and |filter()|: >
        :echo map([1, 2, 3], {idx, val -> val + 1})
@@ -2071,8 +2073,10 @@ foldlevel({lnum})                Number  fold level at {lnum}
 foldtext()                     String  line displayed for closed fold
 foldtextresult({lnum})         String  text for closed fold at {lnum}
 foreground()                   Number  bring the Vim window to the foreground
-function({name} [, {arglist}] [, {dict}])
+funcref({name} [, {arglist}] [, {dict}])
                                Funcref reference to function {name}
+function({name} [, {arglist}] [, {dict}])
+                               Funcref named reference to function {name}
 garbagecollect([{atexit}])     none    free memory, breaking cyclic references
 get({list}, {idx} [, {def}])   any     get item {idx} from {list} or {def}
 get({dict}, {key} [, {def}])   any     get item {key} from {dict} or {def}
@@ -3850,6 +3854,15 @@ foreground()     Move the Vim window to the foreground.  Useful when sent from
                {only in the Win32, Athena, Motif and GTK GUI versions and the
                Win32 console version}
 
+                                               *funcref()*
+funcref({name} [, {arglist}] [, {dict}])
+               Just like |function()|, but the returned Funcref will lookup
+               the function by reference, not by name.  This matters when the
+               function {name} is redefined later.
+
+               Unlike |function()|, {name} must be an existing user function.
+               Also for autoloaded functions. {name} cannot be a builtin
+               function.
 
                                        *function()* *E700* *E922* *E923*
 function({name} [, {arglist}] [, {dict}])
@@ -3857,12 +3870,16 @@ function({name} [, {arglist}] [, {dict}])
                {name} can be the name of a user defined function or an
                internal function.
 
-               {name} can also be a Funcref, also a partial.  When it is a
+               {name} can also be a Funcref or a partial.  When it is a
                partial the dict stored in it will be used and the {dict}
                argument is not allowed. E.g.: >
                        let FuncWithArg = function(dict.Func, [arg])
                        let Broken = function(dict.Func, [arg], dict)
 <
+               When using the Funcref the function will be found by {name},
+               also when it was redefined later.  Use |funcref()| to keep the
+               same function.
+
                When {arglist} or {dict} is present this creates a partial.
                That means the argument list and/or the dictionary is stored in
                the Funcref and will be used when the Funcref is called.
@@ -6191,6 +6208,7 @@ screenrow()                                                       *screenrow()*
                The result is a Number, which is the current screen row of the
                cursor.  The top line has number one.
                This function is mainly used for testing.
+               Alternatively you can use |winline()|.
 
                Note: Same restrictions as with |screencol()|.
 
@@ -8039,6 +8057,7 @@ insert_expand             Compiled with support for CTRL-X expansion commands in
                        Insert mode.
 jumplist               Compiled with |jumplist| support.
 keymap                 Compiled with 'keymap' support.
+lambda                 Compiled with |lambda| support.
 langmap                        Compiled with 'langmap' support.
 libcall                        Compiled with |libcall()| support.
 linebreak              Compiled with 'linebreak', 'breakat', 'showbreak' and
@@ -8294,7 +8313,7 @@ See |:verbose-cmd| for more information.
 :endf[unction]         The end of a function definition.  Must be on a line
                        by its own, without other commands.
 
-                                       *:delf* *:delfunction* *E130* *E131*
+                               *:delf* *:delfunction* *E130* *E131* *E933*
 :delf[unction] {name}  Delete function {name}.
                        {name} can also be a |Dictionary| entry that is a
                        |Funcref|: >
index 3b8b5afa05774d99eed17704cc06e259c4200307..5ee05e3332a3c39b49ac37a604f64bfc963e022e 100644 (file)
@@ -1124,15 +1124,18 @@ set_callback(
     if (callback != NULL && *callback != NUL)
     {
        if (partial != NULL)
-           *cbp = partial->pt_name;
+           *cbp = partial_name(partial);
        else
+       {
            *cbp = vim_strsave(callback);
+           func_ref(*cbp);
+       }
     }
     else
        *cbp = NULL;
     *pp = partial;
-    if (*pp != NULL)
-       ++(*pp)->pt_refcount;
+    if (partial != NULL)
+       ++partial->pt_refcount;
 }
 
 /*
@@ -1279,7 +1282,10 @@ channel_set_req_callback(
            item->cq_callback = callback;
        }
        else
+       {
            item->cq_callback = vim_strsave(callback);
+           func_ref(item->cq_callback);
+       }
        item->cq_seq_nr = id;
        item->cq_prev = head->cq_prev;
        head->cq_prev = item;
@@ -3923,14 +3929,24 @@ free_job_options(jobopt_T *opt)
 {
     if (opt->jo_partial != NULL)
        partial_unref(opt->jo_partial);
+    else if (opt->jo_callback != NULL)
+       func_unref(opt->jo_callback);
     if (opt->jo_out_partial != NULL)
        partial_unref(opt->jo_out_partial);
+    else if (opt->jo_out_cb != NULL)
+       func_unref(opt->jo_out_cb);
     if (opt->jo_err_partial != NULL)
        partial_unref(opt->jo_err_partial);
+    else if (opt->jo_err_cb != NULL)
+       func_unref(opt->jo_err_cb);
     if (opt->jo_close_partial != NULL)
        partial_unref(opt->jo_close_partial);
+    else if (opt->jo_close_cb != NULL)
+       func_unref(opt->jo_close_cb);
     if (opt->jo_exit_partial != NULL)
        partial_unref(opt->jo_exit_partial);
+    else if (opt->jo_exit_cb != NULL)
+       func_unref(opt->jo_exit_cb);
 }
 
 /*
@@ -4476,7 +4492,10 @@ job_set_options(job_T *job, jobopt_T *opt)
                ++job->jv_exit_partial->pt_refcount;
            }
            else
+           {
                job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
+               func_ref(job->jv_exit_cb);
+           }
        }
     }
 }
index cf2c771438957a225669b7e70a45982ecab9228b..495bbb0697698753332d1206b81ae2623d0388ba 100644 (file)
@@ -5011,6 +5011,17 @@ get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
     return OK;
 }
 
+/*
+ * Return the function name of the partial.
+ */
+    char_u *
+partial_name(partial_T *pt)
+{
+    if (pt->pt_name != NULL)
+       return pt->pt_name;
+    return pt->pt_func->uf_name;
+}
+
     static void
 partial_free(partial_T *pt)
 {
@@ -5020,8 +5031,13 @@ partial_free(partial_T *pt)
        clear_tv(&pt->pt_argv[i]);
     vim_free(pt->pt_argv);
     dict_unref(pt->pt_dict);
-    func_unref(pt->pt_name);
-    vim_free(pt->pt_name);
+    if (pt->pt_name != NULL)
+    {
+       func_unref(pt->pt_name);
+       vim_free(pt->pt_name);
+    }
+    else
+       func_ptr_unref(pt->pt_func);
     vim_free(pt);
 }
 
@@ -5051,11 +5067,11 @@ func_equal(
 
     /* empty and NULL function name considered the same */
     s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
-                                          : tv1->vval.v_partial->pt_name;
+                                          : partial_name(tv1->vval.v_partial);
     if (s1 != NULL && *s1 == NUL)
        s1 = NULL;
     s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
-                                          : tv2->vval.v_partial->pt_name;
+                                          : partial_name(tv2->vval.v_partial);
     if (s2 != NULL && *s2 == NUL)
        s2 = NULL;
     if (s1 == NULL || s2 == NULL)
@@ -5550,7 +5566,7 @@ set_ref_in_item(
     }
     else if (tv->v_type == VAR_FUNC)
     {
-       abort = set_ref_in_func(tv->vval.v_string, copyID);
+       abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
     }
     else if (tv->v_type == VAR_PARTIAL)
     {
@@ -5561,7 +5577,7 @@ set_ref_in_item(
         */
        if (pt != NULL)
        {
-           abort = set_ref_in_func(pt->pt_name, copyID);
+           abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
 
            if (pt->pt_dict != NULL)
            {
@@ -5735,7 +5751,7 @@ echo_string_core(
            {
                partial_T   *pt = tv->vval.v_partial;
                char_u      *fname = string_quote(pt == NULL ? NULL
-                                                       : pt->pt_name, FALSE);
+                                                   : partial_name(pt), FALSE);
                garray_T    ga;
                int         i;
                char_u      *tf;
@@ -6871,7 +6887,7 @@ handle_subscript(
                if (functv.v_type == VAR_PARTIAL)
                {
                    pt = functv.vval.v_partial;
-                   s = pt->pt_name;
+                   s = partial_name(pt);
                }
                else
                    s = functv.vval.v_string;
@@ -10025,7 +10041,7 @@ filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
     {
        partial_T   *partial = expr->vval.v_partial;
 
-       s = partial->pt_name;
+       s = partial_name(partial);
        if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
                                  0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
            goto theend;
index 13864ea3a73334619fbc6a0cc2f9a66492e18d43..68a8b16414ed0c5c344bde67b9c5025d534e7f27 100644 (file)
@@ -148,6 +148,7 @@ static void f_foldlevel(typval_T *argvars, typval_T *rettv);
 static void f_foldtext(typval_T *argvars, typval_T *rettv);
 static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
 static void f_foreground(typval_T *argvars, typval_T *rettv);
+static void f_funcref(typval_T *argvars, typval_T *rettv);
 static void f_function(typval_T *argvars, typval_T *rettv);
 static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
 static void f_get(typval_T *argvars, typval_T *rettv);
@@ -563,6 +564,7 @@ static struct fst
     {"foldtext",       0, 0, f_foldtext},
     {"foldtextresult", 1, 1, f_foldtextresult},
     {"foreground",     0, 0, f_foreground},
+    {"funcref",                1, 3, f_funcref},
     {"function",       1, 3, f_function},
     {"garbagecollect", 0, 1, f_garbagecollect},
     {"get",            2, 3, f_get},
@@ -1723,7 +1725,7 @@ f_call(typval_T *argvars, typval_T *rettv)
     else if (argvars[0].v_type == VAR_PARTIAL)
     {
        partial = argvars[0].vval.v_partial;
-       func = partial->pt_name;
+       func = partial_name(partial);
     }
     else
        func = get_tv_string(&argvars[0]);
@@ -3543,16 +3545,14 @@ f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
 #endif
 }
 
-/*
- * "function()" function
- */
     static void
-f_function(typval_T *argvars, typval_T *rettv)
+common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
 {
     char_u     *s;
     char_u     *name;
     int                use_string = FALSE;
     partial_T   *arg_pt = NULL;
+    char_u     *trans_name = NULL;
 
     if (argvars[0].v_type == VAR_FUNC)
     {
@@ -3564,7 +3564,7 @@ f_function(typval_T *argvars, typval_T *rettv)
     {
        /* function(dict.MyFunc, [arg]) */
        arg_pt = argvars[0].vval.v_partial;
-       s = arg_pt->pt_name;
+       s = partial_name(arg_pt);
     }
     else
     {
@@ -3573,11 +3573,22 @@ f_function(typval_T *argvars, typval_T *rettv)
        use_string = TRUE;
     }
 
+    if (((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL)
+                                  || is_funcref))
+    {
+       name = s;
+       trans_name = trans_function_name(&name, FALSE,
+            TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
+       if (*name != NUL)
+           s = NULL;
+    }
+
     if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)))
        EMSG2(_(e_invarg2), s);
     /* Don't check an autoload name for existence here. */
-    else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL
-                                               && !function_exists(s, TRUE))
+    else if (trans_name != NULL && (is_funcref
+                               ? find_func(trans_name) == NULL
+                               : !translated_function_exists(trans_name)))
        EMSG2(_("E700: Unknown function: %s"), s);
     else
     {
@@ -3625,7 +3636,7 @@ f_function(typval_T *argvars, typval_T *rettv)
                {
                    EMSG(_("E922: expected a dict"));
                    vim_free(name);
-                   return;
+                   goto theend;
                }
                if (argvars[dict_idx].vval.v_dict == NULL)
                    dict_idx = 0;
@@ -3636,14 +3647,14 @@ f_function(typval_T *argvars, typval_T *rettv)
                {
                    EMSG(_("E923: Second argument of function() must be a list or a dict"));
                    vim_free(name);
-                   return;
+                   goto theend;
                }
                list = argvars[arg_idx].vval.v_list;
                if (list == NULL || list->lv_len == 0)
                    arg_idx = 0;
            }
        }
-       if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL)
+       if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
        {
            partial_T   *pt = (partial_T *)alloc_clear(sizeof(partial_T));
 
@@ -3670,17 +3681,14 @@ f_function(typval_T *argvars, typval_T *rettv)
                    {
                        vim_free(pt);
                        vim_free(name);
-                       return;
-                   }
-                   else
-                   {
-                       for (i = 0; i < arg_len; i++)
-                           copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
-                       if (lv_len > 0)
-                           for (li = list->lv_first; li != NULL;
-                                                            li = li->li_next)
-                               copy_tv(&li->li_tv, &pt->pt_argv[i++]);
+                       goto theend;
                    }
+                   for (i = 0; i < arg_len; i++)
+                       copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
+                   if (lv_len > 0)
+                       for (li = list->lv_first; li != NULL;
+                                                        li = li->li_next)
+                           copy_tv(&li->li_tv, &pt->pt_argv[i++]);
                }
 
                /* For "function(dict.func, [], dict)" and "func" is a partial
@@ -3702,8 +3710,23 @@ f_function(typval_T *argvars, typval_T *rettv)
                }
 
                pt->pt_refcount = 1;
-               pt->pt_name = name;
-               func_ref(pt->pt_name);
+               if (arg_pt != NULL && arg_pt->pt_func != NULL)
+               {
+                   pt->pt_func = arg_pt->pt_func;
+                   func_ptr_ref(pt->pt_func);
+                   vim_free(name);
+               }
+               else if (is_funcref)
+               {
+                   pt->pt_func = find_func(trans_name);
+                   func_ptr_ref(pt->pt_func);
+                   vim_free(name);
+               }
+               else
+               {
+                   pt->pt_name = name;
+                   func_ref(name);
+               }
            }
            rettv->v_type = VAR_PARTIAL;
            rettv->vval.v_partial = pt;
@@ -3716,6 +3739,26 @@ f_function(typval_T *argvars, typval_T *rettv)
            func_ref(name);
        }
     }
+theend:
+    vim_free(trans_name);
+}
+
+/*
+ * "funcref()" function
+ */
+    static void
+f_funcref(typval_T *argvars, typval_T *rettv)
+{
+    common_function(argvars, rettv, TRUE);
+}
+
+/*
+ * "function()" function
+ */
+    static void
+f_function(typval_T *argvars, typval_T *rettv)
+{
+    common_function(argvars, rettv, FALSE);
 }
 
 /*
@@ -3781,14 +3824,20 @@ f_get(typval_T *argvars, typval_T *rettv)
        if (pt != NULL)
        {
            char_u *what = get_tv_string(&argvars[1]);
+           char_u *n;
 
            if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
            {
                rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
-               if (pt->pt_name == NULL)
+               n = partial_name(pt);
+               if (n == NULL)
                    rettv->vval.v_string = NULL;
                else
-                   rettv->vval.v_string = vim_strsave(pt->pt_name);
+               {
+                   rettv->vval.v_string = vim_strsave(n);
+                   if (rettv->v_type == VAR_FUNC)
+                       func_ref(rettv->vval.v_string);
+               }
            }
            else if (STRCMP(what, "dict") == 0)
            {
@@ -10104,7 +10153,7 @@ item_compare2(const void *s1, const void *s2)
     if (partial == NULL)
        func_name = sortinfo->item_compare_func;
     else
-       func_name = partial->pt_name;
+       func_name = partial_name(partial);
 
     /* Copy the values.  This is needed to be able to set v_lock to VAR_FIXED
      * in the copy without changing the original list items. */
@@ -11863,16 +11912,14 @@ get_callback(typval_T *arg, partial_T **pp)
     {
        *pp = arg->vval.v_partial;
        ++(*pp)->pt_refcount;
-       return (*pp)->pt_name;
+       return partial_name(*pp);
     }
     *pp = NULL;
-    if (arg->v_type == VAR_FUNC)
+    if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
     {
        func_ref(arg->vval.v_string);
        return arg->vval.v_string;
     }
-    if (arg->v_type == VAR_STRING)
-       return arg->vval.v_string;
     if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
        return (char_u *)"";
     EMSG(_("E921: Invalid callback argument"));
index daec6b0a82e6bf6fececd1e9e5a516a300ab4d2d..7a462ad54b2ccf377b86be11fc6d521880c375ff 100644 (file)
@@ -3134,7 +3134,7 @@ vim_to_mzscheme_impl(typval_T *vim_value, int depth, Scheme_Hash_Table *visited)
            /* FIXME: func_ref() and func_unref() are needed. */
            /* TODO: Support pt_dict and pt_argv. */
            funcname = scheme_make_byte_string(
-                   (char *)vim_value->vval.v_partial->pt_name);
+                             (char *)partial_name(vim_value->vval.v_partial));
            MZ_GC_CHECK();
            result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
                    (const char *)BYTE_STRING_VALUE(funcname), 0, -1);
index 062f8226d7b9f4a4a66d4aa23c8bcb0e9db67c83..4f916b79757dc8d8cb291c6efc491d531c60bb6d 100644 (file)
@@ -6310,7 +6310,7 @@ ConvertToPyObject(typval_T *tv)
            if (tv->vval.v_partial->pt_dict != NULL)
                tv->vval.v_partial->pt_dict->dv_refcount++;
            return NEW_FUNCTION(tv->vval.v_partial == NULL
-                               ? (char_u *)"" : tv->vval.v_partial->pt_name,
+                            ? (char_u *)"" : partial_name(tv->vval.v_partial),
                                tv->vval.v_partial->pt_argc, argv,
                                tv->vval.v_partial->pt_dict,
                                tv->vval.v_partial->pt_auto);
index 53469a261f8447169f24c1c48f344e1b6e1838d1..f44c33cea225931d06b809be6db31f3006619baa 100644 (file)
@@ -1217,16 +1217,20 @@ free_all_mem(void)
        if (delete_first_msg() == FAIL)
            break;
 
-# ifdef FEAT_EVAL
-    eval_clear();
-# endif
 # ifdef FEAT_JOB_CHANNEL
     channel_free_all();
-    job_free_all();
 # endif
 #ifdef FEAT_TIMERS
     timer_free_all();
 #endif
+# ifdef FEAT_EVAL
+    /* must be after channel_free_all() with unrefs partials */
+    eval_clear();
+# endif
+# ifdef FEAT_JOB_CHANNEL
+    /* must be after eval_clear() with unrefs jobs */
+    job_free_all();
+# endif
 
     free_termoptions();
 
index 56f0b49278bce9347102c64f3e6540aab06e8970..7a246838020029379f7a4c7554126ed686d6c930 100644 (file)
@@ -40,6 +40,7 @@ char_u *get_user_var_name(expand_T *xp, int idx);
 int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate);
 int eval1(char_u **arg, typval_T *rettv, int evaluate);
 int get_option_tv(char_u **arg, typval_T *rettv, int evaluate);
+char_u *partial_name(partial_T *pt);
 void partial_unref(partial_T *pt);
 int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive);
 int get_copyID(void);
index bd3960447833bb89b5ba3efdac1618a364d5d3ca..3988683cc5878780ea874582af62ae311d520992 100644 (file)
@@ -3,9 +3,11 @@ void func_init(void);
 int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
 char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
 int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict);
+ufunc_T *find_func(char_u *name);
 void free_all_functions(void);
 int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv);
 int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, int (*argv_func)(int, typval_T *, int), linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict_in);
+char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial);
 void ex_function(exarg_T *eap);
 int eval_fname_script(char_u *p);
 int translated_function_exists(char_u *name);
@@ -17,7 +19,9 @@ void prof_child_exit(proftime_T *tm);
 char_u *get_user_func_name(expand_T *xp, int idx);
 void ex_delfunction(exarg_T *eap);
 void func_unref(char_u *name);
+void func_ptr_unref(ufunc_T *fp);
 void func_ref(char_u *name);
+void func_ptr_ref(ufunc_T *fp);
 void ex_return(exarg_T *eap);
 void ex_call(exarg_T *eap);
 int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv);
@@ -51,5 +55,5 @@ dictitem_T *find_var_in_scoped_ht(char_u *name, char_u **varname, int no_autoloa
 int set_ref_in_previous_funccal(int copyID);
 int set_ref_in_call_stack(int copyID);
 int set_ref_in_func_args(int copyID);
-int set_ref_in_func(char_u *name, int copyID);
+int set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID);
 /* vim: set ft=c : */
index 6b23cfbec9554e0ec3ecb096d128a01d2e02e8db..6a685e30b3adff313ee64b2a7eb7954afa960db0 100644 (file)
@@ -7499,7 +7499,7 @@ vim_regsub_both(
                    {
                        partial_T   *partial = expr->vval.v_partial;
 
-                       s = partial->pt_name;
+                       s = partial_name(partial);
                        call_func(s, (int)STRLEN(s), &rettv,
                                        1, argv, fill_submatch_list,
                                          0L, 0L, &dummy, TRUE, partial, NULL);
index 7375c7c2b8e1a1a5b538665995220dc9d0c49644..11f182a77aa125e22a6e53fc37a60099af92d67f 100644 (file)
@@ -1295,10 +1295,100 @@ struct dictvar_S
     dict_T     *dv_used_prev;  /* previous dict in used dicts list */
 };
 
+#if defined(FEAT_EVAL) || defined(PROTO)
+typedef struct funccall_S funccall_T;
+
+/*
+ * Structure to hold info for a user function.
+ */
+typedef struct
+{
+    int                uf_varargs;     /* variable nr of arguments */
+    int                uf_flags;
+    int                uf_calls;       /* nr of active calls */
+    garray_T   uf_args;        /* arguments */
+    garray_T   uf_lines;       /* function lines */
+#ifdef FEAT_PROFILE
+    int                uf_profiling;   /* TRUE when func is being profiled */
+    /* profiling the function as a whole */
+    int                uf_tm_count;    /* nr of calls */
+    proftime_T uf_tm_total;    /* time spent in function + children */
+    proftime_T uf_tm_self;     /* time spent in function itself */
+    proftime_T uf_tm_children; /* time spent in children this call */
+    /* profiling the function per line */
+    int                *uf_tml_count;  /* nr of times line was executed */
+    proftime_T *uf_tml_total;  /* time spent in a line + children */
+    proftime_T *uf_tml_self;   /* time spent in a line itself */
+    proftime_T uf_tml_start;   /* start time for current line */
+    proftime_T uf_tml_children; /* time spent in children for this line */
+    proftime_T uf_tml_wait;    /* start wait time for current line */
+    int                uf_tml_idx;     /* index of line being timed; -1 if none */
+    int                uf_tml_execed;  /* line being timed was executed */
+#endif
+    scid_T     uf_script_ID;   /* ID of script where function was defined,
+                                  used for s: variables */
+    int                uf_refcount;    /* for numbered function: reference count */
+    funccall_T *uf_scoped;     /* l: local variables for closure */
+    char_u     uf_name[1];     /* name of function (actually longer); can
+                                  start with <SNR>123_ (<SNR> is K_SPECIAL
+                                  KS_EXTRA KE_SNR) */
+} ufunc_T;
+
+#define MAX_FUNC_ARGS  20      /* maximum number of function arguments */
+#define VAR_SHORT_LEN  20      /* short variable name length */
+#define FIXVAR_CNT     12      /* number of fixed variables */
+
+/* structure to hold info for a function that is currently being executed. */
+struct funccall_S
+{
+    ufunc_T    *func;          /* function being called */
+    int                linenr;         /* next line to be executed */
+    int                returned;       /* ":return" used */
+    struct                     /* fixed variables for arguments */
+    {
+       dictitem_T      var;            /* variable (without room for name) */
+       char_u  room[VAR_SHORT_LEN];    /* room for the name */
+    } fixvar[FIXVAR_CNT];
+    dict_T     l_vars;         /* l: local function variables */
+    dictitem_T l_vars_var;     /* variable for l: scope */
+    dict_T     l_avars;        /* a: argument variables */
+    dictitem_T l_avars_var;    /* variable for a: scope */
+    list_T     l_varlist;      /* list for a:000 */
+    listitem_T l_listitems[MAX_FUNC_ARGS];     /* listitems for a:000 */
+    typval_T   *rettv;         /* return value */
+    linenr_T   breakpoint;     /* next line with breakpoint or zero */
+    int                dbg_tick;       /* debug_tick when breakpoint was set */
+    int                level;          /* top nesting level of executed function */
+#ifdef FEAT_PROFILE
+    proftime_T prof_child;     /* time spent in a child */
+#endif
+    funccall_T *caller;        /* calling function or NULL */
+
+    /* for closure */
+    int                fc_refcount;
+    int                fc_copyID;      /* for garbage collection */
+    garray_T   fc_funcs;       /* list of ufunc_T* which refer this */
+};
+
+/*
+ * Struct used by trans_function_name()
+ */
+typedef struct
+{
+    dict_T     *fd_dict;       /* Dictionary used */
+    char_u     *fd_newkey;     /* new key in "dict" in allocated memory */
+    dictitem_T *fd_di;         /* Dictionary item used */
+} funcdict_T;
+
+#endif
+
 struct partial_S
 {
     int                pt_refcount;    /* reference count */
-    char_u     *pt_name;       /* function name */
+    char_u     *pt_name;       /* function name; when NULL use
+                                * pt_func->uf_name */
+    ufunc_T    *pt_func;       /* function pointer; when NULL lookup function
+                                * with pt_name */
     int                pt_auto;        /* when TRUE the partial was created for using
                                   dict.member in handle_subscript() */
     int                pt_argc;        /* number of arguments */
index d8abc275237c2df0cde6460051247408a635fe56..0800039aee1a161ac8fe6246ab845f0c1311c8e5 100644 (file)
@@ -179,3 +179,18 @@ func Test_function_with_funcref()
   call assert_equal(v:t_string, s:fref('x'))
   call assert_fails("call function('s:f')", 'E700:')
 endfunc
+
+func Test_funcref()
+  func! One()
+    return 1
+  endfunc
+  let OneByName = function('One')
+  let OneByRef = funcref('One')
+  func! One()
+    return 2
+  endfunc
+  call assert_equal(2, OneByName())
+  call assert_equal(1, OneByRef())
+  let OneByRef = funcref('One')
+  call assert_equal(2, OneByRef())
+endfunc
index 4d895460e565563e824cc9d67474b47178dd6a7e..721c47de11770837dcddbd15d5cfdb2263918bb0 100644 (file)
@@ -152,7 +152,7 @@ function! Test_lambda_delfunc()
   endfunction
 
   let l:F = s:gen()
-  call assert_fails(':call l:F()', 'E117:')
+  call assert_fails(':call l:F()', 'E933:')
 endfunction
 
 function! Test_lambda_scope()
index d264e5bbbb4355407b3dc33b5cd12f251dfbebb9..a9dc4e843dc7c313c02423d42081fa8bc7183c2b 100644 (file)
 #include "vim.h"
 
 #if defined(FEAT_EVAL) || defined(PROTO)
-
-typedef struct funccall_S funccall_T;
-
-/*
- * Structure to hold info for a user function.
- */
-typedef struct ufunc ufunc_T;
-
-struct ufunc
-{
-    int                uf_varargs;     /* variable nr of arguments */
-    int                uf_flags;
-    int                uf_calls;       /* nr of active calls */
-    garray_T   uf_args;        /* arguments */
-    garray_T   uf_lines;       /* function lines */
-#ifdef FEAT_PROFILE
-    int                uf_profiling;   /* TRUE when func is being profiled */
-    /* profiling the function as a whole */
-    int                uf_tm_count;    /* nr of calls */
-    proftime_T uf_tm_total;    /* time spent in function + children */
-    proftime_T uf_tm_self;     /* time spent in function itself */
-    proftime_T uf_tm_children; /* time spent in children this call */
-    /* profiling the function per line */
-    int                *uf_tml_count;  /* nr of times line was executed */
-    proftime_T *uf_tml_total;  /* time spent in a line + children */
-    proftime_T *uf_tml_self;   /* time spent in a line itself */
-    proftime_T uf_tml_start;   /* start time for current line */
-    proftime_T uf_tml_children; /* time spent in children for this line */
-    proftime_T uf_tml_wait;    /* start wait time for current line */
-    int                uf_tml_idx;     /* index of line being timed; -1 if none */
-    int                uf_tml_execed;  /* line being timed was executed */
-#endif
-    scid_T     uf_script_ID;   /* ID of script where function was defined,
-                                  used for s: variables */
-    int                uf_refcount;    /* for numbered function: reference count */
-    funccall_T *uf_scoped;     /* l: local variables for closure */
-    char_u     uf_name[1];     /* name of function (actually longer); can
-                                  start with <SNR>123_ (<SNR> is K_SPECIAL
-                                  KS_EXTRA KE_SNR) */
-};
-
 /* function flags */
 #define FC_ABORT    1          /* abort function on error */
 #define FC_RANGE    2          /* function accepts range */
 #define FC_DICT            4           /* Dict function, uses "self" */
 #define FC_CLOSURE  8          /* closure, uses outer scope variables */
+#define FC_DELETED  16         /* :delfunction used while uf_refcount > 0 */
 
 /* From user function to hashitem and back. */
 #define UF2HIKEY(fp) ((fp)->uf_name)
@@ -69,52 +29,6 @@ struct ufunc
 #define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
 #define FUNCLINE(fp, j)        ((char_u **)(fp->uf_lines.ga_data))[j]
 
-#define MAX_FUNC_ARGS  20      /* maximum number of function arguments */
-#define VAR_SHORT_LEN  20      /* short variable name length */
-#define FIXVAR_CNT     12      /* number of fixed variables */
-
-/* structure to hold info for a function that is currently being executed. */
-struct funccall_S
-{
-    ufunc_T    *func;          /* function being called */
-    int                linenr;         /* next line to be executed */
-    int                returned;       /* ":return" used */
-    struct                     /* fixed variables for arguments */
-    {
-       dictitem_T      var;            /* variable (without room for name) */
-       char_u  room[VAR_SHORT_LEN];    /* room for the name */
-    } fixvar[FIXVAR_CNT];
-    dict_T     l_vars;         /* l: local function variables */
-    dictitem_T l_vars_var;     /* variable for l: scope */
-    dict_T     l_avars;        /* a: argument variables */
-    dictitem_T l_avars_var;    /* variable for a: scope */
-    list_T     l_varlist;      /* list for a:000 */
-    listitem_T l_listitems[MAX_FUNC_ARGS];     /* listitems for a:000 */
-    typval_T   *rettv;         /* return value */
-    linenr_T   breakpoint;     /* next line with breakpoint or zero */
-    int                dbg_tick;       /* debug_tick when breakpoint was set */
-    int                level;          /* top nesting level of executed function */
-#ifdef FEAT_PROFILE
-    proftime_T prof_child;     /* time spent in a child */
-#endif
-    funccall_T *caller;        /* calling function or NULL */
-
-    /* for closure */
-    int                fc_refcount;
-    int                fc_copyID;      /* for garbage collection */
-    garray_T   fc_funcs;       /* list of ufunc_T* which refer this */
-};
-
-/*
- * Struct used by trans_function_name()
- */
-typedef struct
-{
-    dict_T     *fd_dict;       /* Dictionary used */
-    char_u     *fd_newkey;     /* new key in "dict" in allocated memory */
-    dictitem_T *fd_di;         /* Dictionary item used */
-} funcdict_T;
-
 /*
  * All user-defined functions are found in this hashtable.
  */
@@ -271,7 +185,7 @@ register_closure(ufunc_T *fp)
        return FAIL;
     ((ufunc_T **)current_funccal->fc_funcs.ga_data)
        [current_funccal->fc_funcs.ga_len++] = fp;
-    func_ref(current_funccal->func->uf_name);
+    func_ptr_ref(current_funccal->func);
     return OK;
 }
 
@@ -288,7 +202,6 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
     ufunc_T    *fp = NULL;
     int                varargs;
     int                ret;
-    char_u     name[20];
     char_u     *start = skipwhite(*arg + 1);
     char_u     *s, *e;
     static int lambda_no = 0;
@@ -331,14 +244,22 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
 
     if (evaluate)
     {
-       int     len, flags = 0;
-       char_u  *p;
+       int         len, flags = 0;
+       char_u      *p;
+       char_u      name[20];
+       partial_T   *pt;
 
        sprintf((char*)name, "<lambda>%d", ++lambda_no);
 
        fp = (ufunc_T *)alloc_clear((unsigned)(sizeof(ufunc_T) + STRLEN(name)));
        if (fp == NULL)
            goto errret;
+       pt = (partial_T *)alloc_clear((unsigned)sizeof(partial_T));
+       if (pt == NULL)
+       {
+           vim_free(fp);
+           goto errret;
+       }
 
        ga_init2(&newlines, (int)sizeof(char_u *), 1);
        if (ga_grow(&newlines, 1) == FAIL)
@@ -380,8 +301,10 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
        fp->uf_calls = 0;
        fp->uf_script_ID = current_SID;
 
-       rettv->vval.v_string = vim_strsave(name);
-       rettv->v_type = VAR_FUNC;
+       pt->pt_func = fp;
+       pt->pt_refcount = 1;
+       rettv->vval.v_partial = pt;
+       rettv->v_type = VAR_PARTIAL;
     }
 
     eval_lavars_used = old_eval_lavars;
@@ -406,6 +329,7 @@ deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload)
 {
     dictitem_T *v;
     int                cc;
+    char_u     *s;
 
     if (partialp != NULL)
        *partialp = NULL;
@@ -421,8 +345,9 @@ deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload)
            *lenp = 0;
            return (char_u *)"";        /* just in case */
        }
-       *lenp = (int)STRLEN(v->di_tv.vval.v_string);
-       return v->di_tv.vval.v_string;
+       s = v->di_tv.vval.v_string;
+       *lenp = (int)STRLEN(s);
+       return s;
     }
 
     if (v != NULL && v->di_tv.v_type == VAR_PARTIAL)
@@ -436,8 +361,9 @@ deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload)
        }
        if (partialp != NULL)
            *partialp = pt;
-       *lenp = (int)STRLEN(pt->pt_name);
-       return pt->pt_name;
+       s = partial_name(pt);
+       *lenp = (int)STRLEN(s);
+       return s;
     }
 
     return name;
@@ -611,7 +537,7 @@ fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
  * Find a function by name, return pointer to it in ufuncs.
  * Return NULL for unknown function.
  */
-    static ufunc_T *
+    ufunc_T *
 find_func(char_u *name)
 {
     hashitem_T *hi;
@@ -678,7 +604,7 @@ free_funccal(
             * funccall_T, don't clear it then. */
            if (fp->uf_scoped == fc)
                fp->uf_scoped = NULL;
-           func_unref(fc->func->uf_name);
+           func_ptr_unref(fc->func);
        }
     }
     ga_clear(&fc->fc_funcs);
@@ -695,7 +621,7 @@ free_funccal(
        for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next)
            clear_tv(&li->li_tv);
 
-    func_unref(fc->func->uf_name);
+    func_ptr_unref(fc->func);
     vim_free(fc);
 }
 
@@ -759,7 +685,7 @@ call_user_func(
     fc->fc_refcount = 0;
     fc->fc_copyID = 0;
     ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
-    func_ref(fp->uf_name);
+    func_ptr_ref(fp);
 
     if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
        islambda = TRUE;
@@ -1112,24 +1038,25 @@ funccal_unref(funccall_T *fc, ufunc_T *fp)
 
     if (--fc->fc_refcount <= 0)
     {
-       for (pfc = &previous_funccal; *pfc != NULL; )
+       for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller)
        {
-           if (fc == *pfc
-                   && fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT
+           if (fc == *pfc)
+           {
+               if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT
                    && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT
                    && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT)
-           {
-               *pfc = fc->caller;
-               free_funccal(fc, TRUE);
-               freed = TRUE;
+               {
+                   *pfc = fc->caller;
+                   free_funccal(fc, TRUE);
+                   freed = TRUE;
+               }
+               break;
            }
-           else
-               pfc = &(*pfc)->caller;
        }
     }
     if (!freed)
     {
-       func_unref(fc->func->uf_name);
+       func_ptr_unref(fc->func);
 
        if (fp != NULL)
            for (i = 0; i < fc->fc_funcs.ga_len; ++i)
@@ -1140,14 +1067,25 @@ funccal_unref(funccall_T *fc, ufunc_T *fp)
     }
 }
 
+/*
+ * Remove the function from the function hashtable.  If the function was
+ * deleted while it still has references this was already done.
+ */
+    static void
+func_remove(ufunc_T *fp)
+{
+    hashitem_T *hi = hash_find(&func_hashtab, UF2HIKEY(fp));
+
+    if (!HASHITEM_EMPTY(hi))
+       hash_remove(&func_hashtab, hi);
+}
+
 /*
  * Free a function and remove it from the list of functions.
  */
     static void
 func_free(ufunc_T *fp)
 {
-    hashitem_T *hi;
-
     /* clear this function */
     ga_clear_strings(&(fp->uf_args));
     ga_clear_strings(&(fp->uf_lines));
@@ -1156,13 +1094,7 @@ func_free(ufunc_T *fp)
     vim_free(fp->uf_tml_total);
     vim_free(fp->uf_tml_self);
 #endif
-
-    /* remove the function from the function hashtable */
-    hi = hash_find(&func_hashtab, UF2HIKEY(fp));
-    if (HASHITEM_EMPTY(hi))
-       EMSG2(_(e_intern2), "func_free()");
-    else
-       hash_remove(&func_hashtab, hi);
+    func_remove(fp);
 
     funccal_unref(fp->uf_scoped, fp);
 
@@ -1333,7 +1265,10 @@ call_func(
            /*
             * User defined function.
             */
-           fp = find_func(rfname);
+           if (partial != NULL && partial->pt_func != NULL)
+               fp = partial->pt_func;
+           else
+               fp = find_func(rfname);
 
 #ifdef FEAT_AUTOCMD
            /* Trigger FuncUndefined event, may load the function. */
@@ -1353,7 +1288,9 @@ call_func(
                fp = find_func(rfname);
            }
 
-           if (fp != NULL)
+           if (fp != NULL && (fp->uf_flags & FC_DELETED))
+               error = ERROR_DELETED;
+           else if (fp != NULL)
            {
                if (argv_func != NULL)
                    argcount = argv_func(argcount, argvars, fp->uf_args.ga_len);
@@ -1387,9 +1324,7 @@ call_func(
                    call_user_func(fp, argcount, argvars, rettv,
                                               firstline, lastline,
                                  (fp->uf_flags & FC_DICT) ? selfdict : NULL);
-                   if (--fp->uf_calls <= 0 && (isdigit(*fp->uf_name)
-                               || STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
-                                                     && fp->uf_refcount <= 0)
+                   if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
                        /* Function was unreferenced while being used, free it
                         * now. */
                        func_free(fp);
@@ -1433,6 +1368,9 @@ call_func(
            case ERROR_UNKNOWN:
                    emsg_funcname(N_("E117: Unknown function: %s"), name);
                    break;
+           case ERROR_DELETED:
+                   emsg_funcname(N_("E933: Function was deleted: %s"), name);
+                   break;
            case ERROR_TOOMANY:
                    emsg_funcname((char *)e_toomanyarg, name);
                    break;
@@ -1516,7 +1454,7 @@ list_func_head(ufunc_T *fp, int indent)
  * TFN_NO_DEREF:    do not dereference a Funcref
  * Advances "pp" to just after the function name (if no error).
  */
-    static char_u *
+    char_u *
 trans_function_name(
     char_u     **pp,
     int                skip,           /* only find the end, don't evaluate */
@@ -1595,7 +1533,7 @@ trans_function_name(
        else if (lv.ll_tv->v_type == VAR_PARTIAL
                                          && lv.ll_tv->vval.v_partial != NULL)
        {
-           name = vim_strsave(lv.ll_tv->vval.v_partial->pt_name);
+           name = vim_strsave(partial_name(lv.ll_tv->vval.v_partial));
            *pp = end;
            if (partial != NULL)
                *partial = lv.ll_tv->vval.v_partial;
@@ -1752,6 +1690,7 @@ ex_function(exarg_T *eap)
     int                varargs = FALSE;
     int                flags = 0;
     ufunc_T    *fp;
+    int                overwrite = FALSE;
     int                indent;
     int                nesting;
     char_u     *skip_until = NULL;
@@ -2214,11 +2153,22 @@ ex_function(exarg_T *eap)
                                                                        name);
                goto erret;
            }
-           /* redefine existing function */
-           ga_clear_strings(&(fp->uf_args));
-           ga_clear_strings(&(fp->uf_lines));
-           vim_free(name);
-           name = NULL;
+           if (fp->uf_refcount > 1)
+           {
+               /* This function is referenced somewhere, don't redefine it but
+                * create a new one. */
+               --fp->uf_refcount;
+               fp = NULL;
+               overwrite = TRUE;
+           }
+           else
+           {
+               /* redefine existing function */
+               ga_clear_strings(&(fp->uf_args));
+               ga_clear_strings(&(fp->uf_lines));
+               vim_free(name);
+               name = NULL;
+           }
        }
     }
     else
@@ -2308,7 +2258,6 @@ ex_function(exarg_T *eap)
            fudi.fd_di->di_tv.v_type = VAR_FUNC;
            fudi.fd_di->di_tv.v_lock = 0;
            fudi.fd_di->di_tv.vval.v_string = vim_strsave(name);
-           fp->uf_refcount = 1;
 
            /* behave like "dict" was used */
            flags |= FC_DICT;
@@ -2316,17 +2265,22 @@ ex_function(exarg_T *eap)
 
        /* insert the new function in the function list */
        STRCPY(fp->uf_name, name);
-       if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL)
+       if (overwrite)
+       {
+           hi = hash_find(&func_hashtab, name);
+           hi->hi_key = UF2HIKEY(fp);
+       }
+       else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL)
        {
            vim_free(fp);
            goto erret;
        }
+       fp->uf_refcount = 1;
     }
     fp->uf_args = newargs;
     fp->uf_lines = newlines;
     if ((flags & FC_CLOSURE) != 0)
     {
-       ++fp->uf_refcount;
        if (register_closure(fp) == FAIL)
            goto erret;
     }
@@ -2750,13 +2704,30 @@ ex_delfunction(exarg_T *eap)
            dictitem_remove(fudi.fd_dict, fudi.fd_di);
        }
        else
-           func_free(fp);
+       {
+           /* Normal functions (not numbered functions and lambdas) have a
+            * refcount of 1 for the entry in the hashtable.  When deleting
+            * them and the refcount is more than one, it should be kept.
+            * Numbered functions and lambdas snould be kept if the refcount is
+            * one or more. */
+           if (fp->uf_refcount > (isdigit(fp->uf_name[0])
+                                            || fp->uf_name[0] == '<') ? 0 : 1)
+           {
+               /* Function is still referenced somewhere.  Don't free it but
+                * do remove it from the hashtable. */
+               func_remove(fp);
+               fp->uf_flags |= FC_DELETED;
+               fp->uf_refcount--;
+           }
+           else
+               func_free(fp);
+       }
     }
 }
 
 /*
  * Unreference a Function: decrement the reference count and free it when it
- * becomes zero.  Only for numbered functions.
+ * becomes zero.
  */
     void
 func_unref(char_u *name)
@@ -2765,22 +2736,30 @@ func_unref(char_u *name)
 
     if (name == NULL)
        return;
-    if (isdigit(*name))
+    fp = find_func(name);
+    if (fp == NULL && isdigit(*name))
     {
-       fp = find_func(name);
-       if (fp == NULL)
-       {
 #ifdef EXITFREE
-           if (!entered_free_all_mem)
+       if (!entered_free_all_mem)
 #endif
-               EMSG2(_(e_intern2), "func_unref()");
-       }
+           EMSG2(_(e_intern2), "func_unref()");
     }
-    else if (STRNCMP(name, "<lambda>", 8) == 0)
+    if (fp != NULL && --fp->uf_refcount <= 0)
     {
-       /* fail silently, when lambda function isn't found. */
-       fp = find_func(name);
+       /* Only delete it when it's not being used.  Otherwise it's done
+        * when "uf_calls" becomes zero. */
+       if (fp->uf_calls == 0)
+           func_free(fp);
     }
+}
+
+/*
+ * Unreference a Function: decrement the reference count and free it when it
+ * becomes zero.
+ */
+    void
+func_ptr_unref(ufunc_T *fp)
+{
     if (fp != NULL && --fp->uf_refcount <= 0)
     {
        /* Only delete it when it's not being used.  Otherwise it's done
@@ -2800,21 +2779,23 @@ func_ref(char_u *name)
 
     if (name == NULL)
        return;
+    fp = find_func(name);
+    if (fp != NULL)
+       ++fp->uf_refcount;
     else if (isdigit(*name))
-    {
-       fp = find_func(name);
-       if (fp == NULL)
-           EMSG2(_(e_intern2), "func_ref()");
-       else
-           ++fp->uf_refcount;
-    }
-    else if (STRNCMP(name, "<lambda>", 8) == 0)
-    {
-       /* fail silently, when lambda function isn't found. */
-       fp = find_func(name);
-       if (fp != NULL)
-           ++fp->uf_refcount;
-    }
+       /* Only give an error for a numbered function.
+        * Fail silently, when named or lambda function isn't found. */
+       EMSG2(_(e_intern2), "func_ref()");
+}
+
+/*
+ * Count a reference to a Function.
+ */
+    void
+func_ptr_ref(ufunc_T *fp)
+{
+    if (fp != NULL)
+       ++fp->uf_refcount;
 }
 
 /*
@@ -3298,18 +3279,24 @@ func_has_abort(
     dict_T *
 make_partial(dict_T *selfdict_in, typval_T *rettv)
 {
-    char_u     *fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
-                                        : rettv->vval.v_partial->pt_name;
+    char_u     *fname;
     char_u     *tofree = NULL;
     ufunc_T    *fp;
     char_u     fname_buf[FLEN_FIXED + 1];
     int                error;
     dict_T     *selfdict = selfdict_in;
 
-    /* Translate "s:func" to the stored function name. */
-    fname = fname_trans_sid(fname, fname_buf, &tofree, &error);
-    fp = find_func(fname);
-    vim_free(tofree);
+    if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func != NULL)
+       fp = rettv->vval.v_partial->pt_func;
+    else
+    {
+       fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
+                                             : 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);
+       vim_free(tofree);
+    }
 
     if (fp != NULL && (fp->uf_flags & FC_DICT))
     {
@@ -3335,8 +3322,16 @@ make_partial(dict_T *selfdict_in, typval_T *rettv)
                /* Partial: copy the function name, use selfdict and copy
                 * args.  Can't take over name or args, the partial might
                 * be referenced elsewhere. */
-               pt->pt_name = vim_strsave(ret_pt->pt_name);
-               func_ref(pt->pt_name);
+               if (ret_pt->pt_name != NULL)
+               {
+                   pt->pt_name = vim_strsave(ret_pt->pt_name);
+                   func_ref(pt->pt_name);
+               }
+               else
+               {
+                   pt->pt_func = ret_pt->pt_func;
+                   func_ptr_ref(pt->pt_func);
+               }
                if (ret_pt->pt_argc > 0)
                {
                    pt->pt_argv = (typval_T *)alloc(
@@ -3703,20 +3698,23 @@ set_ref_in_func_args(int copyID)
  * Returns TRUE if setting references failed somehow.
  */
     int
-set_ref_in_func(char_u *name, int copyID)
+set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
 {
-    ufunc_T    *fp;
+    ufunc_T    *fp = fp_in;
     funccall_T *fc;
     int                error = ERROR_NONE;
     char_u     fname_buf[FLEN_FIXED + 1];
     char_u     *tofree = NULL;
     char_u     *fname;
 
-    if (name == NULL)
+    if (name == NULL && fp_in == NULL)
        return FALSE;
 
-    fname = fname_trans_sid(name, fname_buf, &tofree, &error);
-    fp = find_func(fname);
+    if (fp_in == NULL)
+    {
+       fname = fname_trans_sid(name, fname_buf, &tofree, &error);
+       fp = find_func(fname);
+    }
     if (fp != NULL)
     {
        for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped)
index 7e1b45aa887c0efaf3322ee1a45fac222ca54ffb..474b3b542c4cbccd999648fa4c56dbaf56e69c6b 100644 (file)
@@ -763,6 +763,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2137,
 /**/
     2136,
 /**/
index 34a8650c4900c698ad51d7f1897c8150d3b327a7..18c3ff8507456ce14f8d3393df99ccbc23261af0 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -2475,6 +2475,7 @@ int vim_main2(int argc, char **argv);
 #define ERROR_DICT     4
 #define ERROR_NONE     5
 #define ERROR_OTHER    6
+#define ERROR_DELETED  7
 
 /* flags for find_name_end() */
 #define FNE_INCL_BR    1       /* include [] in name */