From 3f821d6de2586d921fb23e2facb4764ef9eb3294 Mon Sep 17 00:00:00 2001 From: Ernie Rael Date: Wed, 24 Apr 2024 20:07:50 +0200 Subject: 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 Signed-off-by: Christian Brabandt Signed-off-by: Yegappan Lakshmanan --- src/evalvars.c | 1 + src/testdir/test_vim9_disassemble.vim | 28 ++++++++++++++++++++ src/testdir/test_vim9_func.vim | 31 ++++++++++++++++++++++ src/testdir/test_vim9_import.vim | 50 +++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ src/vim9.h | 1 + src/vim9compile.c | 9 ++++--- src/vim9execute.c | 14 +++++++--- src/vim9instr.c | 9 +++++-- 9 files changed, 137 insertions(+), 8 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index b70a3cd394..6facbeb138 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 92a4ff2a6e..c74cce4482 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('\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 27585a9049..b008929611 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 cfab50d584..581925d24c 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 feed8385e5..658a410271 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 65de618207..54938fe20c 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 a091c57963..4cbc1cf058 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 5af3af68ba..3a3960a8d1 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 4df63fd09a..ad8beb1a30 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 -- cgit v1.2.3