forked from aniani/vim
patch 7.4.1644
Problem: Using string() on a partial that exists in the dictionary it binds results in an error. (Nikolai Pavlov) Solution: Make string() not fail on a recursively nested structure. (Ken Takta)
This commit is contained in:
96
src/eval.c
96
src/eval.c
@@ -7851,10 +7851,50 @@ echo_string(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VAR_PARTIAL:
|
case VAR_PARTIAL:
|
||||||
*tofree = NULL;
|
{
|
||||||
/* TODO: arguments */
|
partial_T *pt = tv->vval.v_partial;
|
||||||
r = tv->vval.v_partial == NULL ? NULL : tv->vval.v_partial->pt_name;
|
char_u *fname = string_quote(pt == NULL ? NULL
|
||||||
break;
|
: pt->pt_name, FALSE);
|
||||||
|
garray_T ga;
|
||||||
|
int i;
|
||||||
|
char_u *tf;
|
||||||
|
|
||||||
|
ga_init2(&ga, 1, 100);
|
||||||
|
ga_concat(&ga, (char_u *)"function(");
|
||||||
|
if (fname != NULL)
|
||||||
|
{
|
||||||
|
ga_concat(&ga, fname);
|
||||||
|
vim_free(fname);
|
||||||
|
}
|
||||||
|
if (pt != NULL && pt->pt_argc > 0)
|
||||||
|
{
|
||||||
|
ga_concat(&ga, (char_u *)", [");
|
||||||
|
for (i = 0; i < pt->pt_argc; ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
ga_concat(&ga, (char_u *)", ");
|
||||||
|
ga_concat(&ga,
|
||||||
|
tv2string(&pt->pt_argv[i], &tf, numbuf, copyID));
|
||||||
|
vim_free(tf);
|
||||||
|
}
|
||||||
|
ga_concat(&ga, (char_u *)"]");
|
||||||
|
}
|
||||||
|
if (pt != NULL && pt->pt_dict != NULL)
|
||||||
|
{
|
||||||
|
typval_T dtv;
|
||||||
|
|
||||||
|
ga_concat(&ga, (char_u *)", ");
|
||||||
|
dtv.v_type = VAR_DICT;
|
||||||
|
dtv.vval.v_dict = pt->pt_dict;
|
||||||
|
ga_concat(&ga, tv2string(&dtv, &tf, numbuf, copyID));
|
||||||
|
vim_free(tf);
|
||||||
|
}
|
||||||
|
ga_concat(&ga, (char_u *)")");
|
||||||
|
|
||||||
|
*tofree = ga.ga_data;
|
||||||
|
r = *tofree;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
if (tv->vval.v_list == NULL)
|
if (tv->vval.v_list == NULL)
|
||||||
@@ -7941,50 +7981,6 @@ tv2string(
|
|||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
*tofree = string_quote(tv->vval.v_string, TRUE);
|
*tofree = string_quote(tv->vval.v_string, TRUE);
|
||||||
return *tofree;
|
return *tofree;
|
||||||
case VAR_PARTIAL:
|
|
||||||
{
|
|
||||||
partial_T *pt = tv->vval.v_partial;
|
|
||||||
char_u *fname = string_quote(pt == NULL ? NULL
|
|
||||||
: pt->pt_name, FALSE);
|
|
||||||
garray_T ga;
|
|
||||||
int i;
|
|
||||||
char_u *tf;
|
|
||||||
|
|
||||||
ga_init2(&ga, 1, 100);
|
|
||||||
ga_concat(&ga, (char_u *)"function(");
|
|
||||||
if (fname != NULL)
|
|
||||||
{
|
|
||||||
ga_concat(&ga, fname);
|
|
||||||
vim_free(fname);
|
|
||||||
}
|
|
||||||
if (pt != NULL && pt->pt_argc > 0)
|
|
||||||
{
|
|
||||||
ga_concat(&ga, (char_u *)", [");
|
|
||||||
for (i = 0; i < pt->pt_argc; ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
ga_concat(&ga, (char_u *)", ");
|
|
||||||
ga_concat(&ga,
|
|
||||||
tv2string(&pt->pt_argv[i], &tf, numbuf, copyID));
|
|
||||||
vim_free(tf);
|
|
||||||
}
|
|
||||||
ga_concat(&ga, (char_u *)"]");
|
|
||||||
}
|
|
||||||
if (pt != NULL && pt->pt_dict != NULL)
|
|
||||||
{
|
|
||||||
typval_T dtv;
|
|
||||||
|
|
||||||
ga_concat(&ga, (char_u *)", ");
|
|
||||||
dtv.v_type = VAR_DICT;
|
|
||||||
dtv.vval.v_dict = pt->pt_dict;
|
|
||||||
ga_concat(&ga, tv2string(&dtv, &tf, numbuf, copyID));
|
|
||||||
vim_free(tf);
|
|
||||||
}
|
|
||||||
ga_concat(&ga, (char_u *)")");
|
|
||||||
|
|
||||||
*tofree = ga.ga_data;
|
|
||||||
return *tofree;
|
|
||||||
}
|
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
*tofree = string_quote(tv->vval.v_string, FALSE);
|
*tofree = string_quote(tv->vval.v_string, FALSE);
|
||||||
return *tofree;
|
return *tofree;
|
||||||
@@ -7997,6 +7993,7 @@ tv2string(
|
|||||||
case VAR_NUMBER:
|
case VAR_NUMBER:
|
||||||
case VAR_LIST:
|
case VAR_LIST:
|
||||||
case VAR_DICT:
|
case VAR_DICT:
|
||||||
|
case VAR_PARTIAL:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
@@ -19258,7 +19255,8 @@ f_string(typval_T *argvars, typval_T *rettv)
|
|||||||
char_u numbuf[NUMBUFLEN];
|
char_u numbuf[NUMBUFLEN];
|
||||||
|
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf, 0);
|
rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
|
||||||
|
get_copyID());
|
||||||
/* Make a copy if we have a value but it's not in allocated memory. */
|
/* Make a copy if we have a value but it's not in allocated memory. */
|
||||||
if (rettv->vval.v_string != NULL && tofree == NULL)
|
if (rettv->vval.v_string != NULL && tofree == NULL)
|
||||||
rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
|
rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
|
||||||
|
@@ -180,3 +180,16 @@ func Test_func_unref()
|
|||||||
unlet obj
|
unlet obj
|
||||||
call assert_false(exists('*{' . funcnumber . '}'))
|
call assert_false(exists('*{' . funcnumber . '}'))
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_tostring()
|
||||||
|
let d = {}
|
||||||
|
let d.d = d
|
||||||
|
function d.test3()
|
||||||
|
echo 42
|
||||||
|
endfunction
|
||||||
|
try
|
||||||
|
call string(d.test3)
|
||||||
|
catch
|
||||||
|
call assert_true(v:false, v:exception)
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
@@ -748,6 +748,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1644,
|
||||||
/**/
|
/**/
|
||||||
1643,
|
1643,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user