changeset 20281:ab8c8fd0f868 v8.2.0696

patch 8.2.0696: Vim9: nested function does not work properly Commit: https://github.com/vim/vim/commit/0e65d3de0aeff00aa42ea899f1afd11f8b22b93e Author: Bram Moolenaar <Bram@vim.org> 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.
author Bram Moolenaar <Bram@vim.org>
date Tue, 05 May 2020 18:00:04 +0200
parents 50e2e957cd0d
children a461511dc68f
files src/testdir/test_vim9_func.vim src/version.c src/vim9compile.c src/vim9execute.c
diffstat 4 files changed, 30 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- 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
 
--- 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,
--- 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 *)"";
--- 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);