To: vim_dev@googlegroups.com Subject: Patch 8.2.4634 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4634 Problem: Vim9: cannot initialize a variable to null_list. Solution: Give negative count to NEWLIST. (closes #10027) Also fix inconsistencies in comparing with null values. Files: src/vim9instr.c, src/proto/vim9instr.pro, src/vim9.h, src/vim9compile.c, src/vim9expr.c, src/vim9execute.c, src/evalvars.c, src/typval.c, src/testdir/test_vim9_expr.vim, src/testdir/test_vim9_builtin.vim, src/testdir/test_vim9_disassemble.vim *** ../vim-8.2.4633/src/vim9instr.c 2022-03-23 11:29:08.560730204 +0000 --- src/vim9instr.c 2022-03-27 15:17:41.899085611 +0100 *************** *** 581,592 **** case VAR_LIST: if (tv->vval.v_list != NULL) iemsg("non-empty list constant not supported"); ! generate_NEWLIST(cctx, 0); break; case VAR_DICT: if (tv->vval.v_dict != NULL) iemsg("non-empty dict constant not supported"); ! generate_NEWDICT(cctx, 0); break; #ifdef FEAT_JOB_CHANNEL case VAR_JOB: --- 581,592 ---- case VAR_LIST: if (tv->vval.v_list != NULL) iemsg("non-empty list constant not supported"); ! generate_NEWLIST(cctx, 0, TRUE); break; case VAR_DICT: if (tv->vval.v_dict != NULL) iemsg("non-empty dict constant not supported"); ! generate_NEWDICT(cctx, 0, TRUE); break; #ifdef FEAT_JOB_CHANNEL case VAR_JOB: *************** *** 1115,1124 **** } /* ! * Generate an ISN_NEWLIST instruction. */ int ! generate_NEWLIST(cctx_T *cctx, int count) { isn_T *isn; type_T *member_type; --- 1115,1125 ---- } /* ! * Generate an ISN_NEWLIST instruction for "count" items. ! * "use_null" is TRUE for null_list. */ int ! generate_NEWLIST(cctx_T *cctx, int count, int use_null) { isn_T *isn; type_T *member_type; *************** *** 1128,1134 **** RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_NEWLIST)) == NULL) return FAIL; ! isn->isn_arg.number = count; // Get the member type and the declared member type from all the items on // the stack. --- 1129,1135 ---- RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_NEWLIST)) == NULL) return FAIL; ! isn->isn_arg.number = use_null ? -1 : count; // Get the member type and the declared member type from all the items on // the stack. *************** *** 1145,1153 **** /* * Generate an ISN_NEWDICT instruction. */ int ! generate_NEWDICT(cctx_T *cctx, int count) { isn_T *isn; type_T *member_type; --- 1146,1155 ---- /* * Generate an ISN_NEWDICT instruction. + * "use_null" is TRUE for null_dict. */ int ! generate_NEWDICT(cctx_T *cctx, int count, int use_null) { isn_T *isn; type_T *member_type; *************** *** 1157,1163 **** RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_NEWDICT)) == NULL) return FAIL; ! isn->isn_arg.number = count; member_type = get_member_type_from_stack(count, 2, cctx); type = get_dict_type(member_type, cctx->ctx_type_list); --- 1159,1165 ---- RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_NEWDICT)) == NULL) return FAIL; ! isn->isn_arg.number = use_null ? -1 : count; member_type = get_member_type_from_stack(count, 2, cctx); type = get_dict_type(member_type, cctx->ctx_type_list); *** ../vim-8.2.4633/src/proto/vim9instr.pro 2022-03-23 11:29:08.560730204 +0000 --- src/proto/vim9instr.pro 2022-03-27 15:27:55.744030581 +0100 *************** *** 36,43 **** int generate_LOCKCONST(cctx_T *cctx); int generate_OLDSCRIPT(cctx_T *cctx, isntype_T isn_type, char_u *name, int sid, type_T *type); int generate_VIM9SCRIPT(cctx_T *cctx, isntype_T isn_type, int sid, int idx, type_T *type); ! int generate_NEWLIST(cctx_T *cctx, int count); ! int generate_NEWDICT(cctx_T *cctx, int count); int generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, isn_T **isnp); int generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name); int generate_DEF(cctx_T *cctx, char_u *name, size_t len); --- 36,43 ---- int generate_LOCKCONST(cctx_T *cctx); int generate_OLDSCRIPT(cctx_T *cctx, isntype_T isn_type, char_u *name, int sid, type_T *type); int generate_VIM9SCRIPT(cctx_T *cctx, isntype_T isn_type, int sid, int idx, type_T *type); ! int generate_NEWLIST(cctx_T *cctx, int count, int use_null); ! int generate_NEWDICT(cctx_T *cctx, int count, int use_null); int generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, isn_T **isnp); int generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name); int generate_DEF(cctx_T *cctx, char_u *name, size_t len); *** ../vim-8.2.4633/src/vim9.h 2022-03-20 21:14:08.434143821 +0000 --- src/vim9.h 2022-03-27 16:29:07.284254445 +0100 *************** *** 90,96 **** --- 90,98 ---- ISN_PUSHCHANNEL, // push NULL channel ISN_PUSHJOB, // push NULL job ISN_NEWLIST, // push list from stack items, size is isn_arg.number + // -1 for null_list ISN_NEWDICT, // push dict from stack items, size is isn_arg.number + // -1 for null_dict ISN_NEWPARTIAL, // push NULL partial ISN_AUTOLOAD, // get item from autoload import, function or variable *** ../vim-8.2.4633/src/vim9compile.c 2022-03-23 11:29:08.560730204 +0000 --- src/vim9compile.c 2022-03-27 15:15:53.595066246 +0100 *************** *** 1955,1961 **** generate_PUSHS(cctx, &li->li_tv.vval.v_string); li->li_tv.vval.v_string = NULL; } ! generate_NEWLIST(cctx, l->lv_len); } list_free(l); p += STRLEN(p); --- 1955,1961 ---- generate_PUSHS(cctx, &li->li_tv.vval.v_string); li->li_tv.vval.v_string = NULL; } ! generate_NEWLIST(cctx, l->lv_len, FALSE); } list_free(l); p += STRLEN(p); *************** *** 2239,2248 **** generate_PUSHFUNC(cctx, NULL, &t_func_void); break; case VAR_LIST: ! generate_NEWLIST(cctx, 0); break; case VAR_DICT: ! generate_NEWDICT(cctx, 0); break; case VAR_JOB: generate_PUSHJOB(cctx); --- 2239,2248 ---- generate_PUSHFUNC(cctx, NULL, &t_func_void); break; case VAR_LIST: ! generate_NEWLIST(cctx, 0, FALSE); break; case VAR_DICT: ! generate_NEWDICT(cctx, 0, FALSE); break; case VAR_JOB: generate_PUSHJOB(cctx); *** ../vim-8.2.4633/src/vim9expr.c 2022-03-23 11:29:08.560730204 +0000 --- src/vim9expr.c 2022-03-27 15:16:07.347069210 +0100 *************** *** 958,964 **** *arg = p; ppconst->pp_is_const = is_all_const; ! return generate_NEWLIST(cctx, count); } /* --- 958,964 ---- *arg = p; ppconst->pp_is_const = is_all_const; ! return generate_NEWLIST(cctx, count, FALSE); } /* *************** *** 1246,1252 **** dict_unref(d); ppconst->pp_is_const = is_all_const; ! return generate_NEWDICT(cctx, count); failret: if (*arg == NULL) --- 1246,1252 ---- dict_unref(d); ppconst->pp_is_const = is_all_const; ! return generate_NEWDICT(cctx, count, FALSE); failret: if (*arg == NULL) *** ../vim-8.2.4633/src/vim9execute.c 2022-03-20 21:14:08.434143821 +0000 --- src/vim9execute.c 2022-03-27 15:29:02.915549774 +0100 *************** *** 122,150 **** /* * Create a new list from "count" items at the bottom of the stack. * When "count" is zero an empty list is added to the stack. */ static int exe_newlist(int count, ectx_T *ectx) { ! list_T *list = list_alloc_with_items(count); int idx; typval_T *tv; ! if (list == NULL) ! return FAIL; ! for (idx = 0; idx < count; ++idx) ! list_set_item(list, idx, STACK_TV_BOT(idx - count)); if (count > 0) ectx->ec_stack.ga_len -= count - 1; else if (GA_GROW_FAILS(&ectx->ec_stack, 1)) return FAIL; else ++ectx->ec_stack.ga_len; tv = STACK_TV_BOT(-1); tv->v_type = VAR_LIST; tv->vval.v_list = list; ! ++list->lv_refcount; return OK; } --- 122,224 ---- /* * Create a new list from "count" items at the bottom of the stack. * When "count" is zero an empty list is added to the stack. + * When "count" is -1 a NULL list is added to the stack. */ static int exe_newlist(int count, ectx_T *ectx) { ! list_T *list = NULL; int idx; typval_T *tv; ! if (count >= 0) ! { ! list = list_alloc_with_items(count); ! if (list == NULL) ! return FAIL; ! for (idx = 0; idx < count; ++idx) ! list_set_item(list, idx, STACK_TV_BOT(idx - count)); ! } if (count > 0) ectx->ec_stack.ga_len -= count - 1; else if (GA_GROW_FAILS(&ectx->ec_stack, 1)) + { + list_unref(list); return FAIL; + } else ++ectx->ec_stack.ga_len; tv = STACK_TV_BOT(-1); tv->v_type = VAR_LIST; tv->vval.v_list = list; ! if (list != NULL) ! ++list->lv_refcount; ! return OK; ! } ! ! /* ! * Implementation of ISN_NEWDICT. ! * Returns FAIL on total failure, MAYBE on error. ! */ ! static int ! exe_newdict(int count, ectx_T *ectx) ! { ! dict_T *dict = NULL; ! dictitem_T *item; ! char_u *key; ! int idx; ! typval_T *tv; ! ! if (count >= 0) ! { ! dict = dict_alloc(); ! if (unlikely(dict == NULL)) ! return FAIL; ! for (idx = 0; idx < count; ++idx) ! { ! // have already checked key type is VAR_STRING ! tv = STACK_TV_BOT(2 * (idx - count)); ! // check key is unique ! key = tv->vval.v_string == NULL ! ? (char_u *)"" : tv->vval.v_string; ! item = dict_find(dict, key, -1); ! if (item != NULL) ! { ! semsg(_(e_duplicate_key_in_dicitonary), key); ! dict_unref(dict); ! return MAYBE; ! } ! item = dictitem_alloc(key); ! clear_tv(tv); ! if (unlikely(item == NULL)) ! { ! dict_unref(dict); ! return FAIL; ! } ! item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1); ! item->di_tv.v_lock = 0; ! if (dict_add(dict, item) == FAIL) ! { ! // can this ever happen? ! dict_unref(dict); ! return FAIL; ! } ! } ! } ! ! if (count > 0) ! ectx->ec_stack.ga_len -= 2 * count - 1; ! else if (GA_GROW_FAILS(&ectx->ec_stack, 1)) ! return FAIL; ! else ! ++ectx->ec_stack.ga_len; ! tv = STACK_TV_BOT(-1); ! tv->v_type = VAR_DICT; ! tv->v_lock = 0; ! tv->vval.v_dict = dict; ! if (dict != NULL) ! ++dict->dv_refcount; return OK; } *************** *** 3357,3413 **** // create a dict from items on the stack case ISN_NEWDICT: { ! int count = iptr->isn_arg.number; ! dict_T *dict = dict_alloc(); ! dictitem_T *item; ! char_u *key; ! int idx; ! if (unlikely(dict == NULL)) ! goto theend; ! for (idx = 0; idx < count; ++idx) ! { ! // have already checked key type is VAR_STRING ! tv = STACK_TV_BOT(2 * (idx - count)); ! // check key is unique ! key = tv->vval.v_string == NULL ! ? (char_u *)"" : tv->vval.v_string; ! item = dict_find(dict, key, -1); ! if (item != NULL) ! { ! SOURCING_LNUM = iptr->isn_lnum; ! semsg(_(e_duplicate_key_in_dicitonary), key); ! dict_unref(dict); ! goto on_error; ! } ! item = dictitem_alloc(key); ! clear_tv(tv); ! if (unlikely(item == NULL)) ! { ! dict_unref(dict); ! goto theend; ! } ! item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1); ! item->di_tv.v_lock = 0; ! if (dict_add(dict, item) == FAIL) ! { ! // can this ever happen? ! dict_unref(dict); ! goto theend; ! } ! } ! ! if (count > 0) ! ectx->ec_stack.ga_len -= 2 * count - 1; ! else if (GA_GROW_FAILS(&ectx->ec_stack, 1)) goto theend; ! else ! ++ectx->ec_stack.ga_len; ! tv = STACK_TV_BOT(-1); ! tv->v_type = VAR_DICT; ! tv->v_lock = 0; ! tv->vval.v_dict = dict; ! ++dict->dv_refcount; } break; --- 3431,3444 ---- // create a dict from items on the stack case ISN_NEWDICT: { ! int res; ! SOURCING_LNUM = iptr->isn_lnum; ! res = exe_newdict(iptr->isn_arg.number, ectx); ! if (res == FAIL) goto theend; ! if (res == MAYBE) ! goto on_error; } break; *** ../vim-8.2.4633/src/evalvars.c 2022-03-20 17:46:01.797053490 +0000 --- src/evalvars.c 2022-03-27 15:12:43.563007587 +0100 *************** *** 2816,2826 **** type = sv->sv_type; } ! // If a list or dict variable wasn't initialized, do it now. ! // Not for global variables, they are not declared. if (ht != &globvarht) { ! if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL) { tv->vval.v_dict = dict_alloc(); if (tv->vval.v_dict != NULL) --- 2816,2828 ---- type = sv->sv_type; } ! // If a list or dict variable wasn't initialized and has meaningful ! // type, do it now. Not for global variables, they are not ! // declared. if (ht != &globvarht) { ! if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL ! && type != NULL && type != &t_dict_empty) { tv->vval.v_dict = dict_alloc(); if (tv->vval.v_dict != NULL) *************** *** 2829,2835 **** tv->vval.v_dict->dv_type = alloc_type(type); } } ! else if (tv->v_type == VAR_LIST && tv->vval.v_list == NULL) { tv->vval.v_list = list_alloc(); if (tv->vval.v_list != NULL) --- 2831,2838 ---- tv->vval.v_dict->dv_type = alloc_type(type); } } ! else if (tv->v_type == VAR_LIST && tv->vval.v_list == NULL ! && type != NULL && type != &t_list_empty) { tv->vval.v_list = list_alloc(); if (tv->vval.v_list != NULL) *************** *** 2838,2849 **** tv->vval.v_list->lv_type = alloc_type(type); } } - else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL) - { - tv->vval.v_blob = blob_alloc(); - if (tv->vval.v_blob != NULL) - ++tv->vval.v_blob->bv_refcount; - } } copy_tv(tv, rettv); } --- 2841,2846 ---- *** ../vim-8.2.4633/src/typval.c 2022-03-15 20:21:26.397378123 +0000 --- src/typval.c 2022-03-27 14:59:20.581984323 +0100 *************** *** 1314,1319 **** --- 1314,1332 ---- return FAIL; } } + #ifdef FEAT_JOB_CHANNEL + else if (tv1->v_type == tv2->v_type + && (tv1->v_type == VAR_CHANNEL || tv1->v_type == VAR_JOB) + && (type == EXPR_NEQUAL || type == EXPR_EQUAL)) + { + if (tv1->v_type == VAR_CHANNEL) + n1 = tv1->vval.v_channel == tv2->vval.v_channel; + else + n1 = tv1->vval.v_job == tv2->vval.v_job; + if (type == EXPR_NEQUAL) + n1 = !n1; + } + #endif else { if (typval_compare_string(tv1, tv2, type, ic, &res) == FAIL) *************** *** 1417,1423 **** default: break; } } ! // although comparing null with number, float or bool is not very usefule // we won't give an error return FALSE; } --- 1430,1436 ---- default: break; } } ! // although comparing null with number, float or bool is not very useful // we won't give an error return FALSE; } *** ../vim-8.2.4633/src/testdir/test_vim9_expr.vim 2022-03-22 21:14:51.756456002 +0000 --- src/testdir/test_vim9_expr.vim 2022-03-27 16:27:03.528548998 +0100 *************** *** 754,759 **** --- 754,765 ---- assert_false(v:null != test_null_blob()) assert_false(null != null_blob) + var nb = null_blob + assert_true(nb == null_blob) + assert_true(nb == null) + assert_true(null_blob == nb) + assert_true(null == nb) + if has('channel') assert_true(test_null_channel() == v:null) assert_true(null_channel == null) *************** *** 763,768 **** --- 769,780 ---- assert_false(null_channel != null) assert_false(v:null != test_null_channel()) assert_false(null != null_channel) + + var nc = null_channel + assert_true(nc == null_channel) + assert_true(nc == null) + assert_true(null_channel == nc) + assert_true(null == nc) endif assert_true(test_null_dict() == v:null) *************** *** 779,784 **** --- 791,802 ---- assert_false(g:null_dict != v:null) assert_false(v:null != g:null_dict) + var nd = null_dict + assert_true(nd == null_dict) + assert_true(nd == null) + assert_true(null_dict == nd) + assert_true(null == nd) + assert_true(test_null_function() == v:null) assert_true(null_function == null) assert_true(v:null == test_null_function()) *************** *** 788,793 **** --- 806,817 ---- assert_false(v:null != test_null_function()) assert_false(null != null_function) + var Nf = null_function + assert_true(Nf == null_function) + assert_true(Nf == null) + assert_true(null_function == Nf) + assert_true(null == Nf) + if has('job') assert_true(test_null_job() == v:null) assert_true(null_job == null) *************** *** 797,802 **** --- 821,832 ---- assert_false(null_job != null) assert_false(v:null != test_null_job()) assert_false(null != null_job) + + var nj = null_job + assert_true(nj == null_job) + assert_true(nj == null) + assert_true(null_job == nj) + assert_true(null == nj) endif assert_true(test_null_list() == v:null) *************** *** 813,818 **** --- 843,854 ---- assert_true(g:not_null_list != v:null) assert_true(v:null != g:not_null_list) + var nl = null_list + assert_true(nl == null_list) + assert_true(nl == null) + assert_true(null_list == nl) + assert_true(null == nl) + assert_true(test_null_partial() == v:null) assert_true(null_partial == null) assert_true(v:null == test_null_partial()) *************** *** 822,827 **** --- 858,869 ---- assert_false(v:null != test_null_partial()) assert_false(null != null_partial) + var Np = null_partial + assert_true(Np == null_partial) + assert_true(Np == null) + assert_true(null_partial == Np) + assert_true(null == Np) + assert_true(test_null_string() == v:null) assert_true(null_string == null) assert_true(v:null == test_null_string()) *************** *** 837,842 **** --- 879,890 ---- assert_false(null_string isnot test_null_string()) assert_true(null_string isnot '') assert_true('' isnot null_string) + + var ns = null_string + assert_true(ns == null_string) + assert_true(ns == null) + assert_true(null_string == ns) + assert_true(null == ns) END v9.CheckDefAndScriptSuccess(lines) unlet g:null_dict *** ../vim-8.2.4633/src/testdir/test_vim9_builtin.vim 2022-03-08 19:43:51.688198945 +0000 --- src/testdir/test_vim9_builtin.vim 2022-03-27 14:42:39.454823111 +0100 *************** *** 122,134 **** END v9.CheckDefExecFailure(lines, 'E1131:', 2) ! # Getting variable with NULL blob allocates a new blob at script level lines =<< trim END vim9script var b: blob = test_null_blob() add(b, 123) END ! v9.CheckScriptSuccess(lines) enddef def Test_add_list() --- 122,134 ---- END v9.CheckDefExecFailure(lines, 'E1131:', 2) ! # Getting variable with NULL blob fails lines =<< trim END vim9script var b: blob = test_null_blob() add(b, 123) END ! v9.CheckScriptFailure(lines, 'E1131:', 3) enddef def Test_add_list() *** ../vim-8.2.4633/src/testdir/test_vim9_disassemble.vim 2022-03-22 21:14:51.756456002 +0000 --- src/testdir/test_vim9_disassemble.vim 2022-03-27 16:22:35.709192619 +0100 *************** *** 439,449 **** '\d\+ STORE $\d\_s*' .. 'var dd = null_dict\_s*' .. ! '\d\+ NEWDICT size 0\_s*' .. '\d\+ STORE $\d\_s*' .. 'var ll = null_list\_s*' .. ! '\d\+ NEWLIST size 0\_s*' .. '\d\+ STORE $\d\_s*' .. 'var Ff = null_function\_s*' .. --- 439,449 ---- '\d\+ STORE $\d\_s*' .. 'var dd = null_dict\_s*' .. ! '\d\+ NEWDICT size -1\_s*' .. '\d\+ STORE $\d\_s*' .. 'var ll = null_list\_s*' .. ! '\d\+ NEWLIST size -1\_s*' .. '\d\+ STORE $\d\_s*' .. 'var Ff = null_function\_s*' .. *** ../vim-8.2.4633/src/version.c 2022-03-27 13:36:47.110991835 +0100 --- src/version.c 2022-03-27 14:44:19.102654339 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 4634, /**/ -- ARTHUR: Bloody peasant! DENNIS: Oh, what a give away. Did you hear that, did you hear that, eh? That's what I'm on about -- did you see him repressing me, you saw it didn't you? The Quest for the Holy Grail (Monty Python) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///