Patch 8.2.4202
Problem: Vim9: cannot export function that exists globally.
Solution: When checking if a function already exists only check for
script-local functions. (closes #9615)
Files: src/userfunc.c, src/proto/
userfunc.pro, src/vim.h,
src/vim9compile.c, src/vim9instr.c,
src/testdir/test_vim9_import.vim
*** ../vim-8.2.4201/src/userfunc.c 2022-01-21 20:37:02.283408897 +0000
--- src/userfunc.c 2022-01-24 13:51:51.729903391 +0000
***************
*** 1941,1956 ****
/*
* Find a function by name, return pointer to it in ufuncs.
! * When "is_global" is true don't find script-local or imported functions.
* Return NULL for unknown function.
*/
ufunc_T *
! find_func_even_dead(char_u *name, int is_global)
{
hashitem_T *hi;
ufunc_T *func;
! if (!is_global)
{
int find_script_local = in_vim9script() && eval_isnamec1(*name)
&& (name[1] != ':' || *name == 's');
--- 1941,1958 ----
/*
* 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.
! * When "flags" has "FFED_NO_GLOBAL" don't find global functions.
* Return NULL for unknown function.
*/
ufunc_T *
! find_func_even_dead(char_u *name, int flags)
{
hashitem_T *hi;
ufunc_T *func;
! if ((flags & FFED_IS_GLOBAL) == 0)
{
int find_script_local = in_vim9script() && eval_isnamec1(*name)
&& (name[1] != ':' || *name == 's');
***************
*** 1965,1974 ****
}
}
! hi = hash_find(&func_hashtab,
STRNCMP(name, "g:", 2) == 0 ? name + 2 : name);
! if (!HASHITEM_EMPTY(hi))
! return HI2UF(hi);
// Find autoload function if this is an autoload script.
return find_func_with_prefix(name[0] == 's' && name[1] == ':'
--- 1967,1979 ----
}
}
! if ((flags & FFED_NO_GLOBAL) == 0)
! {
! hi = hash_find(&func_hashtab,
STRNCMP(name, "g:", 2) == 0 ? name + 2 : name);
! if (!HASHITEM_EMPTY(hi))
! return HI2UF(hi);
! }
// Find autoload function if this is an autoload script.
return find_func_with_prefix(name[0] == 's' && name[1] == ':'
***************
*** 1983,1989 ****
ufunc_T *
find_func(char_u *name, int is_global)
{
! ufunc_T *fp = find_func_even_dead(name, is_global);
if (fp != NULL && (fp->uf_flags & FC_DEAD) == 0)
return fp;
--- 1988,1994 ----
ufunc_T *
find_func(char_u *name, int is_global)
{
! ufunc_T *fp = find_func_even_dead(name, is_global ? FFED_IS_GLOBAL : 0);
if (fp != NULL && (fp->uf_flags & FC_DEAD) == 0)
return fp;
***************
*** 2354,2360 ****
int
copy_func(char_u *lambda, char_u *global, ectx_T *ectx)
{
! ufunc_T *ufunc = find_func_even_dead(lambda, TRUE);
ufunc_T *fp = NULL;
if (ufunc == NULL)
--- 2359,2365 ----
int
copy_func(char_u *lambda, char_u *global, ectx_T *ectx)
{
! ufunc_T *ufunc = find_func_even_dead(lambda, FFED_IS_GLOBAL);
ufunc_T *fp = NULL;
if (ufunc == NULL)
***************
*** 4464,4469 ****
--- 4469,4475 ----
hashtab_T *ht;
char_u *find_name = name;
int var_conflict = FALSE;
+ int ffed_flags = is_global ? FFED_IS_GLOBAL : 0;
v = find_var(name, &ht, TRUE);
if (v != NULL && (in_vim9script() || v->di_tv.v_type == VAR_FUNC))
***************
*** 4481,4486 ****
--- 4487,4495 ----
v = find_var(find_name, &ht, TRUE);
if (v != NULL)
var_conflict = TRUE;
+ // Only check if the function already exists in the script,
+ // global functions can be shadowed.
+ ffed_flags |= FFED_NO_GLOBAL;
}
else
{
***************
*** 4508,4514 ****
goto erret;
}
! fp = find_func_even_dead(find_name, is_global);
if (vim9script)
{
char_u *uname = untrans_function_name(name);
--- 4517,4523 ----
goto erret;
}
! fp = find_func_even_dead(find_name, ffed_flags);
if (vim9script)
{
char_u *uname = untrans_function_name(name);
*** ../vim-8.2.4201/src/proto/
userfunc.pro 2022-01-19 17:21:24.846755312 +0000
--- src/proto/
userfunc.pro 2022-01-24 13:42:07.086554796 +0000
***************
*** 8,14 ****
void emsg_funcname(char *ermsg, char_u *name);
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, funcexe_T *funcexe);
char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error);
! ufunc_T *find_func_even_dead(char_u *name, int is_global);
ufunc_T *find_func(char_u *name, int is_global);
int func_is_global(ufunc_T *ufunc);
int func_name_refcount(char_u *name);
--- 8,14 ----
void emsg_funcname(char *ermsg, char_u *name);
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, funcexe_T *funcexe);
char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error);
! ufunc_T *find_func_even_dead(char_u *name, int flags);
ufunc_T *find_func(char_u *name, int is_global);
int func_is_global(ufunc_T *ufunc);
int func_name_refcount(char_u *name);
*** ../vim-8.2.4201/src/vim.h 2022-01-24 11:23:59.859900461 +0000
--- src/vim.h 2022-01-24 13:35:28.027983378 +0000
***************
*** 2798,2801 ****
--- 2798,2805 ----
#define VSE_SHELL 1 // escape for a shell command
#define VSE_BUFFER 2 // escape for a ":buffer" command
+ // Flags used by find_func_even_dead()
+ #define FFED_IS_GLOBAL 1 // "g:" was used
+ #define FFED_NO_GLOBAL 2 // only check for script-local functions
+
#endif // VIM__H
*** ../vim-8.2.4201/src/vim9compile.c 2022-01-22 11:27:24.694028145 +0000
--- src/vim9compile.c 2022-01-24 13:41:13.775782559 +0000
***************
*** 332,338 ****
&& (lookup_local(p, len, NULL, cctx) == OK
|| arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
|| find_imported(p, len, FALSE, cctx) != NULL
! || (ufunc = find_func_even_dead(p, FALSE)) != NULL)
{
// A local or script-local function can shadow a global function.
if (ufunc == NULL || ((ufunc->uf_flags & FC_DEAD) == 0
--- 332,338 ----
&& (lookup_local(p, len, NULL, cctx) == OK
|| arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
|| find_imported(p, len, FALSE, cctx) != NULL
! || (ufunc = find_func_even_dead(p, 0)) != NULL)
{
// A local or script-local function can shadow a global function.
if (ufunc == NULL || ((ufunc->uf_flags & FC_DEAD) == 0
*** ../vim-8.2.4201/src/vim9instr.c 2022-01-15 21:44:39.832970792 +0000
--- src/vim9instr.c 2022-01-24 13:41:42.891109832 +0000
***************
*** 2050,2056 ****
case ISN_NEWFUNC:
{
char_u *lambda = isn->isn_arg.newfunc.nf_lambda;
! ufunc_T *ufunc = find_func_even_dead(lambda, TRUE);
if (ufunc != NULL)
{
--- 2050,2056 ----
case ISN_NEWFUNC:
{
char_u *lambda = isn->isn_arg.newfunc.nf_lambda;
! ufunc_T *ufunc = find_func_even_dead(lambda, FFED_IS_GLOBAL);
if (ufunc != NULL)
{
*** ../vim-8.2.4201/src/testdir/test_vim9_import.vim 2022-01-24 11:40:33.944693856 +0000
--- src/testdir/test_vim9_import.vim 2022-01-24 13:51:29.794360081 +0000
***************
*** 965,970 ****
--- 965,1001 ----
set nospell spellsuggest& verbose=0
enddef
+ def Test_export_shadows_global_function()
+ mkdir('Xdir/autoload', 'p')
+ var save_rtp = &rtp
+ exe 'set rtp^=' .. getcwd() .. '/Xdir'
+
+ var lines =<< trim END
+ vim9script
+ export def Shadow(): string
+ return 'Shadow()'
+ enddef
+ END
+ writefile(lines, 'Xdir/autoload/shadow.vim')
+
+ lines =<< trim END
+ vim9script
+
+ def g:Shadow(): string
+ return 'global'
+ enddef
+
+ import autoload 'shadow.vim'
+ assert_equal('Shadow()', shadow.Shadow())
+ END
+ CheckScriptSuccess(lines)
+
+ delfunc g:Shadow
+ bwipe!
+ delete('Xdir', 'rf')
+ &rtp = save_rtp
+ enddef
+
def Test_export_fails()
CheckScriptFailure(['export var some = 123'], 'E1042:')
CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')
*** ../vim-8.2.4201/src/version.c 2022-01-24 12:20:41.597511550 +0000
--- src/version.c 2022-01-24 13:46:17.976977499 +0000
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 4202,
/**/
--
A special law prohibits unmarried women from parachuting on Sunday or she
shall risk arrest, fine, and/or jailing.
[real standing law in Florida, United States of America]
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///