# HG changeset patch # User Christian Brabandt # Date 1458252905 -3600 # Node ID ddb04cbe1e0c6c333328dce5fa538e88b01d0d80 # Parent 1974ffbf43619c23e63a3301d5952142bb533bde commit https://github.com/vim/vim/commit/9e63f61cb01c70fd71652f54b2d01ee27b2a3534 Author: Bram Moolenaar Date: Thu Mar 17 23:13:28 2016 +0100 patch 7.4.1589 Problem: Combining dict and args with partial doesn't always work. Solution: Use the arguments from the partial. diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -3461,7 +3461,7 @@ ex_call(exarg_T *eap) int doesrange; int failed = FALSE; funcdict_T fudi; - partial_T *partial; + partial_T *partial = NULL; if (eap->skip) { @@ -3497,12 +3497,6 @@ ex_call(exarg_T *eap) name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial, FALSE); - /* When calling fdict.func(), where "func" is a partial, use "fdict" - * instead of the dict in the partial, for backwards compatibility. - * TODO: Do use the arguments in the partial? */ - if (fudi.fd_dict != NULL) - partial = NULL; - /* Skip white space to allow ":call func ()". Not good, but required for * backward compatibility. */ startarg = skipwhite(arg); @@ -21734,17 +21728,18 @@ handle_subscript( } } - if (rettv->v_type == VAR_FUNC && selfdict != NULL) - { - char_u *fname; + if ((rettv->v_type == VAR_FUNC || rettv->v_type == VAR_PARTIAL) + && selfdict != NULL) + { + char_u *fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string + : rettv->vval.v_partial->pt_name; char_u *tofree = NULL; ufunc_T *fp; char_u fname_buf[FLEN_FIXED + 1]; int error; /* Translate "s:func" to the stored function name. */ - fname = fname_trans_sid(rettv->vval.v_string, fname_buf, - &tofree, &error); + fname = fname_trans_sid(fname, fname_buf, &tofree, &error); fp = find_func(fname); vim_free(tofree); @@ -21758,7 +21753,34 @@ handle_subscript( pt->pt_refcount = 1; pt->pt_dict = selfdict; selfdict = NULL; - pt->pt_name = rettv->vval.v_string; + if (rettv->v_type == VAR_FUNC) + { + /* just a function: use selfdict */ + pt->pt_name = rettv->vval.v_string; + } + else + { + partial_T *ret_pt = rettv->vval.v_partial; + int i; + + /* partial: use selfdict and copy args */ + pt->pt_name = vim_strsave(ret_pt->pt_name); + if (ret_pt->pt_argc > 0) + { + pt->pt_argv = (typval_T *)alloc( + sizeof(typval_T) * ret_pt->pt_argc); + if (pt->pt_argv == NULL) + /* out of memory: drop the arguments */ + pt->pt_argc = 0; + else + { + pt->pt_argc = ret_pt->pt_argc; + for (i = 0; i < pt->pt_argc; i++) + copy_tv(&ret_pt->pt_argv[i], &pt->pt_argv[i]); + } + } + partial_unref(ret_pt); + } func_ref(pt->pt_name); rettv->v_type = VAR_PARTIAL; rettv->vval.v_partial = pt; @@ -23915,6 +23937,8 @@ trans_function_name( { name = vim_strsave(lv.ll_tv->vval.v_partial->pt_name); *pp = end; + if (partial != NULL) + *partial = lv.ll_tv->vval.v_partial; } else { diff --git a/src/testdir/test_partial.vim b/src/testdir/test_partial.vim --- a/src/testdir/test_partial.vim +++ b/src/testdir/test_partial.vim @@ -115,6 +115,36 @@ func Test_script_function_in_dict() call assert_equal('bar', B()) endfunc +function! s:cache_arg(arg) dict + let s:result = self.name . '/' . a:arg + return s:result +endfunction + +func Test_script_function_in_dict_arg() + let s:obj = {'name': 'foo'} + let s:obj['clear'] = function('s:cache_arg') + + call assert_equal('foo/bar', s:obj.clear('bar')) + let F = s:obj.clear + let s:result = '' + call assert_equal('foo/bar', F('bar')) + call assert_equal('foo/bar', s:result) + + let s:obj['clear'] = function('s:cache_arg', ['bar']) + call assert_equal('foo/bar', s:obj.clear()) + let s:result = '' + call s:obj.clear() + call assert_equal('foo/bar', s:result) + + let F = s:obj.clear + call assert_equal('foo/bar', F()) + let s:result = '' + call F() + call assert_equal('foo/bar', s:result) + + call assert_equal('foo/bar', call(s:obj.clear, [], s:obj)) +endfunc + func Test_partial_exists() let F = function('MyFunc') call assert_true(exists('*F')) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -749,6 +749,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1589, +/**/ 1588, /**/ 1587,