# HG changeset patch # User Bram Moolenaar # Date 1648925103 -7200 # Node ID bd1dcc605e58b7bab9a8d5c7905730e9e3c2b211 # Parent e998d4284855c7c01e7fbfa58f25433fa5b9c608 patch 8.2.4666: Vim9: assignment not recognized in skipped block Commit: https://github.com/vim/vim/commit/97f8c1081ec6d6d158bb51e18fa23a36d3ed5623 Author: Bram Moolenaar Date: Sat Apr 2 19:43:57 2022 +0100 patch 8.2.4666: Vim9: assignment not recognized in skipped block Problem: Vim9: assignment not recognized in skipped block. Solution: When skipping assume identifier exists. (closes https://github.com/vim/vim/issues/10059) diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -18,9 +18,9 @@ void fill_exarg_from_cctx(exarg_T *eap, int func_needs_compiling(ufunc_T *ufunc, compiletype_T compile_type); int assignment_len(char_u *p, int *heredoc); void vim9_declare_error(char_u *name); -int get_var_dest(char_u *name, assign_dest_T *dest, int cmdidx, int *option_scope, int *vimvaridx, type_T **type, cctx_T *cctx); -int compile_lhs(char_u *var_start, lhs_T *lhs, int cmdidx, int heredoc, int oplen, cctx_T *cctx); -int compile_assign_lhs(char_u *var_start, lhs_T *lhs, int cmdidx, int is_decl, int heredoc, int oplen, cctx_T *cctx); +int get_var_dest(char_u *name, assign_dest_T *dest, cmdidx_T cmdidx, int *option_scope, int *vimvaridx, type_T **type, cctx_T *cctx); +int compile_lhs(char_u *var_start, lhs_T *lhs, cmdidx_T cmdidx, int heredoc, int has_cmd, int oplen, cctx_T *cctx); +int compile_assign_lhs(char_u *var_start, lhs_T *lhs, cmdidx_T cmdidx, int is_decl, int heredoc, int has_cmd, int oplen, cctx_T *cctx); int compile_load_lhs_with_index(lhs_T *lhs, char_u *var_start, cctx_T *cctx); int compile_assign_unlet(char_u *var_start, lhs_T *lhs, int is_assign, type_T *rhs_type, cctx_T *cctx); compiletype_T get_compile_type(ufunc_T *ufunc); diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -1363,7 +1363,12 @@ def Test_command_not_recognized() var lines =<< trim END d.key = 'asdf' END - v9.CheckDefFailure(lines, 'E1146:', 1) + v9.CheckDefFailure(lines, 'E1089: Unknown variable: d', 1) + + lines =<< trim END + d['key'] = 'asdf' + END + v9.CheckDefFailure(lines, 'E1089: Unknown variable: d', 1) lines =<< trim END if 0 @@ -1371,11 +1376,6 @@ def Test_command_not_recognized() endif END v9.CheckDefSuccess(lines) - - lines =<< trim END - d['key'] = 'asdf' - END - v9.CheckDefFailure(lines, 'E1146:', 1) enddef def Test_magic_not_used() diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -2003,6 +2003,19 @@ def Test_for_skipped_block() assert_equal([3, 4], result) enddef DefFalse() + + def BuildDiagrams() + var diagrams: list + if false + var max = 0 + for v in diagrams + var l = 3 + if max < l | max = l | endif + v->add(l) + endfor + endif + enddef + BuildDiagrams() END v9.CheckDefAndScriptSuccess(lines) enddef diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4666, +/**/ 4665, /**/ 4664, diff --git a/src/vim9cmds.c b/src/vim9cmds.c --- a/src/vim9cmds.c +++ b/src/vim9cmds.c @@ -139,7 +139,7 @@ compile_unlet( // // Figure out the LHS type and other properties. // - ret = compile_lhs(p, &lhs, CMD_unlet, FALSE, 0, cctx); + ret = compile_lhs(p, &lhs, CMD_unlet, FALSE, FALSE, 0, cctx); // Use the info in "lhs" to unlet the item at the index in the // list or dict. @@ -2160,7 +2160,7 @@ compile_redir(char_u *line, exarg_T *eap arg = skipwhite(arg); if (compile_assign_lhs(arg, lhs, CMD_redir, - FALSE, FALSE, 1, cctx) == FAIL) + FALSE, FALSE, FALSE, 1, cctx) == FAIL) return NULL; if (need_type(&t_string, lhs->lhs_member_type, -1, 0, cctx, FALSE, FALSE) == FAIL) diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -279,7 +279,8 @@ variable_exists(char_u *name, size_t len /* * Return TRUE if "name" is a local variable, argument, script variable, - * imported or function. + * imported or function. Or commands are being skipped, a declaration may have + * been skipped then. */ static int item_exists(char_u *name, size_t len, int cmd UNUSED, cctx_T *cctx) @@ -1109,7 +1110,7 @@ vim9_declare_error(char_u *name) get_var_dest( char_u *name, assign_dest_T *dest, - int cmdidx, + cmdidx_T cmdidx, int *option_scope, int *vimvaridx, type_T **type, @@ -1225,7 +1226,7 @@ get_var_dest( } static int -is_decl_command(int cmdidx) +is_decl_command(cmdidx_T cmdidx) { return cmdidx == CMD_let || cmdidx == CMD_var || cmdidx == CMD_final || cmdidx == CMD_const; @@ -1238,12 +1239,13 @@ is_decl_command(int cmdidx) */ int compile_lhs( - char_u *var_start, - lhs_T *lhs, - int cmdidx, - int heredoc, - int oplen, - cctx_T *cctx) + char_u *var_start, + lhs_T *lhs, + cmdidx_T cmdidx, + int heredoc, + int has_cmd, // "var" before "var_start" + int oplen, + cctx_T *cctx) { char_u *var_end; int is_decl = is_decl_command(cmdidx); @@ -1493,7 +1495,8 @@ compile_lhs( semsg(_(e_cannot_use_operator_on_new_variable), lhs->lhs_name); return FAIL; } - if (!is_decl) + if (!is_decl || (lhs->lhs_has_index && !has_cmd + && cctx->ctx_skip != SKIP_YES)) { semsg(_(e_unknown_variable_str), lhs->lhs_name); return FAIL; @@ -1520,9 +1523,12 @@ compile_lhs( char_u *p; // Something follows after the variable: "var[idx]" or "var.key". - if (is_decl) + if (is_decl && cctx->ctx_skip != SKIP_YES) { - emsg(_(e_cannot_use_index_when_declaring_variable)); + if (has_cmd) + emsg(_(e_cannot_use_index_when_declaring_variable)); + else + semsg(_(e_unknown_variable_str), lhs->lhs_name); return FAIL; } @@ -1562,15 +1568,17 @@ compile_lhs( */ int compile_assign_lhs( - char_u *var_start, - lhs_T *lhs, - int cmdidx, - int is_decl, - int heredoc, - int oplen, - cctx_T *cctx) + char_u *var_start, + lhs_T *lhs, + cmdidx_T cmdidx, + int is_decl, + int heredoc, + int has_cmd, // "var" before "var_start" + int oplen, + cctx_T *cctx) { - if (compile_lhs(var_start, lhs, cmdidx, heredoc, oplen, cctx) == FAIL) + if (compile_lhs(var_start, lhs, cmdidx, heredoc, has_cmd, oplen, cctx) + == FAIL) return FAIL; if (!lhs->lhs_has_index && lhs->lhs_lvar == &lhs->lhs_arg_lvar) @@ -2049,7 +2057,8 @@ compile_assignment(char_u *arg, exarg_T * Figure out the LHS type and other properties. */ if (compile_assign_lhs(var_start, &lhs, cmdidx, - is_decl, heredoc, oplen, cctx) == FAIL) + is_decl, heredoc, var_start > eap->cmd, + oplen, cctx) == FAIL) goto theend; if (heredoc) { @@ -2769,6 +2778,7 @@ compile_def_function( CLEAR_FIELD(ea); ea.cmdlinep = &line; ea.cmd = skipwhite(line); + ea.skip = cctx.ctx_skip == SKIP_YES; if (*ea.cmd == '#') { @@ -2957,15 +2967,17 @@ compile_def_function( if (p == ea.cmd && ea.cmdidx != CMD_SIZE) { - if (cctx.ctx_skip == SKIP_YES && ea.cmdidx != CMD_eval) + // "eval" is used for "val->func()" and "var" for "var = val", then + // "p" is equal to "ea.cmd" for a valid command. + if (ea.cmdidx == CMD_eval || ea.cmdidx == CMD_var) + ; + else if (cctx.ctx_skip == SKIP_YES) { line += STRLEN(line); goto nextline; } - else if (ea.cmdidx != CMD_eval) + else { - // CMD_var cannot happen, compile_assignment() above would be - // used. Most likely an assignment to a non-existing variable. semsg(_(e_command_not_recognized_str), ea.cmd); goto erret; }