]> granicus.if.org Git - vim/commitdiff
patch 8.2.0696: Vim9: nested function does not work properly v8.2.0696
authorBram Moolenaar <Bram@vim.org>
Tue, 5 May 2020 15:53:16 +0000 (17:53 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 5 May 2020 15:53:16 +0000 (17:53 +0200)
Problem:    Vim9: nested function does not work properly
Solution:   Create a function reference.  Check argument count.

src/testdir/test_vim9_func.vim
src/version.c
src/vim9compile.c
src/vim9execute.c

index 712733149892ef8503aa405f9c94b121789177d0..840c22048753c8b73a50e4cfb835cdc76b9f89b9 100644 (file)
@@ -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
 
index da1a20f41ffa3ef91df3c4920052d713fc34ba3c..38755db73ff2318df446c6ef48bcad39a4fcb9f6 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    696,
 /**/
     695,
 /**/
index 7e700d5637a444eb239740d42d6ffb067d74338d..de2fb96b516abfb783f1d25376fd6725401a8c9f 100644 (file)
@@ -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, cctx_T *cctx, int argcount_init)
     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, cctx_T *cctx, int argcount_init)
        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 *cctx)
     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, cctx_T *cctx)
     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 *)"";
index 665c6afd29ec9890ddd4ec657c13d59d7697c6cc..c74240ff2037f217b3b12da791959dcbea602b23 100644 (file)
@@ -206,11 +206,6 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx)
                       + 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);