Skip to content

Instantly share code, notes, and snippets.

@mattn
Last active March 16, 2016 16:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattn/394e8a95be26d9c7bce9 to your computer and use it in GitHub Desktop.
Save mattn/394e8a95be26d9c7bce9 to your computer and use it in GitHub Desktop.
Fixes issue that crash with dict.MyFunc. this patch include @k-takata's patch
diff --git a/src/eval.c b/src/eval.c
index 5069324..7bdf7bb 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -867,7 +867,7 @@ static int valid_varname(char_u *varname);
static int tv_check_lock(int lock, char_u *name, int use_gettext);
static int item_copy(typval_T *from, typval_T *to, int deep, int copyID);
static char_u *find_option_end(char_u **arg, int *opt_flags);
-static char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fd);
+static char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fd, partial_T **partial);
static int eval_fname_script(char_u *p);
static int eval_fname_sid(char_u *p);
static void list_func_head(ufunc_T *fp, int indent);
@@ -3476,7 +3476,7 @@ ex_call(exarg_T *eap)
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)
{
/* Still need to give an error message for missing key. */
@@ -3491,9 +3491,14 @@ ex_call(exarg_T *eap)
if (fudi.fd_dict != NULL)
++fudi.fd_dict->dv_refcount;
+ /* Don't use partial because the function should have dict. */
+ if (fudi.fd_dict != NULL || !eval_fname_sid(tofree))
+ partial = NULL;
+
/* If it is the name of a variable of type VAR_FUNC use its contents. */
len = (int)STRLEN(tofree);
- name = deref_func_name(tofree, &len, &partial, FALSE);
+ name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial,
+ FALSE);
/* Skip white space to allow ":call func ()". Not good, but required for
* backward compatibility. */
@@ -5245,7 +5250,7 @@ eval7(
{
if (**arg == '(') /* recursive! */
{
- partial_T *partial;
+ partial_T *partial = NULL;
/* If "s" is the name of a variable of type VAR_FUNC
* use its contents. */
@@ -8569,7 +8574,8 @@ deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload)
dictitem_T *v;
int cc;
- *partial = NULL;
+ if (partial != NULL)
+ *partial = NULL;
cc = name[*lenp];
name[*lenp] = NUL;
@@ -8586,7 +8592,7 @@ deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload)
return v->di_tv.vval.v_string;
}
- if (v != NULL && v->di_tv.v_type == VAR_PARTIAL)
+ if (partial != NULL && v != NULL && v->di_tv.v_type == VAR_PARTIAL)
{
*partial = v->di_tv.vval.v_partial;
if (*partial == NULL)
@@ -21700,17 +21706,23 @@ handle_subscript(
if (rettv->v_type == VAR_FUNC && selfdict != NULL)
{
- partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
-
- /* Turn "dict.Func" into a partial for "Func" with "dict". */
- if (pt != NULL)
+ ufunc_T *fp;
+ fp = find_func(rettv->vval.v_string);
+ if (fp && fp->uf_flags & FC_DICT)
{
- pt->pt_dict = selfdict;
- selfdict = NULL;
- pt->pt_name = rettv->vval.v_string;
- func_ref(pt->pt_name);
- rettv->v_type = VAR_PARTIAL;
- rettv->vval.v_partial = pt;
+ partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
+
+ /* Turn "dict.Func" into a partial for "Func" with "dict". */
+ if (pt != NULL)
+ {
+ pt->pt_dict = selfdict;
+ pt->pt_refcount = 1;
+ selfdict = NULL;
+ pt->pt_name = rettv->vval.v_string;
+ func_ref(pt->pt_name);
+ rettv->v_type = VAR_PARTIAL;
+ rettv->vval.v_partial = pt;
+ }
}
}
@@ -23219,7 +23231,7 @@ ex_function(exarg_T *eap)
* g:func global function name, same as "func"
*/
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);
if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
{
@@ -23532,7 +23544,7 @@ ex_function(exarg_T *eap)
if (*p == '!')
p = skipwhite(p + 1);
p += eval_fname_script(p);
- vim_free(trans_function_name(&p, TRUE, 0, NULL));
+ vim_free(trans_function_name(&p, TRUE, 0, NULL, NULL));
if (*skipwhite(p) == '(')
{
++nesting;
@@ -23787,7 +23799,8 @@ trans_function_name(
char_u **pp,
int skip, /* only find the end, don't evaluate */
int flags,
- funcdict_T *fdp) /* return: info about dictionary used */
+ funcdict_T *fdp,
+ partial_T **partial) /* return: info about dictionary used */
{
char_u *name = NULL;
char_u *start;
@@ -23796,7 +23809,6 @@ trans_function_name(
char_u sid_buf[20];
int len;
lval_T lv;
- partial_T *partial;
if (fdp != NULL)
vim_memset(fdp, 0, sizeof(funcdict_T));
@@ -23881,7 +23893,7 @@ trans_function_name(
if (lv.ll_exp_name != NULL)
{
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);
if (name == lv.ll_exp_name)
name = NULL;
@@ -23889,7 +23901,7 @@ trans_function_name(
else
{
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)
name = NULL;
}
@@ -24114,7 +24126,7 @@ function_exists(char_u *name)
int n = FALSE;
p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD,
- NULL);
+ NULL, NULL);
nm = skipwhite(nm);
/* Only accept "funcname", "funcname ", "funcname (..." and
@@ -24131,7 +24143,7 @@ get_expanded_name(char_u *name, int check)
char_u *nm = name;
char_u *p;
- p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL);
+ p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL, NULL);
if (p != NULL && *nm == NUL)
if (!check || translated_function_exists(p))
@@ -24487,7 +24499,7 @@ ex_delfunction(exarg_T *eap)
funcdict_T fudi;
p = eap->arg;
- name = trans_function_name(&p, eap->skip, 0, &fudi);
+ name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
vim_free(fudi.fd_newkey);
if (name == NULL)
{
diff --git a/src/testdir/test_partial.vim b/src/testdir/test_partial.vim
index ddc85e0..054c700 100644
--- a/src/testdir/test_partial.vim
+++ b/src/testdir/test_partial.vim
@@ -16,6 +16,8 @@ endfunc
func Test_partial_args()
let Cb = function('MyFunc', ["foo", "bar"])
+
+ call Cb("zzz")
call assert_equal("foo/bar/xxx", Cb("xxx"))
call assert_equal("foo/bar/yyy", call(Cb, ["yyy"]))
@@ -49,6 +51,9 @@ func Test_partial_dict()
let Cb = function('MyDictFunc', dict)
call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy"))
call assert_fails('Cb("fff")', 'E492:')
+
+ let dict = {"tr": function('tr', ['hello', 'h', 'H'])}
+ call assert_equal("Hello", dict.tr())
endfunc
func Test_partial_implicit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment