Skip to content

Commit 3b69006

Browse files
committed
patch 8.2.2449: Vim9: flatten() always changes the list type
Problem: Vim9: flatten() always changes the list type. Solution: Disallow using flatten() and add flattennew().
1 parent 9d20daf commit 3b69006

10 files changed

Lines changed: 98 additions & 14 deletions

File tree

runtime/doc/eval.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2549,6 +2549,8 @@ finddir({name} [, {path} [, {count}]])
25492549
findfile({name} [, {path} [, {count}]])
25502550
String find file {name} in {path}
25512551
flatten({list} [, {maxdepth}]) List flatten {list} up to {maxdepth} levels
2552+
flattennew({list} [, {maxdepth}])
2553+
List flatten a copy of {list}
25522554
float2nr({expr}) Number convert Float {expr} to a Number
25532555
floor({expr}) Float round {expr} down
25542556
fmod({expr1}, {expr2}) Float remainder of {expr1} / {expr2}
@@ -4712,8 +4714,10 @@ flatten({list} [, {maxdepth}]) *flatten()*
47124714
Flatten {list} up to {maxdepth} levels. Without {maxdepth}
47134715
the result is a |List| without nesting, as if {maxdepth} is
47144716
a very large number.
4715-
The {list} is changed in place, make a copy first if you do
4717+
The {list} is changed in place, use |flattennew()| if you do
47164718
not want that.
4719+
In Vim9 script flatten() cannot be used, you must always use
4720+
|flattennew()|.
47174721
*E900*
47184722
{maxdepth} means how deep in nested lists changes are made.
47194723
{list} is not modified when {maxdepth} is 0.
@@ -4727,6 +4731,10 @@ flatten({list} [, {maxdepth}]) *flatten()*
47274731
:echo flatten([1, [2, [3, 4]], 5], 1)
47284732
< [1, 2, [3, 4], 5]
47294733

4734+
flattennew({list} [, {maxdepth}]) *flattennew()*
4735+
Like |flatten()| but first make a copy of {list}.
4736+
4737+
47304738
float2nr({expr}) *float2nr()*
47314739
Convert {expr} to a Number by omitting the part after the
47324740
decimal point.

runtime/doc/usr_41.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,7 @@ List manipulation: *list-functions*
665665
count() count number of times a value appears in a List
666666
repeat() repeat a List multiple times
667667
flatten() flatten a List
668+
flattennew() flatten a copy of a List
668669

669670
Dictionary manipulation: *dict-functions*
670671
get() get an entry without an error for a wrong key

src/errors.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,5 @@ EXTERN char e_cannot_change_arglist_recursively[]
351351
INIT(= N_("E1156: Cannot change the argument list recursively"));
352352
EXTERN char e_missing_return_type[]
353353
INIT(= N_("E1157: Missing return type"));
354+
EXTERN char e_cannot_use_flatten_in_vim9_script[]
355+
INIT(= N_("E1158: Cannot use flatten() in Vim9 script"));

src/evalfunc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,8 @@ static funcentry_T global_functions[] =
954954
ret_string, f_findfile},
955955
{"flatten", 1, 2, FEARG_1, NULL,
956956
ret_list_any, f_flatten},
957+
{"flattennew", 1, 2, FEARG_1, NULL,
958+
ret_list_any, f_flattennew},
957959
{"float2nr", 1, 1, FEARG_1, NULL,
958960
ret_number, FLOAT_FUNC(f_float2nr)},
959961
{"floor", 1, 1, FEARG_1, NULL,

src/list.c

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -740,15 +740,15 @@ list_insert(list_T *l, listitem_T *ni, listitem_T *item)
740740
* It does nothing if "maxdepth" is 0.
741741
* Returns FAIL when out of memory.
742742
*/
743-
static int
743+
static void
744744
list_flatten(list_T *list, long maxdepth)
745745
{
746746
listitem_T *item;
747747
listitem_T *tofree;
748748
int n;
749749

750750
if (maxdepth == 0)
751-
return OK;
751+
return;
752752
CHECK_LIST_MATERIALIZE(list);
753753

754754
n = 0;
@@ -757,15 +757,15 @@ list_flatten(list_T *list, long maxdepth)
757757
{
758758
fast_breakcheck();
759759
if (got_int)
760-
return FAIL;
760+
return;
761761

762762
if (item->li_tv.v_type == VAR_LIST)
763763
{
764764
listitem_T *next = item->li_next;
765765

766766
vimlist_remove(list, item, item);
767767
if (list_extend(list, item->li_tv.vval.v_list, next) == FAIL)
768-
return FAIL;
768+
return;
769769
clear_tv(&item->li_tv);
770770
tofree = item;
771771

@@ -787,15 +787,13 @@ list_flatten(list_T *list, long maxdepth)
787787
item = item->li_next;
788788
}
789789
}
790-
791-
return OK;
792790
}
793791

794792
/*
795-
* "flatten(list[, {maxdepth}])" function
793+
* "flatten()" and "flattennew()" functions
796794
*/
797-
void
798-
f_flatten(typval_T *argvars, typval_T *rettv)
795+
static void
796+
flatten_common(typval_T *argvars, typval_T *rettv, int make_copy)
799797
{
800798
list_T *l;
801799
long maxdepth;
@@ -822,10 +820,48 @@ f_flatten(typval_T *argvars, typval_T *rettv)
822820
}
823821

824822
l = argvars[0].vval.v_list;
825-
if (l != NULL && !value_check_lock(l->lv_lock,
826-
(char_u *)N_("flatten() argument"), TRUE)
827-
&& list_flatten(l, maxdepth) == OK)
828-
copy_tv(&argvars[0], rettv);
823+
rettv->v_type = VAR_LIST;
824+
rettv->vval.v_list = l;
825+
if (l == NULL)
826+
return;
827+
828+
if (make_copy)
829+
{
830+
l = list_copy(l, TRUE, get_copyID());
831+
rettv->vval.v_list = l;
832+
if (l == NULL)
833+
return;
834+
}
835+
else
836+
{
837+
if (value_check_lock(l->lv_lock,
838+
(char_u *)N_("flatten() argument"), TRUE))
839+
return;
840+
++l->lv_refcount;
841+
}
842+
843+
list_flatten(l, maxdepth);
844+
}
845+
846+
/*
847+
* "flatten(list[, {maxdepth}])" function
848+
*/
849+
void
850+
f_flatten(typval_T *argvars, typval_T *rettv)
851+
{
852+
if (in_vim9script())
853+
emsg(_(e_cannot_use_flatten_in_vim9_script));
854+
else
855+
flatten_common(argvars, rettv, FALSE);
856+
}
857+
858+
/*
859+
* "flattennew(list[, {maxdepth}])" function
860+
*/
861+
void
862+
f_flattennew(typval_T *argvars, typval_T *rettv)
863+
{
864+
flatten_common(argvars, rettv, TRUE);
829865
}
830866

831867
/*

src/proto/list.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ int list_append_number(list_T *l, varnumber_T n);
3131
int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item);
3232
void list_insert(list_T *l, listitem_T *ni, listitem_T *item);
3333
void f_flatten(typval_T *argvars, typval_T *rettv);
34+
void f_flattennew(typval_T *argvars, typval_T *rettv);
3435
int list_extend(list_T *l1, list_T *l2, listitem_T *bef);
3536
int list_concat(list_T *l1, list_T *l2, typval_T *tv);
3637
list_T *list_slice(list_T *ol, long n1, long n2);

src/testdir/test_flatten.vim

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,13 @@ func Test_flatten()
8181
call assert_equal([2, l:x], l:y)
8282
endfunc
8383

84+
func Test_flattennew()
85+
let l = [1, [2, [3, 4]], 5]
86+
call assert_equal([1, 2, 3, 4, 5], flattennew(l))
87+
call assert_equal([1, [2, [3, 4]], 5], l)
88+
89+
call assert_equal([1, 2, [3, 4], 5], flattennew(l, 1))
90+
call assert_equal([1, [2, [3, 4]], 5], l)
91+
endfunc
92+
8493
" vim: shiftwidth=2 sts=2 expandtab

src/testdir/test_vim9_builtin.vim

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,23 @@ def Test_findfile()
382382
CheckDefExecFailure(['echo findfile("")'], 'E1142:')
383383
enddef
384384

385+
def Test_flattennew()
386+
var lines =<< trim END
387+
var l = [1, [2, [3, 4]], 5]
388+
call assert_equal([1, 2, 3, 4, 5], flattennew(l))
389+
call assert_equal([1, [2, [3, 4]], 5], l)
390+
391+
call assert_equal([1, 2, [3, 4], 5], flattennew(l, 1))
392+
call assert_equal([1, [2, [3, 4]], 5], l)
393+
END
394+
CheckDefAndScriptSuccess(lines)
395+
396+
lines =<< trim END
397+
echo flatten([1, 2, 3])
398+
END
399+
CheckDefAndScriptFailure(lines, 'E1158:')
400+
enddef
401+
385402
def Test_fnamemodify()
386403
CheckDefSuccess(['echo fnamemodify(test_null_string(), ":p")'])
387404
CheckDefSuccess(['echo fnamemodify("", ":p")'])

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2449,
753755
/**/
754756
2448,
755757
/**/

src/vim9compile.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2900,6 +2900,12 @@ compile_call(
29002900
idx = find_internal_func(name);
29012901
if (idx >= 0)
29022902
{
2903+
if (STRCMP(name, "flatten") == 0)
2904+
{
2905+
emsg(_(e_cannot_use_flatten_in_vim9_script));
2906+
goto theend;
2907+
}
2908+
29032909
if (STRCMP(name, "add") == 0 && argcount == 2)
29042910
{
29052911
garray_T *stack = &cctx->ctx_type_stack;

0 commit comments

Comments
 (0)