To: vim_dev@googlegroups.com Subject: Patch 8.2.2621 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2621 Problem: typval2type() cannot handle recursive structures. Solution: Use copyID. (closes #7979) Files: src/list.c, src/vim9script.c, src/vim9type.c, src/proto/vim9type.pro, src/testdir/test_vimscript.vim *** ../vim-8.2.2620/src/list.c 2021-02-21 16:20:14.248629232 +0100 --- src/list.c 2021-03-18 22:02:23.538286414 +0100 *************** *** 2052,2058 **** { // Check that map() does not change the type of the dict. ga_init2(&type_list, sizeof(type_T *), 10); ! type = typval2type(argvars, &type_list); } if (argvars[0].v_type == VAR_BLOB) --- 2052,2058 ---- { // Check that map() does not change the type of the dict. ga_init2(&type_list, sizeof(type_T *), 10); ! type = typval2type(argvars, get_copyID(), &type_list); } if (argvars[0].v_type == VAR_BLOB) *************** *** 2558,2564 **** { // Check that map() does not change the type of the dict. ga_init2(&type_list, sizeof(type_T *), 10); ! type = typval2type(argvars, &type_list); } if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) --- 2558,2564 ---- { // Check that map() does not change the type of the dict. ga_init2(&type_list, sizeof(type_T *), 10); ! type = typval2type(argvars, get_copyID(), &type_list); } if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) *** ../vim-8.2.2620/src/vim9script.c 2021-03-18 21:37:52.192105213 +0100 --- src/vim9script.c 2021-03-18 22:02:38.082269393 +0100 *************** *** 750,756 **** if (sv != NULL) { if (*type == NULL) ! *type = typval2type(tv, &si->sn_type_list); sv->sv_type = *type; } --- 750,756 ---- if (sv != NULL) { if (*type == NULL) ! *type = typval2type(tv, get_copyID(), &si->sn_type_list); sv->sv_type = *type; } *** ../vim-8.2.2620/src/vim9type.c 2021-03-13 21:24:53.040409187 +0100 --- src/vim9type.c 2021-03-18 22:13:31.913347899 +0100 *************** *** 254,260 **** * "type_gap" is used to temporarily create types in. */ static type_T * ! typval2type_int(typval_T *tv, garray_T *type_gap) { type_T *type; type_T *member_type = &t_any; --- 254,260 ---- * "type_gap" is used to temporarily create types in. */ static type_T * ! typval2type_int(typval_T *tv, int copyID, garray_T *type_gap) { type_T *type; type_T *member_type = &t_any; *************** *** 276,286 **** return &t_list_empty; if (l->lv_first == &range_list_item) return &t_list_number; // Use the common type of all members. ! member_type = typval2type(&l->lv_first->li_tv, type_gap); for (li = l->lv_first->li_next; li != NULL; li = li->li_next) ! common_type(typval2type(&li->li_tv, type_gap), member_type, &member_type, type_gap); return get_list_type(member_type, type_gap); } --- 276,290 ---- return &t_list_empty; if (l->lv_first == &range_list_item) return &t_list_number; + if (l->lv_copyID == copyID) + // avoid recursion + return &t_list_any; + l->lv_copyID = copyID; // Use the common type of all members. ! member_type = typval2type(&l->lv_first->li_tv, copyID, type_gap); for (li = l->lv_first->li_next; li != NULL; li = li->li_next) ! common_type(typval2type(&li->li_tv, copyID, type_gap), member_type, &member_type, type_gap); return get_list_type(member_type, type_gap); } *************** *** 289,305 **** { dict_iterator_T iter; typval_T *value; ! if (tv->vval.v_dict == NULL ! || tv->vval.v_dict->dv_hashtab.ht_used == 0) return &t_dict_empty; // Use the common type of all values. dict_iterate_start(tv, &iter); dict_iterate_next(&iter, &value); ! member_type = typval2type(value, type_gap); while (dict_iterate_next(&iter, &value) != NULL) ! common_type(typval2type(value, type_gap), member_type, &member_type, type_gap); return get_dict_type(member_type, type_gap); } --- 293,313 ---- { dict_iterator_T iter; typval_T *value; + dict_T *d = tv->vval.v_dict; ! if (d == NULL || d->dv_hashtab.ht_used == 0) return &t_dict_empty; + if (d->dv_copyID == copyID) + // avoid recursion + return &t_dict_any; + d->dv_copyID = copyID; // Use the common type of all values. dict_iterate_start(tv, &iter); dict_iterate_next(&iter, &value); ! member_type = typval2type(value, copyID, type_gap); while (dict_iterate_next(&iter, &value) != NULL) ! common_type(typval2type(value, copyID, type_gap), member_type, &member_type, type_gap); return get_dict_type(member_type, type_gap); } *************** *** 372,380 **** * "type_list" is used to temporarily create types in. */ type_T * ! typval2type(typval_T *tv, garray_T *type_gap) { ! type_T *type = typval2type_int(tv, type_gap); if (type != NULL && type != &t_bool && (tv->v_type == VAR_NUMBER --- 380,388 ---- * "type_list" is used to temporarily create types in. */ type_T * ! typval2type(typval_T *tv, int copyID, garray_T *type_gap) { ! type_T *type = typval2type_int(tv, copyID, type_gap); if (type != NULL && type != &t_bool && (tv->v_type == VAR_NUMBER *************** *** 396,402 **** return &t_list_string; if (tv->v_type == VAR_DICT) // e.g. for v:completed_item return &t_dict_any; ! return typval2type(tv, type_gap); } int --- 404,410 ---- return &t_list_string; if (tv->v_type == VAR_DICT) // e.g. for v:completed_item return &t_dict_any; ! return typval2type(tv, get_copyID(), type_gap); } int *************** *** 421,427 **** int res = FAIL; ga_init2(&type_list, sizeof(type_T *), 10); ! actual_type = typval2type(actual_tv, &type_list); if (actual_type != NULL) res = check_type(expected, actual_type, TRUE, where); clear_type_list(&type_list); --- 429,435 ---- int res = FAIL; ga_init2(&type_list, sizeof(type_T *), 10); ! actual_type = typval2type(actual_tv, get_copyID(), &type_list); if (actual_type != NULL) res = check_type(expected, actual_type, TRUE, where); clear_type_list(&type_list); *************** *** 1202,1208 **** rettv->v_type = VAR_STRING; ga_init2(&type_list, sizeof(type_T *), 10); ! type = typval2type(argvars, &type_list); name = type_name(type, &tofree); if (tofree != NULL) rettv->vval.v_string = (char_u *)tofree; --- 1210,1216 ---- rettv->v_type = VAR_STRING; ga_init2(&type_list, sizeof(type_T *), 10); ! type = typval2type(argvars, get_copyID(), &type_list); name = type_name(type, &tofree); if (tofree != NULL) rettv->vval.v_string = (char_u *)tofree; *** ../vim-8.2.2620/src/proto/vim9type.pro 2021-02-11 21:19:30.518147953 +0100 --- src/proto/vim9type.pro 2021-03-18 22:08:09.721832238 +0100 *************** *** 9,15 **** type_T *get_func_type(type_T *ret_type, int argcount, garray_T *type_gap); int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap); int need_convert_to_bool(type_T *type, typval_T *tv); ! type_T *typval2type(typval_T *tv, garray_T *type_gap); type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap); int check_typval_arg_type(type_T *expected, typval_T *actual_tv, int arg_idx); int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where); --- 9,15 ---- type_T *get_func_type(type_T *ret_type, int argcount, garray_T *type_gap); int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap); int need_convert_to_bool(type_T *type, typval_T *tv); ! type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap); type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap); int check_typval_arg_type(type_T *expected, typval_T *actual_tv, int arg_idx); int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where); *** ../vim-8.2.2620/src/testdir/test_vimscript.vim 2021-01-12 21:48:55.879131998 +0100 --- src/testdir/test_vimscript.vim 2021-03-18 22:12:11.917471779 +0100 *************** *** 6606,6611 **** --- 6606,6618 ---- call assert_equal('list', typename([123])) call assert_equal('dict', typename(#{key: 123})) call assert_equal('list>', typename([#{key: 123}])) + + let l = [] + let d = #{a: 0} + let l = [d] + let l[0].e = #{b: l} + call assert_equal('list>', typename(l)) + call assert_equal('dict', typename(d)) endfunc "------------------------------------------------------------------------------- *** ../vim-8.2.2620/src/version.c 2021-03-18 21:37:52.196105245 +0100 --- src/version.c 2021-03-18 22:14:11.877285250 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2621, /**/ -- If someone questions your market projections, simply point out that your target market is "People who are nuts" and "People who will buy any damn thing". Nobody is going to tell you there aren't enough of those people to go around. (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///