vim-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)

65639032bb
This commit is contained in:
Michael Ennen 2016-10-26 12:42:15 -07:00 committed by James McCoy
parent 2c1b4c7f3c
commit 5cf0c99755
3 changed files with 59 additions and 36 deletions

View File

@ -2774,7 +2774,7 @@ void ex_call(exarg_T *eap)
return; return;
} }
tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi); tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial);
if (fudi.fd_newkey != NULL) { if (fudi.fd_newkey != NULL) {
/* Still need to give an error message for missing key. */ /* Still need to give an error message for missing key. */
EMSG2(_(e_dictkey), fudi.fd_newkey); EMSG2(_(e_dictkey), fudi.fd_newkey);
@ -2788,9 +2788,19 @@ void ex_call(exarg_T *eap)
if (fudi.fd_dict != NULL) if (fudi.fd_dict != NULL)
++fudi.fd_dict->dv_refcount; ++fudi.fd_dict->dv_refcount;
/* If it is the name of a variable of type VAR_FUNC use its contents. */ // If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its
// contents. For VAR_PARTIAL get its partial, unless we already have one
// from trans_function_name().
len = (int)STRLEN(tofree); len = (int)STRLEN(tofree);
name = deref_func_name(tofree, &len, &partial, false); 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(vim): 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 /* Skip white space to allow ":call func ()". Not good, but required for
* backward compatibility. */ * backward compatibility. */
@ -6525,7 +6535,7 @@ static ufunc_T *find_ufunc(uint8_t *name)
uint8_t *n = name; uint8_t *n = name;
ufunc_T *rv = NULL; ufunc_T *rv = NULL;
if (*n > '9' || *n < '0') { if (*n > '9' || *n < '0') {
if ((n = trans_function_name(&n, false, TFN_INT|TFN_QUIET, NULL))) { if ((n = trans_function_name(&n, false, TFN_INT|TFN_QUIET, NULL, NULL))) {
rv = find_func(n); rv = find_func(n);
xfree(n); xfree(n);
} }
@ -6814,20 +6824,20 @@ static VimLFuncDef *find_internal_func(const char *const name)
return find_internal_func_gperf(name, len); return find_internal_func_gperf(name, len);
} }
/* /// Check if "name" is a variable of type VAR_FUNC. If so, return the function
* Check if "name" is a variable of type VAR_FUNC. If so, return the function /// name it contains, otherwise return "name".
* name it contains, otherwise return "name". /// If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set
* If "name" is of type VAR_PARTIAL also return "partial" /// "partialp".
*/
static char_u *deref_func_name( static char_u *deref_func_name(
char_u *name, int *lenp, char_u *name, int *lenp,
partial_T **partial, int no_autoload partial_T **partialp, int no_autoload
) )
{ {
dictitem_T *v; dictitem_T *v;
int cc; int cc;
if (partialp != NULL) {
*partial = NULL; *partialp = NULL;
}
cc = name[*lenp]; cc = name[*lenp];
name[*lenp] = NUL; name[*lenp] = NUL;
@ -6843,13 +6853,17 @@ static char_u *deref_func_name(
} }
if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) { if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) {
*partial = v->di_tv.vval.v_partial; partial_T *pt = v->di_tv.vval.v_partial;
if (*partial == NULL) {
if (pt == NULL) {
*lenp = 0; *lenp = 0;
return (char_u *)""; // just in case return (char_u *)""; // just in case
} }
*lenp = (int)STRLEN((*partial)->pt_name); if (partialp != NULL) {
return (*partial)->pt_name; *partialp = pt;
}
*lenp = (int)STRLEN(pt->pt_name);
return pt->pt_name;
} }
return name; return name;
@ -7125,7 +7139,7 @@ call_func(
name); name);
break; break;
case ERROR_BOTH: case ERROR_BOTH:
emsg_funcname(N_(e_dict_both, name); emsg_funcname(N_(e_dict_both), name);
break; break;
} }
} }
@ -18336,9 +18350,12 @@ handle_subscript (
} }
if (rettv->v_type == VAR_FUNC && selfdict != NULL) { if (rettv->v_type == VAR_FUNC && selfdict != NULL) {
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T)); ufunc_T *fp = find_func(rettv->vval.v_string);
// Turn "dict.Func" into a partial for "Func" with "dict". // Turn "dict.Func" into a partial for "Func" with "dict".
if (fp != NULL && (fp->uf_flags & FC_DICT)) {
partial_T *pt = (partial_T *)xcalloc(1, sizeof(partial_T));
if (pt != NULL) { if (pt != NULL) {
pt->pt_refcount = 1; pt->pt_refcount = 1;
pt->pt_dict = selfdict; pt->pt_dict = selfdict;
@ -18349,6 +18366,7 @@ handle_subscript (
rettv->vval.v_partial = pt; rettv->vval.v_partial = pt;
} }
} }
}
dict_unref(selfdict); dict_unref(selfdict);
return ret; return ret;
@ -19735,7 +19753,7 @@ void ex_function(exarg_T *eap)
// s:func script-local function name // s:func script-local function name
// g:func global function name, same as "func" // g:func global function name, same as "func"
p = eap->arg; p = eap->arg;
name = trans_function_name(&p, eap->skip, 0, &fudi); name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
paren = (vim_strchr(p, '(') != NULL); paren = (vim_strchr(p, '(') != NULL);
if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) { if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) {
/* /*
@ -20002,7 +20020,7 @@ void ex_function(exarg_T *eap)
p = skipwhite(p + 1); p = skipwhite(p + 1);
} }
p += eval_fname_script(p); p += eval_fname_script(p);
xfree(trans_function_name(&p, TRUE, 0, NULL)); xfree(trans_function_name(&p, true, 0, NULL, NULL));
if (*skipwhite(p) == '(') { if (*skipwhite(p) == '(') {
nesting++; nesting++;
indent += 2; indent += 2;
@ -20220,7 +20238,8 @@ trans_function_name (
char_u **pp, char_u **pp,
int skip, /* only find the end, don't evaluate */ int skip, /* only find the end, don't evaluate */
int flags, int flags,
funcdict_T *fdp /* return: info about dictionary used */ funcdict_T *fdp, // return: info about dictionary used
partial_T **partial // return: partial of a FuncRef
) )
{ {
char_u *name = NULL; char_u *name = NULL;
@ -20230,7 +20249,6 @@ trans_function_name (
char_u sid_buf[20]; char_u sid_buf[20];
int len; int len;
lval_T lv; lval_T lv;
partial_T *partial;
if (fdp != NULL) if (fdp != NULL)
memset(fdp, 0, sizeof(funcdict_T)); memset(fdp, 0, sizeof(funcdict_T));
@ -20305,14 +20323,14 @@ trans_function_name (
/* Check if the name is a Funcref. If so, use the value. */ /* Check if the name is a Funcref. If so, use the value. */
if (lv.ll_exp_name != NULL) { if (lv.ll_exp_name != NULL) {
len = (int)STRLEN(lv.ll_exp_name); len = (int)STRLEN(lv.ll_exp_name);
name = deref_func_name(lv.ll_exp_name, &len, &partial, name = deref_func_name(lv.ll_exp_name, &len, partial,
flags & TFN_NO_AUTOLOAD); flags & TFN_NO_AUTOLOAD);
if (name == lv.ll_exp_name) { if (name == lv.ll_exp_name) {
name = NULL; name = NULL;
} }
} else { } else {
len = (int)(end - *pp); len = (int)(end - *pp);
name = deref_func_name(*pp, &len, &partial, flags & TFN_NO_AUTOLOAD); name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD);
if (name == *pp) { if (name == *pp) {
name = NULL; name = NULL;
} }
@ -20513,8 +20531,8 @@ static int function_exists(char_u *name)
char_u *p; char_u *p;
int n = FALSE; int n = FALSE;
p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD, p = trans_function_name(&nm, false, TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD,
NULL); NULL, NULL);
nm = skipwhite(nm); nm = skipwhite(nm);
/* Only accept "funcname", "funcname ", "funcname (..." and /* Only accept "funcname", "funcname ", "funcname (..." and
@ -20834,7 +20852,7 @@ void ex_delfunction(exarg_T *eap)
funcdict_T fudi; funcdict_T fudi;
p = eap->arg; p = eap->arg;
name = trans_function_name(&p, eap->skip, 0, &fudi); name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
xfree(fudi.fd_newkey); xfree(fudi.fd_newkey);
if (name == NULL) { if (name == NULL) {
if (fudi.fd_dict != NULL && !eap->skip) if (fudi.fd_dict != NULL && !eap->skip)

View File

@ -16,6 +16,8 @@ endfunc
func Test_partial_args() func Test_partial_args()
let Cb = function('MyFunc', ["foo", "bar"]) let Cb = function('MyFunc', ["foo", "bar"])
call Cb("zzz")
call assert_equal("foo/bar/xxx", Cb("xxx")) call assert_equal("foo/bar/xxx", Cb("xxx"))
call assert_equal("foo/bar/yyy", call(Cb, ["yyy"])) call assert_equal("foo/bar/yyy", call(Cb, ["yyy"]))
@ -48,6 +50,9 @@ func Test_partial_dict()
let Cb = function('MyDictFunc', dict) let Cb = function('MyDictFunc', dict)
call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy")) call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy"))
call assert_fails('Cb("fff")', 'E492:') call assert_fails('Cb("fff")', 'E492:')
let dict = {"tr": function('tr', ['hello', 'h', 'H'])}
call assert_equal("Hello", dict.tr())
endfunc endfunc
func Test_partial_implicit() func Test_partial_implicit()

View File

@ -861,7 +861,7 @@ static int included_patches[] = {
// 1584 NA // 1584 NA
// 1583 NA // 1583 NA
// 1582, // 1582,
// 1581, 1581,
1580, 1580,
// 1579 NA // 1579 NA
1578, 1578,