# HG changeset patch # User Bram Moolenaar # Date 1588694404 -7200 # Node ID ab8c8fd0f8682ae2a93126993f59c007eeb4ce87 # Parent 50e2e957cd0dc2e2efa861340ca9233aa58d12b4 patch 8.2.0696: Vim9: nested function does not work properly Commit: https://github.com/vim/vim/commit/0e65d3de0aeff00aa42ea899f1afd11f8b22b93e Author: Bram Moolenaar Date: Tue May 5 17:53:16 2020 +0200 patch 8.2.0696: Vim9: nested function does not work properly Problem: Vim9: nested function does not work properly Solution: Create a function reference. Check argument count. 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 @@ -93,6 +93,9 @@ def Test_nested_function() enddef assert_equal('nested function', Nested('function')) + CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:') + CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:') + CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:') enddef diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 696, +/**/ 695, /**/ 694, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -101,7 +101,6 @@ typedef struct { int lv_from_outer; // when TRUE using ctx_outer scope int lv_const; // when TRUE cannot be assigned to int lv_arg; // when TRUE this is an argument - int lv_func_idx; // for nested function } lvar_T; /* @@ -1504,7 +1503,24 @@ generate_PCALL( if (type->tt_type == VAR_ANY) ret_type = &t_any; else if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL) + { + if (type->tt_argcount != -1) + { + int varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0; + + if (argcount < type->tt_min_argcount - varargs) + { + semsg(_(e_toofewarg), "[reference]"); + return FAIL; + } + if (!varargs && argcount > type->tt_argcount) + { + semsg(_(e_toomanyarg), "[reference]"); + return FAIL; + } + } ret_type = type->tt_member; + } else { semsg(_("E1085: Not a callable type: %s"), name); @@ -2616,7 +2632,6 @@ compile_call(char_u **arg, size_t varlen int error = FCERR_NONE; ufunc_T *ufunc; int res = FAIL; - lvar_T *lvar; if (varlen >= sizeof(namebuf)) { @@ -2643,16 +2658,6 @@ compile_call(char_u **arg, size_t varlen goto theend; } - // Check if the name is a nested function. - lvar = lookup_local(namebuf, varlen, cctx); - if (lvar != NULL && lvar->lv_func_idx > 0) - { - dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) - + lvar->lv_func_idx; - res = generate_CALL(cctx, dfunc->df_ufunc, argcount); - goto theend; - } - // If we can find the function by name generate the right call. ufunc = find_func(name, FALSE, cctx); if (ufunc != NULL) @@ -2807,7 +2812,6 @@ compile_list(char_u **arg, cctx_T *cctx) static int compile_lambda(char_u **arg, cctx_T *cctx) { - garray_T *instr = &cctx->ctx_instr; typval_T rettv; ufunc_T *ufunc; @@ -2825,12 +2829,7 @@ compile_lambda(char_u **arg, cctx_T *cct compile_def_function(ufunc, TRUE, cctx); if (ufunc->uf_dfunc_idx >= 0) - { - if (ga_grow(instr, 1) == FAIL) - return FAIL; - generate_FUNCREF(cctx, ufunc->uf_dfunc_idx); - return OK; - } + return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx); return FAIL; } @@ -4103,16 +4102,16 @@ compile_nested_function(exarg_T *eap, cc eap->forceit = FALSE; ufunc = def_function(eap, name, cctx); - if (ufunc == NULL) + if (ufunc == NULL || ufunc->uf_dfunc_idx < 0) return NULL; - // Define a local variable for the function, but change the index to -1 to - // mark it as a function name. + // Define a local variable for the function reference. lvar = reserve_local(cctx, name_start, name_end - name_start, - TRUE, &t_func_unknown); - lvar->lv_idx = 0; - ++cctx->ctx_locals_count; // doesn't count as a local variable - lvar->lv_func_idx = ufunc->uf_dfunc_idx; + TRUE, ufunc->uf_func_type); + + if (generate_FUNCREF(cctx, ufunc->uf_dfunc_idx) == FAIL + || generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL) == FAIL) + return NULL; // TODO: warning for trailing? return (char_u *)""; diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -206,11 +206,6 @@ call_dfunc(int cdf_idx, int argcount_arg + dfunc->df_varcount + dfunc->df_closure_count) == FAIL) return FAIL; - // Closure may need the function context where it was defined. - // TODO: assuming current context. - ectx->ec_outer_stack = &ectx->ec_stack; - ectx->ec_outer_frame = ectx->ec_frame_idx; - // Move the vararg-list to below the missing optional arguments. if (vararg_count > 0 && arg_to_add > 0) *STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1);