Skip to content

Commit 9e63f61

Browse files
committed
patch 7.4.1589
Problem: Combining dict and args with partial doesn't always work. Solution: Use the arguments from the partial.
1 parent 1ff2b64 commit 9e63f61

3 files changed

Lines changed: 68 additions & 12 deletions

File tree

src/eval.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3461,7 +3461,7 @@ ex_call(exarg_T *eap)
34613461
int doesrange;
34623462
int failed = FALSE;
34633463
funcdict_T fudi;
3464-
partial_T *partial;
3464+
partial_T *partial = NULL;
34653465

34663466
if (eap->skip)
34673467
{
@@ -3497,12 +3497,6 @@ ex_call(exarg_T *eap)
34973497
name = deref_func_name(tofree, &len,
34983498
partial != NULL ? NULL : &partial, FALSE);
34993499

3500-
/* When calling fdict.func(), where "func" is a partial, use "fdict"
3501-
* instead of the dict in the partial, for backwards compatibility.
3502-
* TODO: Do use the arguments in the partial? */
3503-
if (fudi.fd_dict != NULL)
3504-
partial = NULL;
3505-
35063500
/* Skip white space to allow ":call func ()". Not good, but required for
35073501
* backward compatibility. */
35083502
startarg = skipwhite(arg);
@@ -21734,17 +21728,18 @@ handle_subscript(
2173421728
}
2173521729
}
2173621730

21737-
if (rettv->v_type == VAR_FUNC && selfdict != NULL)
21731+
if ((rettv->v_type == VAR_FUNC || rettv->v_type == VAR_PARTIAL)
21732+
&& selfdict != NULL)
2173821733
{
21739-
char_u *fname;
21734+
char_u *fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
21735+
: rettv->vval.v_partial->pt_name;
2174021736
char_u *tofree = NULL;
2174121737
ufunc_T *fp;
2174221738
char_u fname_buf[FLEN_FIXED + 1];
2174321739
int error;
2174421740

2174521741
/* Translate "s:func" to the stored function name. */
21746-
fname = fname_trans_sid(rettv->vval.v_string, fname_buf,
21747-
&tofree, &error);
21742+
fname = fname_trans_sid(fname, fname_buf, &tofree, &error);
2174821743
fp = find_func(fname);
2174921744
vim_free(tofree);
2175021745

@@ -21758,7 +21753,34 @@ handle_subscript(
2175821753
pt->pt_refcount = 1;
2175921754
pt->pt_dict = selfdict;
2176021755
selfdict = NULL;
21761-
pt->pt_name = rettv->vval.v_string;
21756+
if (rettv->v_type == VAR_FUNC)
21757+
{
21758+
/* just a function: use selfdict */
21759+
pt->pt_name = rettv->vval.v_string;
21760+
}
21761+
else
21762+
{
21763+
partial_T *ret_pt = rettv->vval.v_partial;
21764+
int i;
21765+
21766+
/* partial: use selfdict and copy args */
21767+
pt->pt_name = vim_strsave(ret_pt->pt_name);
21768+
if (ret_pt->pt_argc > 0)
21769+
{
21770+
pt->pt_argv = (typval_T *)alloc(
21771+
sizeof(typval_T) * ret_pt->pt_argc);
21772+
if (pt->pt_argv == NULL)
21773+
/* out of memory: drop the arguments */
21774+
pt->pt_argc = 0;
21775+
else
21776+
{
21777+
pt->pt_argc = ret_pt->pt_argc;
21778+
for (i = 0; i < pt->pt_argc; i++)
21779+
copy_tv(&ret_pt->pt_argv[i], &pt->pt_argv[i]);
21780+
}
21781+
}
21782+
partial_unref(ret_pt);
21783+
}
2176221784
func_ref(pt->pt_name);
2176321785
rettv->v_type = VAR_PARTIAL;
2176421786
rettv->vval.v_partial = pt;
@@ -23915,6 +23937,8 @@ trans_function_name(
2391523937
{
2391623938
name = vim_strsave(lv.ll_tv->vval.v_partial->pt_name);
2391723939
*pp = end;
23940+
if (partial != NULL)
23941+
*partial = lv.ll_tv->vval.v_partial;
2391823942
}
2391923943
else
2392023944
{

src/testdir/test_partial.vim

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,36 @@ func Test_script_function_in_dict()
115115
call assert_equal('bar', B())
116116
endfunc
117117

118+
function! s:cache_arg(arg) dict
119+
let s:result = self.name . '/' . a:arg
120+
return s:result
121+
endfunction
122+
123+
func Test_script_function_in_dict_arg()
124+
let s:obj = {'name': 'foo'}
125+
let s:obj['clear'] = function('s:cache_arg')
126+
127+
call assert_equal('foo/bar', s:obj.clear('bar'))
128+
let F = s:obj.clear
129+
let s:result = ''
130+
call assert_equal('foo/bar', F('bar'))
131+
call assert_equal('foo/bar', s:result)
132+
133+
let s:obj['clear'] = function('s:cache_arg', ['bar'])
134+
call assert_equal('foo/bar', s:obj.clear())
135+
let s:result = ''
136+
call s:obj.clear()
137+
call assert_equal('foo/bar', s:result)
138+
139+
let F = s:obj.clear
140+
call assert_equal('foo/bar', F())
141+
let s:result = ''
142+
call F()
143+
call assert_equal('foo/bar', s:result)
144+
145+
call assert_equal('foo/bar', call(s:obj.clear, [], s:obj))
146+
endfunc
147+
118148
func Test_partial_exists()
119149
let F = function('MyFunc')
120150
call assert_true(exists('*F'))

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+
1589,
751753
/**/
752754
1588,
753755
/**/

0 commit comments

Comments
 (0)