diff src/vim9compile.c @ 27611:e311a80f8cbe v8.2.4332

patch 8.2.4332: Vim9: incomplete test for existing script variable in block Commit: https://github.com/vim/vim/commit/dce2441a603f2c9343a4a46091283a32420d80a2 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Feb 8 20:35:30 2022 +0000 patch 8.2.4332: Vim9: incomplete test for existing script variable in block Problem: Vim9: incomplete test for existing script variable in block. Solution: Add a couple more tests. Fix uncovered problem.
author Bram Moolenaar <Bram@vim.org>
date Tue, 08 Feb 2022 21:45:03 +0100
parents d504745607bc
children 42d0279c6e7c
line wrap: on
line diff
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -152,11 +152,12 @@ arg_exists(
  * Lookup a script-local variable in the current script, possibly defined in a
  * block that contains the function "cctx->ctx_ufunc".
  * "cctx" is NULL at the script level.
+ * "cstack_T" is NULL in a function.
  * If "len" is <= 0 "name" must be NUL terminated.
  * Return NULL when not found.
  */
     static sallvar_T *
-find_script_var(char_u *name, size_t len, cctx_T *cctx)
+find_script_var(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack)
 {
     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
     hashitem_T	    *hi;
@@ -183,11 +184,22 @@ find_script_var(char_u *name, size_t len
 
     if (cctx == NULL)
     {
-	// Not in a function scope, find variable with block id equal to or
-	// smaller than the current block id.
+	// Not in a function scope, find variable with block ID equal to or
+	// smaller than the current block id.  If "cstack" is not NULL go up
+	// the block scopes (more accurate).
 	while (sav != NULL)
 	{
-	    if (sav->sav_block_id <= si->sn_current_block_id)
+	    if (cstack != NULL)
+	    {
+		int idx;
+
+		for (idx = cstack->cs_idx; idx >= 0; --idx)
+		    if (cstack->cs_block_id[idx] == sav->sav_block_id)
+			break;
+		if (idx >= 0)
+		    break;
+	    }
+	    else if (sav->sav_block_id <= si->sn_current_block_id)
 		break;
 	    sav = sav->sav_next;
 	}
@@ -225,10 +237,11 @@ script_is_vim9()
 /*
  * Lookup a variable (without s: prefix) in the current script.
  * "cctx" is NULL at the script level.
+ * "cstack" is NULL in a function.
  * Returns OK or FAIL.
  */
     int
-script_var_exists(char_u *name, size_t len, cctx_T *cctx)
+script_var_exists(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack)
 {
     if (current_sctx.sc_sid <= 0)
 	return FAIL;
@@ -236,7 +249,7 @@ script_var_exists(char_u *name, size_t l
     {
 	// Check script variables that were visible where the function was
 	// defined.
-	if (find_script_var(name, len, cctx) != NULL)
+	if (find_script_var(name, len, cctx, cstack) != NULL)
 	    return OK;
     }
     else
@@ -267,7 +280,7 @@ variable_exists(char_u *name, size_t len
     return (cctx != NULL
 		&& (lookup_local(name, len, NULL, cctx) == OK
 		    || arg_exists(name, len, NULL, NULL, NULL, cctx) == OK))
-	    || script_var_exists(name, len, cctx) == OK
+	    || script_var_exists(name, len, cctx, NULL) == OK
 	    || find_imported(name, len, FALSE, cctx) != NULL;
 }
 
@@ -309,7 +322,12 @@ item_exists(char_u *name, size_t len, in
  * Return FAIL and give an error if it defined.
  */
     int
-check_defined(char_u *p, size_t len, cctx_T *cctx, int is_arg)
+check_defined(
+	char_u	    *p,
+	size_t	    len,
+	cctx_T	    *cctx,
+	cstack_T    *cstack,
+	int	    is_arg)
 {
     int		c = p[len];
     ufunc_T	*ufunc = NULL;
@@ -318,7 +336,7 @@ check_defined(char_u *p, size_t len, cct
     if (len == 1 && *p == '_')
 	return OK;
 
-    if (script_var_exists(p, len, cctx) == OK)
+    if (script_var_exists(p, len, cctx, cstack) == OK)
     {
 	if (is_arg)
 	    semsg(_(e_argument_already_declared_in_script_str), p);
@@ -526,7 +544,7 @@ get_script_item_idx(int sid, char_u *nam
 	return -1;
     if (sid == current_sctx.sc_sid)
     {
-	sallvar_T *sav = find_script_var(name, 0, cctx);
+	sallvar_T *sav = find_script_var(name, 0, cctx, NULL);
 
 	if (sav == NULL)
 	    return -2;
@@ -884,7 +902,8 @@ compile_nested_function(exarg_T *eap, cc
 	semsg(_(e_namespace_not_supported_str), name_start);
 	return NULL;
     }
-    if (check_defined(name_start, name_end - name_start, cctx, FALSE) == FAIL)
+    if (check_defined(name_start, name_end - name_start, cctx,
+							  NULL, FALSE) == FAIL)
 	return NULL;
     if (!ASCII_ISUPPER(is_global ? name_start[2] : name_start[0]))
     {
@@ -1356,9 +1375,9 @@ compile_lhs(
 				       && STRNCMP(var_start, "s:", 2) == 0;
 		int script_var = (script_namespace
 			? script_var_exists(var_start + 2, lhs->lhs_varlen - 2,
-									  cctx)
+								    cctx, NULL)
 			  : script_var_exists(var_start, lhs->lhs_varlen,
-								  cctx)) == OK;
+							    cctx, NULL)) == OK;
 		imported_T  *import =
 			find_imported(var_start, lhs->lhs_varlen, FALSE, cctx);
 
@@ -1442,8 +1461,8 @@ compile_lhs(
 			}
 		    }
 		}
-		else if (check_defined(var_start, lhs->lhs_varlen, cctx, FALSE)
-								       == FAIL)
+		else if (check_defined(var_start, lhs->lhs_varlen, cctx,
+							  NULL, FALSE) == FAIL)
 		    return FAIL;
 	    }
 	}
@@ -2470,7 +2489,7 @@ check_args_shadowing(ufunc_T *ufunc, cct
     for (i = 0; i < ufunc->uf_args.ga_len; ++i)
     {
 	arg = ((char_u **)(ufunc->uf_args.ga_data))[i];
-	if (check_defined(arg, STRLEN(arg), cctx, TRUE) == FAIL)
+	if (check_defined(arg, STRLEN(arg), cctx, NULL, TRUE) == FAIL)
 	{
 	    r = FAIL;
 	    break;