Mercurial > vim
changeset 35868:a93a8afce1ef v9.1.0646
patch 9.1.0646: Vim9: imported function may not be found
Commit: https://github.com/vim/vim/commit/164096927b8691085206dae3975766639a9a16e2
Author: Ernie Rael <errael@raelity.com>
Date: Wed Jul 31 22:18:11 2024 +0200
patch 9.1.0646: Vim9: imported function may not be found
Problem: Vim9: imported function may not be found
Solution: Try to find the function by name (Ernie Rael)
fixes: #15381
closes: #15382
Signed-off-by: Ernie Rael <errael@raelity.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Wed, 31 Jul 2024 22:30:09 +0200 |
parents | ceae17f28228 |
children | 407b352f3b19 |
files | src/testdir/test_vim9_builtin.vim src/userfunc.c src/version.c |
diffstat | 3 files changed, 102 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -497,6 +497,56 @@ def Test_call_call() v9.CheckSourceDefAndScriptFailure(['call("reverse", [2], [1])'], ['E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', 'E1206: Dictionary required for argument 3']) enddef +def Test_call_imports() + # Use call with an imported function + var lines =<< trim END + vim9script + + export const foo = 'foo' + + export def Imported() + enddef + + var count: number + export def ImportedListArg(l: list<number>) + count += 1 + l[0] += count + enddef + END + writefile(lines, 'Test_call_imports_importme', 'D') + lines =<< trim END + vim9script + import './Test_call_imports_importme' as i_imp + + var l = [12] + call('i_imp.ImportedListArg', [l]) + assert_equal(13, l[0]) + const ImportedListArg = i_imp.ImportedListArg + call('ImportedListArg', [l]) + assert_equal(15, l[0]) + const Imported = i_imp.Imported + call("Imported", []) + + assert_equal('foo', i_imp.foo) + const foo = i_imp.foo + assert_equal('foo', foo) + END + v9.CheckSourceScriptSuccess(lines) + + # A few error cases + lines =<< trim END + vim9script + import './Test_call_imports_importme' as i_imp + const Imported = i_imp.Imported + const foo = i_imp.foo + + assert_fails('call("i_imp.foo", [])', 'E117:') # foo is not a function + assert_fails('call("foo", [])', 'E117:') # foo is not a function + assert_fails('call("i_xxx.foo", [])', 'E117:') # i_xxx not imported file + END + v9.CheckSourceScriptSuccess(lines) +enddef + def Test_ch_canread() if !has('channel') CheckFeature channel
--- a/src/userfunc.c +++ b/src/userfunc.c @@ -2212,6 +2212,48 @@ find_func_with_prefix(char_u *name, int } /* + * Find a function by name, return pointer to it. + * The name may be a local script variable, VAR_FUNC. or it may be a fully + * qualified import name such as 'i_imp.FuncName'. + * + * When VAR_FUNC, the import might either direct or autoload. + * When 'i_imp.FuncName' it is direct, autoload is rewritten as i_imp#FuncName + * in f_call and subsequently found. + */ + static ufunc_T * +find_func_imported(char_u *name, int flags) +{ + ufunc_T *func = NULL; + char_u *dot = name; // Find a dot, '.', in the name + + // Either run into '.' or the end of the string + while (eval_isnamec(*dot)) + ++dot; + + if (*dot == '.') + { + imported_T *import = find_imported(name, dot - name, FALSE); + if (import != NULL) + func = find_func_with_sid(dot + 1, import->imp_sid); + } + else if (*dot == NUL) // looking at the entire string + { + hashtab_T *ht = get_script_local_ht(); + if (ht != NULL) + { + hashitem_T *hi = hash_find(ht, name); + if (!HASHITEM_EMPTY(hi)) + { + dictitem_T *di = HI2DI(hi); + if (di->di_tv.v_type == VAR_FUNC) + func = find_func_even_dead(di->di_tv.vval.v_string, flags); + } + } + } + return func; +} + +/* * Find a function by name, return pointer to it in ufuncs. * When "flags" has FFED_IS_GLOBAL don't find script-local or imported * functions. @@ -2260,8 +2302,15 @@ find_func_even_dead(char_u *name, int fl } // Find autoload function if this is an autoload script. - return find_func_with_prefix(name[0] == 's' && name[1] == ':' + func = find_func_with_prefix(name[0] == 's' && name[1] == ':' ? name + 2 : name, current_sctx.sc_sid); + if (func != NULL) + return func; + + // Find a script-local "VAR_FUNC" or i_"imp.Func", so vim9script). + if (in_vim9script()) + func = find_func_imported(name, flags); + return func; } /*