To: vim_dev@googlegroups.com Subject: Patch 8.2.3339 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3339 Problem: Vim9: cannot lock a member in a local dict. Solution: Get the local dict from the stack and pass it to get_lval(). Files: src/eval.c, src/vim9execute.c, src/vim9compile.c, src/vim9.h, src/globals.h, src/testdir/test_vim9_cmd.vim, src/testdir/test_vim9_disassemble.vim *** ../vim-8.2.3338/src/eval.c 2021-08-11 21:49:19.626869328 +0200 --- src/eval.c 2021-08-13 18:58:32.241535354 +0200 *************** *** 902,918 **** if ((*p != '[' && *p != '.') || lp->ll_name == NULL) return p; ! cc = *p; ! *p = NUL; ! // When we would write to the variable pass &ht and prevent autoload. ! writing = !(flags & GLV_READ_ONLY); ! v = find_var(lp->ll_name, writing ? &ht : NULL, (flags & GLV_NO_AUTOLOAD) || writing); ! if (v == NULL && !quiet) ! semsg(_(e_undefined_variable_str), lp->ll_name); ! *p = cc; ! if (v == NULL) ! return NULL; if (in_vim9script() && (flags & GLV_NO_DECL) == 0) { --- 902,927 ---- if ((*p != '[' && *p != '.') || lp->ll_name == NULL) return p; ! if (in_vim9script() && lval_root != NULL) ! { ! // using local variable ! lp->ll_tv = lval_root; ! } ! else ! { ! cc = *p; ! *p = NUL; ! // When we would write to the variable pass &ht and prevent autoload. ! writing = !(flags & GLV_READ_ONLY); ! v = find_var(lp->ll_name, writing ? &ht : NULL, (flags & GLV_NO_AUTOLOAD) || writing); ! if (v == NULL && !quiet) ! semsg(_(e_undefined_variable_str), lp->ll_name); ! *p = cc; ! if (v == NULL) ! return NULL; ! lp->ll_tv = &v->di_tv; ! } if (in_vim9script() && (flags & GLV_NO_DECL) == 0) { *************** *** 924,930 **** /* * Loop until no more [idx] or .key is following. */ - lp->ll_tv = &v->di_tv; var1.v_type = VAR_UNKNOWN; var2.v_type = VAR_UNKNOWN; while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.')) --- 933,938 ---- *** ../vim-8.2.3338/src/vim9execute.c 2021-08-11 21:49:19.626869328 +0200 --- src/vim9execute.c 2021-08-13 19:25:54.238568203 +0200 *************** *** 1396,1401 **** --- 1396,1422 ---- return OK; } + /* + * Execute iptr->isn_arg.string as an Ex command. + */ + static int + exec_command(isn_T *iptr) + { + source_cookie_T cookie; + + SOURCING_LNUM = iptr->isn_lnum; + // Pass getsourceline to get an error for a missing ":end" + // command. + CLEAR_FIELD(cookie); + cookie.sourcing_lnum = iptr->isn_lnum - 1; + if (do_cmdline(iptr->isn_arg.string, + getsourceline, &cookie, + DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED) == FAIL + || did_emsg) + return FAIL; + return OK; + } + // used for v_instr of typval of VAR_INSTR struct instr_S { ectx_T *instr_ectx; *************** *** 1637,1657 **** { // execute Ex command line case ISN_EXEC: ! { ! source_cookie_T cookie; ! ! SOURCING_LNUM = iptr->isn_lnum; ! // Pass getsourceline to get an error for a missing ":end" ! // command. ! CLEAR_FIELD(cookie); ! cookie.sourcing_lnum = iptr->isn_lnum - 1; ! if (do_cmdline(iptr->isn_arg.string, ! getsourceline, &cookie, ! DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED) ! == FAIL ! || did_emsg) ! goto on_error; ! } break; // execute Ex command line split at NL characters. --- 1658,1665 ---- { // execute Ex command line case ISN_EXEC: ! if (exec_command(iptr) == FAIL) ! goto on_error; break; // execute Ex command line split at NL characters. *************** *** 2880,2885 **** --- 2888,2910 ---- vim_unsetenv(iptr->isn_arg.unlet.ul_name); break; + case ISN_LOCKUNLOCK: + { + typval_T *lval_root_save = lval_root; + int res; + + // Stack has the local variable, argument the whole :lock + // or :unlock command, like ISN_EXEC. + --ectx->ec_stack.ga_len; + lval_root = STACK_TV_BOT(0); + res = exec_command(iptr); + clear_tv(lval_root); + lval_root = lval_root_save; + if (res == FAIL) + goto on_error; + } + break; + case ISN_LOCKCONST: item_lock(STACK_TV_BOT(-1), 100, TRUE, TRUE); break; *************** *** 5244,5249 **** --- 5269,5277 ---- case ISN_UNLETRANGE: smsg("%s%4d UNLETRANGE", pfx, current); break; + case ISN_LOCKUNLOCK: + smsg("%s%4d LOCKUNLOCK %s", pfx, current, iptr->isn_arg.string); + break; case ISN_LOCKCONST: smsg("%s%4d LOCKCONST", pfx, current); break; *** ../vim-8.2.3338/src/vim9compile.c 2021-08-12 17:06:01.392925681 +0200 --- src/vim9compile.c 2021-08-13 19:26:07.514548558 +0200 *************** *** 2262,2273 **** } static int ! generate_EXEC(cctx_T *cctx, char_u *line) { isn_T *isn; RETURN_OK_IF_SKIP(cctx); ! if ((isn = generate_instr(cctx, ISN_EXEC)) == NULL) return FAIL; isn->isn_arg.string = vim_strsave(line); return OK; --- 2262,2273 ---- } static int ! generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *line) { isn_T *isn; RETURN_OK_IF_SKIP(cctx); ! if ((isn = generate_instr(cctx, isntype)) == NULL) return FAIL; isn->isn_arg.string = vim_strsave(line); return OK; *************** *** 7426,7431 **** --- 7426,7432 ---- int ret = OK; size_t len; char_u *buf; + isntype_T isn = ISN_EXEC; if (cctx->ctx_skip == SKIP_YES) return OK; *************** *** 7437,7444 **** if (lookup_local(p, end - p, NULL, cctx) == OK) { ! emsg(_(e_cannot_lock_unlock_local_variable)); ! return FAIL; } } --- 7438,7456 ---- if (lookup_local(p, end - p, NULL, cctx) == OK) { ! char_u *s = p; ! ! if (*end != '.' && *end != '[') ! { ! emsg(_(e_cannot_lock_unlock_local_variable)); ! return FAIL; ! } ! ! // For "d.member" put the local variable on the stack, it will be ! // passed to ex_lockvar() indirectly. ! if (compile_load(&s, end, cctx, FALSE, FALSE) == FAIL) ! return FAIL; ! isn = ISN_LOCKUNLOCK; } } *************** *** 7453,7459 **** vim_snprintf((char *)buf, len, "%s %s", eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar", p); ! ret = generate_EXEC(cctx, buf); vim_free(buf); *name_end = cc; --- 7465,7471 ---- vim_snprintf((char *)buf, len, "%s %s", eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar", p); ! ret = generate_EXEC(cctx, isn, buf); vim_free(buf); *name_end = cc; *************** *** 9110,9116 **** generate_EXECCONCAT(cctx, count); } else ! generate_EXEC(cctx, line); theend: if (*nextcmd != NUL) --- 9122,9128 ---- generate_EXECCONCAT(cctx, count); } else ! generate_EXEC(cctx, ISN_EXEC, line); theend: if (*nextcmd != NUL) *************** *** 10198,10203 **** --- 10210,10216 ---- case ISN_LOADOPT: case ISN_LOADT: case ISN_LOADW: + case ISN_LOCKUNLOCK: case ISN_PUSHEXC: case ISN_PUSHFUNC: case ISN_PUSHS: *** ../vim-8.2.3338/src/vim9.h 2021-08-07 15:05:44.707105779 +0200 --- src/vim9.h 2021-08-13 19:09:32.924125204 +0200 *************** *** 70,75 **** --- 70,76 ---- ISN_UNLETINDEX, // unlet item of list or dict ISN_UNLETRANGE, // unlet items of list + ISN_LOCKUNLOCK, // :lock and :unlock for local variable member ISN_LOCKCONST, // lock constant value // constants *** ../vim-8.2.3338/src/globals.h 2021-07-28 16:51:49.857364325 +0200 --- src/globals.h 2021-08-13 19:19:12.567060140 +0200 *************** *** 1835,1840 **** --- 1835,1842 ---- #endif #ifdef FEAT_EVAL EXTERN int input_busy INIT(= 0); // when inside get_user_input() then > 0 + + EXTERN typval_T *lval_root INIT(= NULL); #endif #ifdef FEAT_BEVAL_TERM *** ../vim-8.2.3338/src/testdir/test_vim9_cmd.vim 2021-08-10 19:52:57.474235537 +0200 --- src/testdir/test_vim9_cmd.vim 2021-08-13 19:32:12.881957940 +0200 *************** *** 1195,1200 **** --- 1195,1217 ---- s:theList[1] = 44 assert_equal([1, 44, 3], s:theList) + var d = {a: 1, b: 2} + d.a = 3 + d.b = 4 + assert_equal({a: 3, b: 4}, d) + lockvar d.a + d.b = 5 + var ex = '' + try + d.a = 6 + catch + ex = v:exception + endtry + assert_match('E1121:', ex) + unlockvar d.a + d.a = 7 + assert_equal({a: 7, b: 5}, d) + var lines =<< trim END vim9script var theList = [1, 2, 3] *** ../vim-8.2.3338/src/testdir/test_vim9_disassemble.vim 2021-08-10 22:51:59.369449616 +0200 --- src/testdir/test_vim9_disassemble.vim 2021-08-13 19:39:26.217179419 +0200 *************** *** 588,593 **** --- 588,612 ---- res) enddef + def s:LockLocal() + var d = {a: 1} + lockvar d.a + enddef + + def Test_disassemble_locl_local() + var res = execute('disass s:LockLocal') + assert_match('\d*_LockLocal\_s*' .. + 'var d = {a: 1}\_s*' .. + '\d PUSHS "a"\_s*' .. + '\d PUSHNR 1\_s*' .. + '\d NEWDICT size 1\_s*' .. + '\d STORE $0\_s*' .. + 'lockvar d.a\_s*' .. + '\d LOAD $0\_s*' .. + '\d LOCKUNLOCK lockvar d.a\_s*', + res) + enddef + def s:ScriptFuncTry() try echo "yes" *** ../vim-8.2.3338/src/version.c 2021-08-13 18:19:54.678450486 +0200 --- src/version.c 2021-08-13 19:08:31.736257971 +0200 *************** *** 757,758 **** --- 757,760 ---- { /* Add new patch number below this line */ + /**/ + 3339, /**/ -- TIM: But follow only if you are men of valour. For the entrance to this cave is guarded by a monster, a creature so foul and cruel that no man yet has fought with it and lived. Bones of full fifty men lie strewn about its lair ... "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// 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 ///