changeset 9723:80ac9cf77c9b v7.4.2137

commit https://github.com/vim/vim/commit/437bafe4c8a83ed71ee006eda7f54b65a90f0d4c Author: Bram Moolenaar <Bram@vim.org> Date: Mon Aug 1 15:40:54 2016 +0200 patch 7.4.2137 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.
author Christian Brabandt <cb@256bit.org>
date Mon, 01 Aug 2016 15:45:07 +0200
parents 1557241fd3a7
children 0d9cf1226b6a
files 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
diffstat 16 files changed, 450 insertions(+), 234 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -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 
 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
+funcref({name} [, {arglist}] [, {dict}])
+				Funcref	reference to function {name}
 function({name} [, {arglist}] [, {dict}])
-				Funcref	reference to function {name}
+				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 
 		{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
 			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|: >
--- a/src/channel.c
+++ b/src/channel.c
@@ -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 *op
 		++job->jv_exit_partial->pt_refcount;
 	    }
 	    else
+	    {
 		job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
+		func_ref(job->jv_exit_cb);
+	    }
 	}
     }
 }
--- a/src/eval.c
+++ b/src/eval.c
@@ -5011,6 +5011,17 @@ get_lit_string_tv(char_u **arg, typval_T
     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 *e
     {
 	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;
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -148,6 +148,7 @@ static void f_foldlevel(typval_T *argvar
 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 *rett
     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, t
 #endif
 }
 
-/*
- * "function()" function
- */
-    static void
-f_function(typval_T *argvars, typval_T *rettv)
+    static void
+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 *
     {
 	/* 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 *
 	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 *
 		{
 		    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 *
 		{
 		    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 *
 		    {
 			vim_free(pt);
 			vim_free(name);
-			return;
+			goto theend;
 		    }
-		    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++]);
-		    }
+		    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 *
 		}
 
 		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 *
 	    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
     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 = 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"));
--- a/src/if_mzsch.c
+++ b/src/if_mzsch.c
@@ -3134,7 +3134,7 @@ vim_to_mzscheme_impl(typval_T *vim_value
 	    /* 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);
--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -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);
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1217,16 +1217,20 @@ free_all_mem(void)
 	if (delete_first_msg() == FAIL)
 	    break;
 
+# ifdef FEAT_JOB_CHANNEL
+    channel_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
-    channel_free_all();
+    /* must be after eval_clear() with unrefs jobs */
     job_free_all();
 # endif
-#ifdef FEAT_TIMERS
-    timer_free_all();
-#endif
 
     free_termoptions();
 
--- a/src/proto/eval.pro
+++ b/src/proto/eval.pro
@@ -40,6 +40,7 @@ char_u *get_user_var_name(expand_T *xp, 
 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);
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -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
 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 : */
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -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);
--- a/src/structs.h
+++ b/src/structs.h
@@ -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 */
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -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
--- a/src/testdir/test_lambda.vim
+++ b/src/testdir/test_lambda.vim
@@ -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()
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -14,52 +14,12 @@
 #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 *re
     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 *re
 
     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 *re
 	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,
 {
     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,
 	    *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,
 	}
 	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 *fn
  * 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 *f
 
     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)
@@ -1141,13 +1068,24 @@ funccal_unref(funccall_T *fc, ufunc_T *f
 }
 
 /*
+ * 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()");
+    }
+    if (fp != NULL && --fp->uf_refcount <= 0)
+    {
+	/* 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);
     }
-    else if (STRNCMP(name, "<lambda>", 8) == 0)
-    {
-	/* fail silently, when lambda function isn't found. */
-	fp = find_func(name);
-    }
+}
+
+/*
+ * 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
 		/* 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)
--- a/src/version.c
+++ b/src/version.c
@@ -764,6 +764,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2137,
+/**/
     2136,
 /**/
     2135,
--- 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 */