changeset 28281:bd1dcc605e58 v8.2.4666

patch 8.2.4666: Vim9: assignment not recognized in skipped block Commit: https://github.com/vim/vim/commit/97f8c1081ec6d6d158bb51e18fa23a36d3ed5623 Author: Bram Moolenaar <Bram@vim.org> 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)
author Bram Moolenaar <Bram@vim.org>
date Sat, 02 Apr 2022 20:45:03 +0200
parents e998d4284855
children 548b4ab77157
files src/proto/vim9compile.pro src/testdir/test_vim9_cmd.vim src/testdir/test_vim9_script.vim src/version.c src/vim9cmds.c src/vim9compile.c
diffstat 6 files changed, 63 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- 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);
--- 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()
--- 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<any>
+      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
--- 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,
--- 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)
--- 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;
 	    }