Skip to content

Commit 437bafe

Browse files
committed
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.
1 parent 5801644 commit 437bafe

16 files changed

Lines changed: 447 additions & 231 deletions

File tree

runtime/doc/eval.txt

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*eval.txt* For Vim version 7.4. Last change: 2016 Jul 29
1+
*eval.txt* For Vim version 7.4. Last change: 2016 Jul 31
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1240,7 +1240,9 @@ function returns: >
12401240
:let Bar = Foo(4)
12411241
:echo Bar(6)
12421242
< 5
1243-
See also |:func-closure|.
1243+
1244+
See also |:func-closure|. Lambda and closure support can be checked with: >
1245+
if has('lambda')
12441246
12451247
Examples for using a lambda expression with |sort()|, |map()| and |filter()|: >
12461248
:echo map([1, 2, 3], {idx, val -> val + 1})
@@ -2071,8 +2073,10 @@ foldlevel({lnum}) Number fold level at {lnum}
20712073
foldtext() String line displayed for closed fold
20722074
foldtextresult({lnum}) String text for closed fold at {lnum}
20732075
foreground() Number bring the Vim window to the foreground
2074-
function({name} [, {arglist}] [, {dict}])
2076+
funcref({name} [, {arglist}] [, {dict}])
20752077
Funcref reference to function {name}
2078+
function({name} [, {arglist}] [, {dict}])
2079+
Funcref named reference to function {name}
20762080
garbagecollect([{atexit}]) none free memory, breaking cyclic references
20772081
get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
20782082
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
@@ -3850,19 +3854,32 @@ foreground() Move the Vim window to the foreground. Useful when sent from
38503854
{only in the Win32, Athena, Motif and GTK GUI versions and the
38513855
Win32 console version}
38523856

3857+
*funcref()*
3858+
funcref({name} [, {arglist}] [, {dict}])
3859+
Just like |function()|, but the returned Funcref will lookup
3860+
the function by reference, not by name. This matters when the
3861+
function {name} is redefined later.
3862+
3863+
Unlike |function()|, {name} must be an existing user function.
3864+
Also for autoloaded functions. {name} cannot be a builtin
3865+
function.
38533866

38543867
*function()* *E700* *E922* *E923*
38553868
function({name} [, {arglist}] [, {dict}])
38563869
Return a |Funcref| variable that refers to function {name}.
38573870
{name} can be the name of a user defined function or an
38583871
internal function.
38593872

3860-
{name} can also be a Funcref, also a partial. When it is a
3873+
{name} can also be a Funcref or a partial. When it is a
38613874
partial the dict stored in it will be used and the {dict}
38623875
argument is not allowed. E.g.: >
38633876
let FuncWithArg = function(dict.Func, [arg])
38643877
let Broken = function(dict.Func, [arg], dict)
38653878
<
3879+
When using the Funcref the function will be found by {name},
3880+
also when it was redefined later. Use |funcref()| to keep the
3881+
same function.
3882+
38663883
When {arglist} or {dict} is present this creates a partial.
38673884
That means the argument list and/or the dictionary is stored in
38683885
the Funcref and will be used when the Funcref is called.
@@ -6191,6 +6208,7 @@ screenrow() *screenrow()*
61916208
The result is a Number, which is the current screen row of the
61926209
cursor. The top line has number one.
61936210
This function is mainly used for testing.
6211+
Alternatively you can use |winline()|.
61946212

61956213
Note: Same restrictions as with |screencol()|.
61966214

@@ -8039,6 +8057,7 @@ insert_expand Compiled with support for CTRL-X expansion commands in
80398057
Insert mode.
80408058
jumplist Compiled with |jumplist| support.
80418059
keymap Compiled with 'keymap' support.
8060+
lambda Compiled with |lambda| support.
80428061
langmap Compiled with 'langmap' support.
80438062
libcall Compiled with |libcall()| support.
80448063
linebreak Compiled with 'linebreak', 'breakat', 'showbreak' and
@@ -8294,7 +8313,7 @@ See |:verbose-cmd| for more information.
82948313
:endf[unction] The end of a function definition. Must be on a line
82958314
by its own, without other commands.
82968315

8297-
*:delf* *:delfunction* *E130* *E131*
8316+
*:delf* *:delfunction* *E130* *E131* *E933*
82988317
:delf[unction] {name} Delete function {name}.
82998318
{name} can also be a |Dictionary| entry that is a
83008319
|Funcref|: >

src/channel.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,15 +1124,18 @@ set_callback(
11241124
if (callback != NULL && *callback != NUL)
11251125
{
11261126
if (partial != NULL)
1127-
*cbp = partial->pt_name;
1127+
*cbp = partial_name(partial);
11281128
else
1129+
{
11291130
*cbp = vim_strsave(callback);
1131+
func_ref(*cbp);
1132+
}
11301133
}
11311134
else
11321135
*cbp = NULL;
11331136
*pp = partial;
1134-
if (*pp != NULL)
1135-
++(*pp)->pt_refcount;
1137+
if (partial != NULL)
1138+
++partial->pt_refcount;
11361139
}
11371140

11381141
/*
@@ -1279,7 +1282,10 @@ channel_set_req_callback(
12791282
item->cq_callback = callback;
12801283
}
12811284
else
1285+
{
12821286
item->cq_callback = vim_strsave(callback);
1287+
func_ref(item->cq_callback);
1288+
}
12831289
item->cq_seq_nr = id;
12841290
item->cq_prev = head->cq_prev;
12851291
head->cq_prev = item;
@@ -3923,14 +3929,24 @@ free_job_options(jobopt_T *opt)
39233929
{
39243930
if (opt->jo_partial != NULL)
39253931
partial_unref(opt->jo_partial);
3932+
else if (opt->jo_callback != NULL)
3933+
func_unref(opt->jo_callback);
39263934
if (opt->jo_out_partial != NULL)
39273935
partial_unref(opt->jo_out_partial);
3936+
else if (opt->jo_out_cb != NULL)
3937+
func_unref(opt->jo_out_cb);
39283938
if (opt->jo_err_partial != NULL)
39293939
partial_unref(opt->jo_err_partial);
3940+
else if (opt->jo_err_cb != NULL)
3941+
func_unref(opt->jo_err_cb);
39303942
if (opt->jo_close_partial != NULL)
39313943
partial_unref(opt->jo_close_partial);
3944+
else if (opt->jo_close_cb != NULL)
3945+
func_unref(opt->jo_close_cb);
39323946
if (opt->jo_exit_partial != NULL)
39333947
partial_unref(opt->jo_exit_partial);
3948+
else if (opt->jo_exit_cb != NULL)
3949+
func_unref(opt->jo_exit_cb);
39343950
}
39353951

39363952
/*
@@ -4476,7 +4492,10 @@ job_set_options(job_T *job, jobopt_T *opt)
44764492
++job->jv_exit_partial->pt_refcount;
44774493
}
44784494
else
4495+
{
44794496
job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
4497+
func_ref(job->jv_exit_cb);
4498+
}
44804499
}
44814500
}
44824501
}

src/eval.c

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5011,6 +5011,17 @@ get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
50115011
return OK;
50125012
}
50135013

5014+
/*
5015+
* Return the function name of the partial.
5016+
*/
5017+
char_u *
5018+
partial_name(partial_T *pt)
5019+
{
5020+
if (pt->pt_name != NULL)
5021+
return pt->pt_name;
5022+
return pt->pt_func->uf_name;
5023+
}
5024+
50145025
static void
50155026
partial_free(partial_T *pt)
50165027
{
@@ -5020,8 +5031,13 @@ partial_free(partial_T *pt)
50205031
clear_tv(&pt->pt_argv[i]);
50215032
vim_free(pt->pt_argv);
50225033
dict_unref(pt->pt_dict);
5023-
func_unref(pt->pt_name);
5024-
vim_free(pt->pt_name);
5034+
if (pt->pt_name != NULL)
5035+
{
5036+
func_unref(pt->pt_name);
5037+
vim_free(pt->pt_name);
5038+
}
5039+
else
5040+
func_ptr_unref(pt->pt_func);
50255041
vim_free(pt);
50265042
}
50275043

@@ -5051,11 +5067,11 @@ func_equal(
50515067

50525068
/* empty and NULL function name considered the same */
50535069
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
5054-
: tv1->vval.v_partial->pt_name;
5070+
: partial_name(tv1->vval.v_partial);
50555071
if (s1 != NULL && *s1 == NUL)
50565072
s1 = NULL;
50575073
s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
5058-
: tv2->vval.v_partial->pt_name;
5074+
: partial_name(tv2->vval.v_partial);
50595075
if (s2 != NULL && *s2 == NUL)
50605076
s2 = NULL;
50615077
if (s1 == NULL || s2 == NULL)
@@ -5550,7 +5566,7 @@ set_ref_in_item(
55505566
}
55515567
else if (tv->v_type == VAR_FUNC)
55525568
{
5553-
abort = set_ref_in_func(tv->vval.v_string, copyID);
5569+
abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
55545570
}
55555571
else if (tv->v_type == VAR_PARTIAL)
55565572
{
@@ -5561,7 +5577,7 @@ set_ref_in_item(
55615577
*/
55625578
if (pt != NULL)
55635579
{
5564-
abort = set_ref_in_func(pt->pt_name, copyID);
5580+
abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
55655581

55665582
if (pt->pt_dict != NULL)
55675583
{
@@ -5735,7 +5751,7 @@ echo_string_core(
57355751
{
57365752
partial_T *pt = tv->vval.v_partial;
57375753
char_u *fname = string_quote(pt == NULL ? NULL
5738-
: pt->pt_name, FALSE);
5754+
: partial_name(pt), FALSE);
57395755
garray_T ga;
57405756
int i;
57415757
char_u *tf;
@@ -6871,7 +6887,7 @@ handle_subscript(
68716887
if (functv.v_type == VAR_PARTIAL)
68726888
{
68736889
pt = functv.vval.v_partial;
6874-
s = pt->pt_name;
6890+
s = partial_name(pt);
68756891
}
68766892
else
68776893
s = functv.vval.v_string;
@@ -10025,7 +10041,7 @@ filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
1002510041
{
1002610042
partial_T *partial = expr->vval.v_partial;
1002710043

10028-
s = partial->pt_name;
10044+
s = partial_name(partial);
1002910045
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
1003010046
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
1003110047
goto theend;

0 commit comments

Comments
 (0)