# HG changeset patch # User Christian Brabandt # Date 1722457809 -7200 # Node ID a93a8afce1ef5703d55792597b30c6b2d074d638 # Parent ceae17f2822823c247bb58d893721a76629e81d7 patch 9.1.0646: Vim9: imported function may not be found Commit: https://github.com/vim/vim/commit/164096927b8691085206dae3975766639a9a16e2 Author: Ernie Rael 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 Signed-off-by: Christian Brabandt diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim --- 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 but got list', '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) + 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 diff --git a/src/userfunc.c b/src/userfunc.c --- 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; } /* diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 646, +/**/ 645, /**/ 644,