# HG changeset patch # User Bram Moolenaar # Date 1642527902 -3600 # Node ID facb54d20a504b13b2134b0de9facf1f101bf1f3 # Parent da41f5bae90e5f311eaa225880cdd2c2e4dc487f patch 8.2.4137: Vim9: calling import with and without method is inconsistent Commit: https://github.com/vim/vim/commit/d02dce2bb572f0e6b4570442e9cdbed14ef41820 Author: Bram Moolenaar Date: Tue Jan 18 17:43:04 2022 +0000 patch 8.2.4137: Vim9: calling import with and without method is inconsistent Problem: Vim9: calling import with and without method is inconsistent. Solution: Set a flag that a parenthsis follows to compile_load_scriptvar(). Add some more tests. Improve error message. diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim --- a/src/testdir/test_vim9_import.vim +++ b/src/testdir/test_vim9_import.vim @@ -1256,6 +1256,136 @@ def Test_vim9script_autoload() &rtp = save_rtp enddef +def Test_import_autoload_not_exported() + mkdir('Xdir/autoload', 'p') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xdir' + + # error when using an item that is not exported from an autoload script + var exportLines =<< trim END + vim9script + var notExported = 123 + def NotExport() + echo 'nop' + enddef + END + writefile(exportLines, 'Xdir/autoload/notExport1.vim') + + var lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo notExport1.notFound + END + CheckScriptFailure(lines, 'E1048: Item not found in script: notFound') + + lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo notExport1.notExported + END + CheckScriptFailure(lines, 'E1049: Item not exported in script: notExported') + + lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo notExport1.NotFunc() + END + CheckScriptFailure(lines, 'E1048: Item not found in script: NotFunc') + + lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo notExport1.NotExport() + END + CheckScriptFailure(lines, 'E1049: Item not exported in script: NotExport') + + lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo 'text'->notExport1.NotFunc() + END + CheckScriptFailure(lines, 'E1048: Item not found in script: NotFunc') + + lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo 'text'->notExport1.NotExport() + END + CheckScriptFailure(lines, 'E1049: Item not exported in script: NotExport') + + # using a :def function we use a different autoload script every time so that + # the function is compiled without the script loaded + writefile(exportLines, 'Xdir/autoload/notExport2.vim') + lines =<< trim END + vim9script + import autoload 'notExport2.vim' + def Testit() + echo notExport2.notFound + enddef + Testit() + END + CheckScriptFailure(lines, 'E1048: Item not found in script: notExport2#notFound') + + writefile(exportLines, 'Xdir/autoload/notExport3.vim') + lines =<< trim END + vim9script + import autoload 'notExport3.vim' + def Testit() + echo notExport3.notExported + enddef + Testit() + END + # don't get E1049 because it is too complicated to figure out + CheckScriptFailure(lines, 'E1048: Item not found in script: notExport3#notExported') + + writefile(exportLines, 'Xdir/autoload/notExport4.vim') + lines =<< trim END + vim9script + import autoload 'notExport4.vim' + def Testit() + echo notExport4.NotFunc() + enddef + Testit() + END + CheckScriptFailure(lines, 'E117: Unknown function: notExport4#NotFunc') + + writefile(exportLines, 'Xdir/autoload/notExport5.vim') + lines =<< trim END + vim9script + import autoload 'notExport5.vim' + def Testit() + echo notExport5.NotExport() + enddef + Testit() + END + CheckScriptFailure(lines, 'E117: Unknown function: notExport5#NotExport') + + writefile(exportLines, 'Xdir/autoload/notExport6.vim') + lines =<< trim END + vim9script + import autoload 'notExport6.vim' + def Testit() + echo 'text'->notExport6.NotFunc() + enddef + Testit() + END + CheckScriptFailure(lines, 'E117: Unknown function: notExport6#NotFunc') + + writefile(exportLines, 'Xdir/autoload/notExport7.vim') + lines =<< trim END + vim9script + import autoload 'notExport7.vim' + def Testit() + echo 'text'->notExport7.NotExport() + enddef + Testit() + END + CheckScriptFailure(lines, 'E117: Unknown function: notExport7#NotExport') + + delete('Xdir', 'rf') + &rtp = save_rtp +enddef + def Test_vim9script_autoload_call() mkdir('Xdir/autoload', 'p') var save_rtp = &rtp diff --git a/src/version.c b/src/version.c --- 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 */ /**/ + 4137, +/**/ 4136, /**/ 4135, diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2240,33 +2240,19 @@ exec_instructions(ectx_T *ectx) iptr->isn_arg.string, TRUE); if (did_emsg) goto on_error; - if (di == NULL) - { - isn_T *next = &ectx->ec_instr[ectx->ec_iidx]; - - // When compiling "script.Func()" when "script" is - // an autoload import then this results in - // "LOADG script#Func" because we don't know if it - // is a funcref variable or a function name. In - // that case a PCALL follows, push the function - // name instead. - if (next->isn_type == ISN_PCALL) - { - tv = STACK_TV_BOT(0); - tv->v_type = VAR_FUNC; - tv->v_lock = 0; - tv->vval.v_string = - vim_strsave(iptr->isn_arg.string); - ++ectx->ec_stack.ga_len; - break; - } - } } if (di == NULL) { SOURCING_LNUM = iptr->isn_lnum; - semsg(_(e_undefined_variable_char_str), + if (vim_strchr(iptr->isn_arg.string, + AUTOLOAD_CHAR) != NULL) + // no check if the item exists in the script but + // isn't exported, it is too complicated + semsg(_(e_item_not_found_in_script_str), + iptr->isn_arg.string); + else + semsg(_(e_undefined_variable_char_str), namespace, iptr->isn_arg.string); goto on_error; } diff --git a/src/vim9expr.c b/src/vim9expr.c --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -21,6 +21,9 @@ # include "vim9.h" #endif +// flag passed from compile_subscript() to compile_load_scriptvar() +static int paren_follows_after_expr = 0; + /* * Generate code for any ppconst entries. */ @@ -277,7 +280,6 @@ compile_load_scriptvar( int done = FALSE; int res = OK; - // TODO: if this is an autoload import do something else. // Need to lookup the member. if (*p != '.') { @@ -306,7 +308,7 @@ compile_load_scriptvar( // autoload script must be loaded later, access by the autoload // name. - if (cc == '(') + if (cc == '(' || paren_follows_after_expr) res = generate_PUSHFUNC(cctx, auto_name, &t_func_any); else res = generate_LOAD(cctx, ISN_LOADG, 0, auto_name, &t_any); @@ -1736,12 +1738,19 @@ compile_subscript( int save_len = cctx->ctx_ufunc->uf_lines.ga_len; *paren = NUL; + + // instead of using LOADG for "import.Func" use PUSHFUNC + ++paren_follows_after_expr; + // do not look in the next line cctx->ctx_ufunc->uf_lines.ga_len = 1; + fail = compile_expr8(arg, cctx, ppconst) == FAIL || *skipwhite(*arg) != NUL; *paren = '('; + --paren_follows_after_expr; cctx->ctx_ufunc->uf_lines.ga_len = save_len; + if (fail) { semsg(_(e_invalid_expression_str), pstart); diff --git a/src/vim9script.c b/src/vim9script.c --- a/src/vim9script.c +++ b/src/vim9script.c @@ -707,22 +707,36 @@ find_exported( sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name); } *ufunc = find_func(funcname, FALSE); - if (funcname != buffer) - vim_free(funcname); if (*ufunc == NULL) { if (verbose) - semsg(_(e_item_not_found_in_script_str), name); - return -1; + { + ufunc_T *alt_ufunc = NULL; + + if (script->sn_autoload_prefix != NULL) + { + // try find the function by the script-local name + funcname[0] = K_SPECIAL; + funcname[1] = KS_EXTRA; + funcname[2] = (int)KE_SNR; + sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name); + alt_ufunc = find_func(funcname, FALSE); + } + if (alt_ufunc != NULL) + semsg(_(e_item_not_exported_in_script_str), name); + else + semsg(_(e_item_not_found_in_script_str), name); + } } else if (((*ufunc)->uf_flags & FC_EXPORT) == 0) { if (verbose) semsg(_(e_item_not_exported_in_script_str), name); *ufunc = NULL; - return -1; } + if (funcname != buffer) + vim_free(funcname); } return idx;