patch 9.1.0360: Vim9: does not handle autoloaded variables well

Commit: 
https://github.com/vim/vim/commit/84f6dc7ed29d52b1034bfb27bdcd3154a01ee2b1
Author: Ernie Rael <err...@raelity.com>
Date:   Sun Apr 21 14:45:48 2024 +0200

    patch 9.1.0360: Vim9: does not handle autoloaded variables well
    
    Problem:  Vim9: does not handle autoloaded variables well
    Solution: Better handle script-level exported variable references from
              autoload files (Ernie Rael).
    
    fixes: #14591
    closes: #14607
    
    Signed-off-by: Ernie Rael <err...@raelity.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/evalvars.c b/src/evalvars.c
index 70bb6da2c..b70a3cd39 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -3340,12 +3340,31 @@ find_var(char_u *name, hashtab_T **htp, int no_autoload)
        }
     }
 
+    // and finally try
+    return find_var_autoload_prefix(name, 0, htp, NULL);
+}
+
+/*
+ * Find variable "name" with sn_autoload_prefix.
+ * Return a pointer to it if found, NULL if not found.
+ * When "sid" > 0, use it otherwise use "current_sctx.sc_sid".
+ * When "htp" is not NULL  set "htp" to the hashtab_T used.
+ * When "namep" is not NULL set "namep" to the generated name, and
+ * then the caller gets ownership and is responsible for freeing the name.
+ */
+    dictitem_T *
+find_var_autoload_prefix(char_u *name, int sid, hashtab_T **htp,
+                                                           char_u **namep)
+{
+    hashtab_T  *ht;
+    dictitem_T *ret = NULL;
     // When using "vim9script autoload" script-local items are prefixed but can
     // be used with s:name.
-    if (SCRIPT_ID_VALID(current_sctx.sc_sid)
+    int check_sid = sid > 0 ? sid : current_sctx.sc_sid;
+    if (SCRIPT_ID_VALID(check_sid)
                   && (in_vim9script() || (name[0] == 's' && name[1] == ':')))
     {
-       scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
+       scriptitem_T *si = SCRIPT_ITEM(check_sid);
 
        if (si->sn_autoload_prefix != NULL)
        {
@@ -3355,20 +3374,26 @@ find_var(char_u *name, hashtab_T **htp, int no_autoload)
 
            if (auto_name != NULL)
            {
+               int free_auto_name = TRUE;
                ht = &globvarht;
                ret = find_var_in_ht(ht, 'g', auto_name, TRUE);
-               vim_free(auto_name);
                if (ret != NULL)
                {
                    if (htp != NULL)
                        *htp = ht;
-                   return ret;
+                   if (namep != NULL)
+                   {
+                       free_auto_name = FALSE;
+                       *namep = auto_name;
+                   }
                }
+               if (free_auto_name)
+                   vim_free(auto_name);
            }
        }
     }
 
-    return NULL;
+    return ret;
 }
 
 /*
@@ -3508,7 +3533,11 @@ lookup_scriptitem(
     hi = hash_find(ht, p);
     res = HASHITEM_EMPTY(hi) ? FAIL : OK;
 
-    // if not script-local, then perhaps imported
+    // if not script-local, then perhaps autoload-exported
+    if (res == FAIL && find_var_autoload_prefix(p, 0, NULL, NULL) != NULL)
+       res = OK;
+
+    // if not script-local or autoload, then perhaps imported
     if (res == FAIL && find_imported(p, 0, FALSE) != NULL)
        res = OK;
     if (p != buffer)
@@ -3904,23 +3933,40 @@ set_var_const(
 
     if (sid != 0)
     {
+       varname = NULL;
        if (SCRIPT_ID_VALID(sid))
-           ht = &SCRIPT_VARS(sid);
-       varname = name;
+       {
+           char_u      *auto_name = NULL;
+           if (find_var_autoload_prefix(name, sid, &ht, &auto_name) != NULL)
+           {
+               var_in_autoload = TRUE;
+               varname = auto_name;
+               name_tofree = varname;
+           }
+           else
+               ht = &SCRIPT_VARS(sid);
+       }
+       if (varname == NULL)
+           varname = name;
     }
     else
     {
-       scriptitem_T *si;
+       scriptitem_T    *si;
+       char_u          *auto_name = NULL;
 
-       if (in_vim9script() && is_export
-               && SCRIPT_ID_VALID(current_sctx.sc_sid)
-               && (si = SCRIPT_ITEM(current_sctx.sc_sid))
-                                                 ->sn_autoload_prefix != NULL)
+       if (in_vim9script()
+           && SCRIPT_ID_VALID(current_sctx.sc_sid)
+           && (si = SCRIPT_ITEM(current_sctx.sc_sid))
+                                             ->sn_autoload_prefix != NULL
+           && (is_export
+               || find_var_autoload_prefix(name, 0, NULL, &auto_name)
+                                                                   != NULL))
        {
            // In a vim9 autoload script an exported variable is put in the
            // global namespace with the autoload prefix.
            var_in_autoload = TRUE;
-           varname = concat_str(si->sn_autoload_prefix, name);
+           varname = auto_name != NULL ? auto_name
+                     : concat_str(si->sn_autoload_prefix, name);
            if (varname == NULL)
                goto failed;
            name_tofree = varname;
diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro
index ea14fe5ce..a0e010001 100644
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -63,6 +63,7 @@ int eval_variable(char_u *name, int len, scid_T sid, typval_T 
*rettv, dictitem_T
 int eval_variable_import(char_u *name, typval_T *rettv);
 void check_vars(char_u *name, int len);
 dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
+dictitem_T *find_var_autoload_prefix(char_u *name, int sid, hashtab_T **htp, 
char_u **namep);
 dictitem_T *find_var_also_in_script(char_u *name, hashtab_T **htp, int 
no_autoload);
 dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int 
no_autoload);
 hashtab_T *get_script_local_ht(void);
diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim
index 78383ee79..cfab50d58 100644
--- a/src/testdir/test_vim9_import.vim
+++ b/src/testdir/test_vim9_import.vim
@@ -1201,6 +1201,71 @@ def Test_autoload_import_relative_from_buffer_in_dir()
   :bw!
 enddef
 
+" Test modifying exported autoload variable. Github issue: #14591
+def Test_autoload_export_variables()
+  mkdir('Xautoload_vars/autoload', 'pR')
+  var lines =<< trim END
+    vim9script
+    export var val = 11
+    val = 42
+  END
+
+  # Test that the imported script, above, can modify the exported variable;
+  # and test that the importing script, below, can modify the variable.
+  writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f2.vim', 'D')
+  lines =<< trim END
+    vim9script
+
+    import autoload './Xautoload_vars/autoload/Xauto_vars_f2.vim' as f2
+
+    def F(): number
+      return f2.val
+    enddef
+    assert_equal(42, F())
+    assert_equal(42, f2.val)
+    f2.val = 17
+    assert_equal(17, f2.val)
+
+    def G()
+      f2.val = 19
+    enddef
+    G()
+    assert_equal(19, f2.val)
+  END
+  v9.CheckScriptSuccess(lines)
+
+  # Test const var is not modifiable.
+  lines =<< trim END
+    vim9script
+    export const val = 11
+    val = 42
+  END
+  writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f3.vim', 'D')
+  lines =<< trim END
+    vim9script
+
+    import autoload './Xautoload_vars/autoload/Xauto_vars_f3.vim' as f3
+
+    var x = f3.val
+  END
+  v9.CheckScriptFailure(lines, 'E46:')
+
+  # Test const var is not modifiable from importing script.
+  lines =<< trim END
+    vim9script
+    export const val = 11
+  END
+  writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f4.vim', 'D')
+  lines =<< trim END
+    vim9script
+
+    import autoload './Xautoload_vars/autoload/Xauto_vars_f4.vim' as f4
+
+    f4.val = 13
+  END
+  v9.CheckScriptFailure(lines, 'E46:')
+enddef
+
 def Test_autoload_import_relative_autoload_dir()
   mkdir('autoload', 'pR')
   var lines =<< trim END
diff --git a/src/version.c b/src/version.c
index 9e2acb87e..d418b602b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    360,
 /**/
     359,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1ryWnb-006Hmi-8I%40256bit.org.

Raspunde prin e-mail lui