Last active
March 16, 2016 16:57
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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