patch 9.1.0369: Vim9: problem when importing autoloaded scripts

Commit: 
https://github.com/vim/vim/commit/3f821d6de2586d921fb23e2facb4764ef9eb3294
Author: Ernie Rael <err...@raelity.com>
Date:   Wed Apr 24 20:07:50 2024 +0200

    patch 9.1.0369: Vim9: problem when importing autoloaded scripts
    
    Problem:  Vim9: problem when importing autoloaded scripts
    Solution: In `:def` handle storing to vim9 autoload export
              (Ernie Rael)
    
    Problem occurs when `import autoload ./.../autoload/...`. The autoload
    in the specified path causes the use of an autoload_prefix which combines
    with the `import autoload` to create trouble.
    
    In `generate_store_var()` `case dest_script` use ISN_STOREEXPORT,
    when needed, instead of ISN_STORES. When executing ISN_STOREEXPORT,
    check for autoload_prefix.
    
    fixes: #14606
    closes: #14615
    
    Signed-off-by: Ernie Rael <err...@raelity.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>
    Signed-off-by: Yegappan Lakshmanan <yegap...@yahoo.com>

diff --git a/src/evalvars.c b/src/evalvars.c
index b70a3cd39..6facbeb13 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -4235,6 +4235,7 @@ failed:
  * - Whether the variable is read-only
  * - Whether the variable value is locked
  * - Whether the variable is locked
+ * NOTE: "name" is only used for error messages.
  */
     int
 var_check_permission(dictitem_T *di, char_u *name)
diff --git a/src/testdir/test_vim9_disassemble.vim 
b/src/testdir/test_vim9_disassemble.vim
index 92a4ff2a6..c74cce448 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -381,6 +381,34 @@ def Test_disassemble_import_autoload()
   v9.CheckScriptSuccess(lines)
 enddef
 
+def Test_disassemble_import_autoload_autoload()
+  mkdir('Xauto_auto/autoload', 'pR')
+  var lines =<< trim END
+    vim9script
+    export const val = 11
+  END
+  writefile(lines, 'Xauto_auto/autoload/Xauto_vars_f1.vim')
+
+  lines =<< trim END
+    vim9script
+
+    import autoload './Xauto_auto/autoload/Xauto_vars_f1.vim' as f1
+    def F()
+        f1.val = 13
+    enddef
+    var res = execute('disass F')
+
+    assert_match('<SNR>\d*_F.*' ..
+      'f1.val = 13\_s*' ..
+      '\d PUSHNR 13\_s*' ..
+      '\d SOURCE .*/Xauto_auto/autoload/Xauto_vars_f1.vim\_s*' ..
+      '\d STOREEXPORT val in .*/Xauto_auto/autoload/Xauto_vars_f1.vim\_s*' ..
+      '\d RETURN void',
+      res)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
 def s:ScriptFuncStore()
   var localnr = 1
   localnr = 2
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index 27585a904..b00892961 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -166,6 +166,37 @@ def Test_wrong_function_name()
   delfunc g:Define
 enddef
 
+" Check that in a legacy script a :def accesses the correct script variables.
+" Github issue: #14615.
+def Test_access_var_from_legacy_def()
+  # Access a script variable by name WITH "s:" prefix.
+  var lines =<< trim END
+    let s:foo = 'init'
+    let s:xxfoo = 'init'
+    def! AccessVarFromLegacyDef()
+        s:xxfoo = 'CHANGED'
+    enddef
+    call AccessVarFromLegacyDef()
+    call assert_equal('init', s:foo)
+    call assert_equal('CHANGED', s:xxfoo)
+  END
+  v9.CheckScriptSuccess(lines)
+
+  # Access a script variable by name WITHOUT "s:" prefix;
+  # previously this accessed "foo" and not "xxfoo"
+  lines =<< trim END
+    let s:foo = 'init'
+    let s:xxfoo = 'init'
+    def! AccessVarFromLegacyDef()
+        xxfoo = 'CHANGED'
+    enddef
+    call AccessVarFromLegacyDef()
+    call assert_equal('init', s:foo)
+    call assert_equal('CHANGED', s:xxfoo)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
 def Test_listing_function_error()
   var lines =<< trim END
       var filler = 123
diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim
index cfab50d58..581925d24 100644
--- a/src/testdir/test_vim9_import.vim
+++ b/src/testdir/test_vim9_import.vim
@@ -1206,6 +1206,7 @@ def Test_autoload_export_variables()
   mkdir('Xautoload_vars/autoload', 'pR')
   var lines =<< trim END
     vim9script
+    g:Xautoload_vars_autoload = true
     export var val = 11
     val = 42
   END
@@ -1215,13 +1216,24 @@ def Test_autoload_export_variables()
   writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f2.vim', 'D')
   lines =<< trim END
     vim9script
+    g:Xautoload_vars_autoload = false
 
     import autoload './Xautoload_vars/autoload/Xauto_vars_f2.vim' as f2
+    # Verify that the import statement does not load the file.
+    assert_equal(false, g:Xautoload_vars_autoload)
 
     def F(): number
       return f2.val
     enddef
+    # Verify compile does not load the file.
+    defcompile F
+    assert_equal(false, g:Xautoload_vars_autoload)
+
+    # load the file by accessing the exported variable
     assert_equal(42, F())
+    assert_equal(true, g:Xautoload_vars_autoload)
+    unlet g:Xautoload_vars_autoload
+
     assert_equal(42, f2.val)
     f2.val = 17
     assert_equal(17, f2.val)
@@ -1264,6 +1276,44 @@ def Test_autoload_export_variables()
     f4.val = 13
   END
   v9.CheckScriptFailure(lines, 'E46:')
+
+  # Test const var is not modifiable from importing script from :def.
+  # Github issue: #14606
+  lines =<< trim END
+    vim9script
+    export const val = 11
+  END
+  writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f5.vim', 'D')
+  lines =<< trim END
+    vim9script
+
+    import autoload './Xautoload_vars/autoload/Xauto_vars_f5.vim' as f5
+
+    def F()
+      f5.val = 13
+    enddef
+    F()
+  END
+  v9.CheckScriptFailure(lines, 'E741:')
+
+  # Still part of Github issue: #14606
+  lines =<< trim END
+    vim9script
+    export var val = 11
+  END
+  writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f6.vim', 'D')
+  lines =<< trim END
+    vim9script
+
+    import autoload './Xautoload_vars/autoload/Xauto_vars_f6.vim' as f6
+
+    def F()
+      f6.val = 13
+    enddef
+    F()
+    assert_equal(13, f6.val)
+  END
+  v9.CheckScriptSuccess(lines)
 enddef
 
 def Test_autoload_import_relative_autoload_dir()
diff --git a/src/version.c b/src/version.c
index feed8385e..658a41027 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 */
+/**/
+    369,
 /**/
     368,
 /**/
diff --git a/src/vim9.h b/src/vim9.h
index 65de61820..54938fe20 100644
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -780,6 +780,7 @@ typedef enum {
     dest_vimvar,
     dest_class_member,
     dest_script,
+    dest_script_v9,
     dest_reg,
     dest_expr,
 } assign_dest_T;
diff --git a/src/vim9compile.c b/src/vim9compile.c
index a091c5796..4cbc1cf05 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1367,6 +1367,7 @@ generate_loadvar(cctx_T *cctx, lhs_T *lhs)
            generate_LOAD(cctx, ISN_LOADT, 0, name + 2, type);
            break;
        case dest_script:
+       case dest_script_v9:
            res = compile_load_scriptvar(cctx,
                                  name + (name[1] == ':' ? 2 : 0), NULL, NULL);
            break;
@@ -1838,7 +1839,8 @@ compile_lhs(
                        return FAIL;
                    }
 
-                   lhs->lhs_dest = dest_script;
+                   lhs->lhs_dest = current_script_is_vim9()
+                             ? dest_script_v9 : dest_script;
 
                    // existing script-local variables should have a type
                    lhs->lhs_scriptvar_sid = current_sctx.sc_sid;
@@ -3026,8 +3028,9 @@ compile_assignment(
        else
        {
            if (is_decl && cmdidx == CMD_const && (lhs.lhs_dest == dest_script
-                                               || lhs.lhs_dest == dest_global
-                                               || lhs.lhs_dest == dest_local))
+                                           || lhs.lhs_dest == dest_script_v9
+                                           || lhs.lhs_dest == dest_global
+                                           || lhs.lhs_dest == dest_local))
                // ":const var": lock the value, but not referenced variables
                generate_LOCKCONST(cctx);
 
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 5af3af68b..3a3960a8d 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -3842,11 +3842,19 @@ exec_instructions(ectx_T *ectx)
            case ISN_STOREEXPORT:
                {
                    int         sid = iptr->isn_arg.loadstore.ls_sid;
-                   hashtab_T   *ht = &SCRIPT_VARS(sid);
                    char_u      *name = iptr->isn_arg.loadstore.ls_name;
-                   dictitem_T  *di = find_var_in_ht(ht, 0,
-                                           iptr->isn_type == ISN_STORES
+                   dictitem_T  *di = NULL;
+                   // First check for a variable from an exported autoload
+                   // with an autoload_prefix; it would be in globals.
+                   if (iptr->isn_type == ISN_STOREEXPORT)
+                       di = find_var_autoload_prefix(name, sid, NULL, NULL);
+                   // Then look for a variable in the script's variables.
+                   if (di == NULL)
+                   {
+                       hashtab_T       *ht = &SCRIPT_VARS(sid);
+                       di = find_var_in_ht(ht, 0, STRNCMP("s:", name, 2) == 0
                                                     ? name + 2 : name, TRUE);
+                   }
 
                    --ectx->ec_stack.ga_len;
                    SOURCING_LNUM = iptr->isn_lnum;
diff --git a/src/vim9instr.c b/src/vim9instr.c
index 4df63fd09..ad8beb1a3 100644
--- a/src/vim9instr.c
+++ b/src/vim9instr.c
@@ -2394,6 +2394,7 @@ generate_store_var(
        case dest_vimvar:
            return generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL);
        case dest_script:
+       case dest_script_v9:
            {
                int         scriptvar_idx = lhs->lhs_scriptvar_idx;
                int         scriptvar_sid = lhs->lhs_scriptvar_sid;
@@ -2401,10 +2402,14 @@ generate_store_var(
                {
                    isntype_T   isn_type = ISN_STORES;
 
+                   // If "sn_import_autoload", generate ISN_STOREEXPORT (not
+                   // ISN_STORES) if destination is in a vim9script or if
+                   // there is no "sn_autoload_prefix".
                    if (SCRIPT_ID_VALID(scriptvar_sid)
                             && SCRIPT_ITEM(scriptvar_sid)->sn_import_autoload
-                            && SCRIPT_ITEM(scriptvar_sid)->sn_autoload_prefix
-                                                                      == NULL)
+                            && ((SCRIPT_ITEM(scriptvar_sid)
+                                                 ->sn_autoload_prefix == NULL)
+                               || lhs->lhs_dest == dest_script_v9))
                    {
                        // "import autoload './dir/script.vim'" - load script
                        // first

-- 
-- 
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/E1rzh95-00CdBq-Cf%40256bit.org.

Raspunde prin e-mail lui