Patch 8.2.3692
Problem: Vim9: cannot use :func inside a :def function.
Solution: Make it work.
Files: src/vim9compile.c, src/vim9.h, src/vim9execute.c, src/errors.h,
src/structs.h, src/userfunc.c, src/testdir/test_vim9_func.vim
*** ../vim-8.2.3691/src/vim9compile.c 2021-11-23 12:35:54.350064548 +0000
--- src/vim9compile.c 2021-11-28 21:54:52.784775660 +0000
***************
*** 1675,1681 ****
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
return FAIL;
! isn->isn_arg.funcref.fr_func = ufunc->uf_dfunc_idx;
cctx->ctx_has_closure = 1;
// If the referenced function is a closure, it may use items further up in
--- 1675,1684 ----
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
return FAIL;
! if (ufunc->uf_def_status == UF_NOT_COMPILED)
! isn->isn_arg.funcref.fr_func_name = vim_strsave(ufunc->uf_name);
! else
! isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx;
cctx->ctx_has_closure = 1;
// If the referenced function is a closure, it may use items further up in
***************
*** 5835,5840 ****
--- 5838,5844 ----
fill_exarg_from_cctx(eap, cctx);
eap->forceit = FALSE;
+ // We use the special <Lamba>99 name, but it's not really a lambda.
lambda_name = vim_strsave(get_lambda_name());
if (lambda_name == NULL)
return NULL;
***************
*** 9976,9991 ****
switch (ea.cmdidx)
{
case CMD_def:
ea.arg = p;
line = compile_nested_function(&ea, &cctx);
break;
- case CMD_function:
- // TODO: should we allow this, e.g. to declare a global
- // function?
- emsg(_(e_cannot_use_function_inside_def));
- goto erret;
-
case CMD_return:
line = compile_return(p, check_return_type,
local_cmdmod.cmod_flags & CMOD_LEGACY, &cctx);
--- 9980,9990 ----
switch (ea.cmdidx)
{
case CMD_def:
+ case CMD_function:
ea.arg = p;
line = compile_nested_function(&ea, &cctx);
break;
case CMD_return:
line = compile_return(p, check_return_type,
local_cmdmod.cmod_flags & CMOD_LEGACY, &cctx);
***************
*** 10442,10453 ****
case ISN_FUNCREF:
{
! dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
! + isn->isn_arg.funcref.fr_func;
! ufunc_T *ufunc = dfunc->df_ufunc;
! if (ufunc != NULL && func_name_refcount(ufunc->uf_name))
! func_ptr_unref(ufunc);
}
break;
--- 10441,10463 ----
case ISN_FUNCREF:
{
! if (isn->isn_arg.funcref.fr_func_name == NULL)
! {
! dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
! + isn->isn_arg.funcref.fr_dfunc_idx;
! ufunc_T *ufunc = dfunc->df_ufunc;
! if (ufunc != NULL && func_name_refcount(ufunc->uf_name))
! func_ptr_unref(ufunc);
! }
! else
! {
! char_u *name = isn->isn_arg.funcref.fr_func_name;
!
! if (name != NULL)
! func_unref(name);
! vim_free(isn->isn_arg.funcref.fr_func_name);
! }
}
break;
*** ../vim-8.2.3691/src/vim9.h 2021-09-16 15:15:00.204224417 +0100
--- src/vim9.h 2021-11-28 21:01:31.606756591 +0000
***************
*** 322,328 ****
// arguments to ISN_FUNCREF
typedef struct {
! int fr_func; // function index
} funcref_T;
// arguments to ISN_NEWFUNC
--- 322,329 ----
// arguments to ISN_FUNCREF
typedef struct {
! int fr_dfunc_idx; // function index for :def function
! char_u *fr_func_name; // function name for legacy function
} funcref_T;
// arguments to ISN_NEWFUNC
*** ../vim-8.2.3691/src/vim9execute.c 2021-11-23 22:16:30.522773542 +0000
--- src/vim9execute.c 2021-11-28 21:16:49.706158909 +0000
***************
*** 3168,3175 ****
case ISN_FUNCREF:
{
partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
! dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data)
! + iptr->isn_arg.funcref.fr_func;
if (pt == NULL)
goto theend;
--- 3168,3175 ----
case ISN_FUNCREF:
{
partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
! ufunc_T *ufunc;
! funcref_T *funcref = &iptr->isn_arg.funcref;
if (pt == NULL)
goto theend;
***************
*** 3178,3185 ****
vim_free(pt);
goto theend;
}
! if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc,
! ectx) == FAIL)
goto theend;
tv = STACK_TV_BOT(0);
++ectx->ec_stack.ga_len;
--- 3178,3195 ----
vim_free(pt);
goto theend;
}
! if (funcref->fr_func_name == NULL)
! {
! dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data)
! + funcref->fr_dfunc_idx;
!
! ufunc = pt_dfunc->df_ufunc;
! }
! else
! {
! ufunc = find_func(funcref->fr_func_name, FALSE, NULL);
! }
! if (fill_partial_and_closure(pt, ufunc, ectx) == FAIL)
goto theend;
tv = STACK_TV_BOT(0);
++ectx->ec_stack.ga_len;
***************
*** 5454,5463 ****
case ISN_FUNCREF:
{
funcref_T *funcref = &iptr->isn_arg.funcref;
! dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
! + funcref->fr_func;
! smsg("%s%4d FUNCREF %s", pfx, current, df->df_ufunc->uf_name);
}
break;
--- 5464,5480 ----
case ISN_FUNCREF:
{
funcref_T *funcref = &iptr->isn_arg.funcref;
! char_u *name;
! if (funcref->fr_func_name == NULL)
! {
! dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
! + funcref->fr_dfunc_idx;
! name = df->df_ufunc->uf_name;
! }
! else
! name = funcref->fr_func_name;
! smsg("%s%4d FUNCREF %s", pfx, current, name);
}
break;
*** ../vim-8.2.3691/src/errors.h 2021-11-24 12:17:49.168449919 +0000
--- src/errors.h 2021-11-28 21:54:43.836795171 +0000
***************
*** 355,362 ****
INIT(= N_("E1084: Cannot delete Vim9 script function %s"));
EXTERN char e_not_callable_type_str[]
INIT(= N_("E1085: Not a callable type: %s"));
! EXTERN char e_cannot_use_function_inside_def[]
! INIT(= N_("E1086: Cannot use :function inside :def"));
EXTERN char e_cannot_use_index_when_declaring_variable[]
INIT(= N_("E1087: Cannot use an index when declaring a variable"));
// E1088 unused
--- 355,361 ----
INIT(= N_("E1084: Cannot delete Vim9 script function %s"));
EXTERN char e_not_callable_type_str[]
INIT(= N_("E1085: Not a callable type: %s"));
! // E1086 unused
EXTERN char e_cannot_use_index_when_declaring_variable[]
INIT(= N_("E1087: Cannot use an index when declaring a variable"));
// E1088 unused
*** ../vim-8.2.3691/src/structs.h 2021-11-24 16:32:50.720422469 +0000
--- src/structs.h 2021-11-28 21:44:06.182134663 +0000
***************
*** 1699,1704 ****
--- 1699,1705 ----
#define FC_VIM9 0x400 // defined in vim9 script file
#define FC_CFUNC 0x800 // defined as Lua C func
#define FC_COPY 0x1000 // copy of another function by copy_func()
+ #define FC_LAMBDA 0x2000 // one line "return {expr}"
#define MAX_FUNC_ARGS 20 // maximum number of function arguments
#define VAR_SHORT_LEN 20 // short variable name length
*** ../vim-8.2.3691/src/userfunc.c 2021-11-20 21:46:16.088614817 +0000
--- src/userfunc.c 2021-11-28 21:47:12.133757952 +0000
***************
*** 523,529 ****
fp->uf_def_status = UF_NOT_COMPILED;
fp->uf_refcount = 1;
fp->uf_varargs = TRUE;
! fp->uf_flags = FC_CFUNC;
fp->uf_calls = 0;
fp->uf_script_ctx = current_sctx;
fp->uf_cb = cb;
--- 523,529 ----
fp->uf_def_status = UF_NOT_COMPILED;
fp->uf_refcount = 1;
fp->uf_varargs = TRUE;
! fp->uf_flags = FC_CFUNC | FC_LAMBDA;
fp->uf_calls = 0;
fp->uf_script_ctx = current_sctx;
fp->uf_cb = cb;
***************
*** 1205,1210 ****
--- 1205,1211 ----
set_ufunc_name(ufunc, name);
if (hash_add(&func_hashtab, UF2HIKEY(ufunc)) == FAIL)
goto erret;
+ ufunc->uf_flags = FC_LAMBDA;
ufunc->uf_refcount = 1;
ufunc->uf_args = *newargs;
newargs->ga_data = NULL;
***************
*** 1399,1405 ****
if (evaluate)
{
int len;
! int flags = 0;
char_u *p;
char_u *line_end;
char_u *name = get_lambda_name();
--- 1400,1406 ----
if (evaluate)
{
int len;
! int flags = FC_LAMBDA;
char_u *p;
char_u *line_end;
char_u *name = get_lambda_name();
***************
*** 2506,2513 ****
return;
}
! if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
! islambda = TRUE;
/*
* Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables
--- 2507,2513 ----
return;
}
! islambda = fp->uf_flags & FC_LAMBDA;
/*
* Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables
*** ../vim-8.2.3691/src/testdir/test_vim9_func.vim 2021-11-20 21:46:16.088614817 +0000
--- src/testdir/test_vim9_func.vim 2021-11-28 21:52:25.885094272 +0000
***************
*** 586,600 ****
enddef
def Test_nested_function()
! def Nested(arg: string): string
return 'nested ' .. arg
enddef
! Nested('function')->assert_equal('nested function')
CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:')
CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:')
- CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:')
CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:')
CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
--- 586,604 ----
enddef
def Test_nested_function()
! def NestedDef(arg: string): string
return 'nested ' .. arg
enddef
! NestedDef(':def')->assert_equal('nested :def')
!
! func NestedFunc(arg)
! return 'nested ' .. a:arg
! endfunc
! NestedFunc(':func')->assert_equal('nested :func')
CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:')
CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:')
CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:')
CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:')
***************
*** 691,696 ****
--- 695,720 ----
enddef
defcompile
Outer()
+ g:Inner()->assert_equal('inner')
+ delfunc g:Inner
+ Outer()
+ g:Inner()->assert_equal('inner')
+ delfunc g:Inner
+ Outer()
+ g:Inner()->assert_equal('inner')
+ delfunc g:Inner
+ END
+ CheckScriptSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+ def Outer()
+ func g:Inner()
+ return 'inner'
+ endfunc
+ enddef
+ defcompile
+ Outer()
g:Inner()->assert_equal('inner')
delfunc g:Inner
Outer()
*** ../vim-8.2.3691/src/version.c 2021-11-28 21:33:32.307336723 +0000
--- src/version.c 2021-11-28 21:58:58.072236602 +0000
***************
*** 759,760 ****
--- 759,762 ----
{ /* Add new patch number below this line */
+ /**/
+ 3692,
/**/
--
Wi n0t trei a h0liday in Sweden thi yer?
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// 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 ///