Skip to content

Commit 6563903

Browse files
committed
patch 7.4.1581
Problem: Using ":call dict.func()" where the function is a partial does not work. Using "dict.func()" where the function does not take a Dictionary does not work. Solution: Handle partial properly in ":call". (Yasuhiro Matsumoto)
1 parent 7a5c46a commit 6563903

4 files changed

Lines changed: 56 additions & 30 deletions

File tree

src/eval.c

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ static int valid_varname(char_u *varname);
867867
static int tv_check_lock(int lock, char_u *name, int use_gettext);
868868
static int item_copy(typval_T *from, typval_T *to, int deep, int copyID);
869869
static char_u *find_option_end(char_u **arg, int *opt_flags);
870-
static char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fd);
870+
static char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fd, partial_T **partial);
871871
static int eval_fname_script(char_u *p);
872872
static int eval_fname_sid(char_u *p);
873873
static void list_func_head(ufunc_T *fp, int indent);
@@ -3476,7 +3476,7 @@ ex_call(exarg_T *eap)
34763476
return;
34773477
}
34783478

3479-
tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
3479+
tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial);
34803480
if (fudi.fd_newkey != NULL)
34813481
{
34823482
/* Still need to give an error message for missing key. */
@@ -3491,9 +3491,18 @@ ex_call(exarg_T *eap)
34913491
if (fudi.fd_dict != NULL)
34923492
++fudi.fd_dict->dv_refcount;
34933493

3494-
/* If it is the name of a variable of type VAR_FUNC use its contents. */
3494+
/* If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its
3495+
* contents. For VAR_PARTIAL get its partial, unless we already have one
3496+
* from trans_function_name(). */
34953497
len = (int)STRLEN(tofree);
3496-
name = deref_func_name(tofree, &len, &partial, FALSE);
3498+
name = deref_func_name(tofree, &len,
3499+
partial != NULL ? NULL : &partial, FALSE);
3500+
3501+
/* When calling fdict.func(), where "func" is a partial, use "fdict"
3502+
* instead of the dict in the partial, for backwards compatibility.
3503+
* TODO: Do use the arguments in the partial? */
3504+
if (fudi.fd_dict != NULL)
3505+
partial = NULL;
34973506

34983507
/* Skip white space to allow ":call func ()". Not good, but required for
34993508
* backward compatibility. */
@@ -8561,15 +8570,17 @@ find_internal_func(
85618570
/*
85628571
* Check if "name" is a variable of type VAR_FUNC. If so, return the function
85638572
* name it contains, otherwise return "name".
8564-
* If "name" is of type VAR_PARTIAL also return "partial"
8573+
* If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set
8574+
* "partialp".
85658575
*/
85668576
static char_u *
8567-
deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload)
8577+
deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload)
85688578
{
85698579
dictitem_T *v;
85708580
int cc;
85718581

8572-
*partial = NULL;
8582+
if (partialp != NULL)
8583+
*partialp = NULL;
85738584

85748585
cc = name[*lenp];
85758586
name[*lenp] = NUL;
@@ -8588,14 +8599,17 @@ deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload)
85888599

85898600
if (v != NULL && v->di_tv.v_type == VAR_PARTIAL)
85908601
{
8591-
*partial = v->di_tv.vval.v_partial;
8592-
if (*partial == NULL)
8602+
partial_T *pt = v->di_tv.vval.v_partial;
8603+
8604+
if (pt == NULL)
85938605
{
85948606
*lenp = 0;
85958607
return (char_u *)""; /* just in case */
85968608
}
8597-
*lenp = (int)STRLEN((*partial)->pt_name);
8598-
return (*partial)->pt_name;
8609+
if (partialp != NULL)
8610+
*partialp = pt;
8611+
*lenp = (int)STRLEN(pt->pt_name);
8612+
return pt->pt_name;
85998613
}
86008614

86018615
return name;
@@ -21700,18 +21714,23 @@ handle_subscript(
2170021714

2170121715
if (rettv->v_type == VAR_FUNC && selfdict != NULL)
2170221716
{
21703-
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
21717+
ufunc_T *fp = find_func(rettv->vval.v_string);
2170421718

2170521719
/* Turn "dict.Func" into a partial for "Func" with "dict". */
21706-
if (pt != NULL)
21720+
if (fp != NULL && (fp->uf_flags & FC_DICT))
2170721721
{
21708-
pt->pt_refcount = 1;
21709-
pt->pt_dict = selfdict;
21710-
selfdict = NULL;
21711-
pt->pt_name = rettv->vval.v_string;
21712-
func_ref(pt->pt_name);
21713-
rettv->v_type = VAR_PARTIAL;
21714-
rettv->vval.v_partial = pt;
21722+
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
21723+
21724+
if (pt != NULL)
21725+
{
21726+
pt->pt_refcount = 1;
21727+
pt->pt_dict = selfdict;
21728+
selfdict = NULL;
21729+
pt->pt_name = rettv->vval.v_string;
21730+
func_ref(pt->pt_name);
21731+
rettv->v_type = VAR_PARTIAL;
21732+
rettv->vval.v_partial = pt;
21733+
}
2171521734
}
2171621735
}
2171721736

@@ -23220,7 +23239,7 @@ ex_function(exarg_T *eap)
2322023239
* g:func global function name, same as "func"
2322123240
*/
2322223241
p = eap->arg;
23223-
name = trans_function_name(&p, eap->skip, 0, &fudi);
23242+
name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
2322423243
paren = (vim_strchr(p, '(') != NULL);
2322523244
if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
2322623245
{
@@ -23533,7 +23552,7 @@ ex_function(exarg_T *eap)
2353323552
if (*p == '!')
2353423553
p = skipwhite(p + 1);
2353523554
p += eval_fname_script(p);
23536-
vim_free(trans_function_name(&p, TRUE, 0, NULL));
23555+
vim_free(trans_function_name(&p, TRUE, 0, NULL, NULL));
2353723556
if (*skipwhite(p) == '(')
2353823557
{
2353923558
++nesting;
@@ -23788,7 +23807,8 @@ trans_function_name(
2378823807
char_u **pp,
2378923808
int skip, /* only find the end, don't evaluate */
2379023809
int flags,
23791-
funcdict_T *fdp) /* return: info about dictionary used */
23810+
funcdict_T *fdp, /* return: info about dictionary used */
23811+
partial_T **partial) /* return: partial of a FuncRef */
2379223812
{
2379323813
char_u *name = NULL;
2379423814
char_u *start;
@@ -23797,7 +23817,6 @@ trans_function_name(
2379723817
char_u sid_buf[20];
2379823818
int len;
2379923819
lval_T lv;
23800-
partial_T *partial;
2380123820

2380223821
if (fdp != NULL)
2380323822
vim_memset(fdp, 0, sizeof(funcdict_T));
@@ -23882,15 +23901,15 @@ trans_function_name(
2388223901
if (lv.ll_exp_name != NULL)
2388323902
{
2388423903
len = (int)STRLEN(lv.ll_exp_name);
23885-
name = deref_func_name(lv.ll_exp_name, &len, &partial,
23904+
name = deref_func_name(lv.ll_exp_name, &len, partial,
2388623905
flags & TFN_NO_AUTOLOAD);
2388723906
if (name == lv.ll_exp_name)
2388823907
name = NULL;
2388923908
}
2389023909
else
2389123910
{
2389223911
len = (int)(end - *pp);
23893-
name = deref_func_name(*pp, &len, &partial, flags & TFN_NO_AUTOLOAD);
23912+
name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD);
2389423913
if (name == *pp)
2389523914
name = NULL;
2389623915
}
@@ -24115,7 +24134,7 @@ function_exists(char_u *name)
2411524134
int n = FALSE;
2411624135

2411724136
p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD,
24118-
NULL);
24137+
NULL, NULL);
2411924138
nm = skipwhite(nm);
2412024139

2412124140
/* Only accept "funcname", "funcname ", "funcname (..." and
@@ -24132,7 +24151,7 @@ get_expanded_name(char_u *name, int check)
2413224151
char_u *nm = name;
2413324152
char_u *p;
2413424153

24135-
p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL);
24154+
p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL, NULL);
2413624155

2413724156
if (p != NULL && *nm == NUL)
2413824157
if (!check || translated_function_exists(p))
@@ -24488,7 +24507,7 @@ ex_delfunction(exarg_T *eap)
2448824507
funcdict_T fudi;
2448924508

2449024509
p = eap->arg;
24491-
name = trans_function_name(&p, eap->skip, 0, &fudi);
24510+
name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
2449224511
vim_free(fudi.fd_newkey);
2449324512
if (name == NULL)
2449424513
{

src/testdir/test55.ok

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ NONE 2999
4444
{'33': 999}
4545
len: 3
4646
again: 3
47-
Vim(call):E725:
47+
xxx3
4848
g:dict.func-4
4949
a:function('3')
5050
Vim(let):E698:

src/testdir/test_partial.vim

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ endfunc
1616

1717
func Test_partial_args()
1818
let Cb = function('MyFunc', ["foo", "bar"])
19+
20+
call Cb("zzz")
1921
call assert_equal("foo/bar/xxx", Cb("xxx"))
2022
call assert_equal("foo/bar/yyy", call(Cb, ["yyy"]))
2123

@@ -49,6 +51,9 @@ func Test_partial_dict()
4951
let Cb = function('MyDictFunc', dict)
5052
call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy"))
5153
call assert_fails('Cb("fff")', 'E492:')
54+
55+
let dict = {"tr": function('tr', ['hello', 'h', 'H'])}
56+
call assert_equal("Hello", dict.tr())
5257
endfunc
5358

5459
func Test_partial_implicit()

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,8 @@ static char *(features[]) =
748748

749749
static int included_patches[] =
750750
{ /* Add new patch number below this line */
751+
/**/
752+
1581,
751753
/**/
752754
1580,
753755
/**/

0 commit comments

Comments
 (0)