# HG changeset patch # User Bram Moolenaar # Date 1638137703 -3600 # Node ID 3841da4eac238fd703f1ec8181d2516f0cbb0979 # Parent 931db05edfa7b339e85e7429fdc03e38d91a54f9 patch 8.2.3692: Vim9: cannot use :func inside a :def function Commit: https://github.com/vim/vim/commit/38453528c3372293d70c8e85471a6188749ff331 Author: Bram Moolenaar Date: Sun Nov 28 22:00:12 2021 +0000 patch 8.2.3692: Vim9: cannot use :func inside a :def function Problem: Vim9: cannot use :func inside a :def function. Solution: Make it work. diff --git a/src/errors.h b/src/errors.h --- a/src/errors.h +++ b/src/errors.h @@ -355,8 +355,7 @@ EXTERN char e_cannot_delete_vim9_script_ 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")); +// E1086 unused EXTERN char e_cannot_use_index_when_declaring_variable[] INIT(= N_("E1087: Cannot use an index when declaring a variable")); // E1088 unused diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1699,6 +1699,7 @@ typedef struct #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 diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -586,15 +586,19 @@ def Test_func_with_comments() enddef def Test_nested_function() - def Nested(arg: string): string + def NestedDef(arg: string): string return 'nested ' .. arg enddef - Nested('function')->assert_equal('nested function') + 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(['func Nested()', 'endfunc'], 'E1086:') CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:') CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:') @@ -705,6 +709,26 @@ def Test_nested_global_function() lines =<< trim END vim9script def Outer() + func g:Inner() + return 'inner' + endfunc + 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() def g:Inner(): string return 'inner' enddef diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -523,7 +523,7 @@ register_cfunc(cfunc_T cb, cfunc_free_T fp->uf_def_status = UF_NOT_COMPILED; fp->uf_refcount = 1; fp->uf_varargs = TRUE; - fp->uf_flags = FC_CFUNC; + fp->uf_flags = FC_CFUNC | FC_LAMBDA; fp->uf_calls = 0; fp->uf_script_ctx = current_sctx; fp->uf_cb = cb; @@ -1205,6 +1205,7 @@ lambda_function_body( 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,7 +1400,7 @@ get_lambda_tv( if (evaluate) { int len; - int flags = 0; + int flags = FC_LAMBDA; char_u *p; char_u *line_end; char_u *name = get_lambda_name(); @@ -2506,8 +2507,7 @@ call_user_func( return; } - if (STRNCMP(fp->uf_name, "", 8) == 0) - islambda = TRUE; + islambda = fp->uf_flags & FC_LAMBDA; /* * Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -758,6 +758,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3692, +/**/ 3691, /**/ 3690, diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -322,7 +322,8 @@ typedef struct { // arguments to ISN_FUNCREF typedef struct { - int fr_func; // function index + 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 diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1675,7 +1675,10 @@ generate_FUNCREF(cctx_T *cctx, ufunc_T * 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; + 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,6 +5838,7 @@ compile_nested_function(exarg_T *eap, cc fill_exarg_from_cctx(eap, cctx); eap->forceit = FALSE; + // We use the special 99 name, but it's not really a lambda. lambda_name = vim_strsave(get_lambda_name()); if (lambda_name == NULL) return NULL; @@ -9976,16 +9980,11 @@ compile_def_function( switch (ea.cmdidx) { case CMD_def: + case CMD_function: 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); @@ -10442,12 +10441,23 @@ delete_instr(isn_T *isn) 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); + 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; diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -3168,8 +3168,8 @@ exec_instructions(ectx_T *ectx) 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; + ufunc_T *ufunc; + funcref_T *funcref = &iptr->isn_arg.funcref; if (pt == NULL) goto theend; @@ -3178,8 +3178,18 @@ exec_instructions(ectx_T *ectx) vim_free(pt); goto theend; } - if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc, - ectx) == FAIL) + 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,10 +5464,17 @@ list_instructions(char *pfx, isn_T *inst 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); + 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;