]> granicus.if.org Git - vim/commitdiff
patch 8.2.0693: closure using argument not tested v8.2.0693
authorBram Moolenaar <Bram@vim.org>
Sun, 3 May 2020 20:30:49 +0000 (22:30 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 3 May 2020 20:30:49 +0000 (22:30 +0200)
Problem:    Closure using argument not tested.
Solution:   Add a test, make it work.

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

index fe47513ee9f55b5a966cf822a4b45c544d40b9d4..c06cc2304b362140cbd85e007f0be2e7e19618e3 100644 (file)
@@ -700,5 +700,26 @@ def Test_closure_two_indirect_refs()
   unlet g:Read
 enddef
 
+def MakeArgRefs(theArg: string)
+  let local = 'loc_val'
+  g:UseArg = {s -> theArg .. '/' .. local .. '/' .. s}
+enddef
+
+def MakeArgRefsVarargs(theArg: string, ...rest: list<string>)
+  let local = 'the_loc'
+  g:UseVararg = {s -> theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)}
+enddef
+
+def Test_closure_using_argument()
+  MakeArgRefs('arg_val')
+  assert_equal('arg_val/loc_val/call_val', g:UseArg('call_val'))
+
+  MakeArgRefsVarargs('arg_val', 'one', 'two')
+  assert_equal('arg_val/the_loc/call_val/one two', g:UseVararg('call_val'))
+
+  unlet g:UseArg
+  unlet g:UseVararg
+enddef
+
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
index f87cc8bda6fa1a3c6dfc8610d0a7019a8cb9172b..10f4efdf3f50d6183e8123a6d9941460c8a2520f 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    693,
 /**/
     692,
 /**/
index c18cdc0a8abf838ef1e4a4cfc4926cbed933dd31..300adfbec5adc593b87b858a4d1a78c887a471b5 100644 (file)
@@ -186,37 +186,74 @@ lookup_local(char_u *name, size_t len, cctx_T *cctx)
 }
 
 /*
- * Lookup an argument in the current function.
- * Returns the argument index or -1 if not found.
+ * Lookup an argument in the current function and an enclosing function.
+ * Returns the argument index in "idxp"
+ * Returns the argument type in "type"
+ * Sets "gen_load_outer" to TRUE if found in outer scope.
+ * Returns OK when found, FAIL otherwise.
  */
     static int
-lookup_arg(char_u *name, size_t len, cctx_T *cctx)
+lookup_arg(
+       char_u  *name,
+       size_t  len,
+       int     *idxp,
+       type_T  **type,
+       int     *gen_load_outer,
+       cctx_T  *cctx)
 {
     int            idx;
+    char_u  *va_name;
 
     if (len == 0)
-       return -1;
+       return FAIL;
     for (idx = 0; idx < cctx->ctx_ufunc->uf_args.ga_len; ++idx)
     {
        char_u *arg = FUNCARG(cctx->ctx_ufunc, idx);
 
-       if (STRNCMP(name, arg, len) == 0 && STRLEN(arg) == len)
-           return idx;
+       if (STRNCMP(name, arg, len) == 0 && arg[len] == NUL)
+       {
+           if (idxp != NULL)
+           {
+               // Arguments are located above the frame pointer.  One further
+               // if there is a vararg argument
+               *idxp = idx - (cctx->ctx_ufunc->uf_args.ga_len
+                                                           + STACK_FRAME_SIZE)
+                             + (cctx->ctx_ufunc->uf_va_name != NULL ? -1 : 0);
+
+               if (cctx->ctx_ufunc->uf_arg_types != NULL)
+                   *type = cctx->ctx_ufunc->uf_arg_types[idx];
+               else
+                   *type = &t_any;
+           }
+           return OK;
+       }
     }
-    return -1;
-}
 
-/*
- * Lookup a vararg argument in the current function.
- * Returns TRUE if there is a match.
- */
-    static int
-lookup_vararg(char_u *name, size_t len, cctx_T *cctx)
-{
-    char_u  *va_name = cctx->ctx_ufunc->uf_va_name;
+    va_name = cctx->ctx_ufunc->uf_va_name;
+    if (va_name != NULL
+                   && STRNCMP(name, va_name, len) == 0 && va_name[len] == NUL)
+    {
+       if (idxp != NULL)
+       {
+           // varargs is always the last argument
+           *idxp = -STACK_FRAME_SIZE - 1;
+           *type = cctx->ctx_ufunc->uf_va_type;
+       }
+       return OK;
+    }
+
+    if (cctx->ctx_outer != NULL)
+    {
+       // Lookup the name for an argument of the outer function.
+       if (lookup_arg(name, len, idxp, type, gen_load_outer, cctx->ctx_outer)
+                                                                        == OK)
+       {
+           *gen_load_outer = TRUE;
+           return OK;
+       }
+    }
 
-    return len > 0 && va_name != NULL
-                && STRNCMP(name, va_name, len) == 0 && STRLEN(va_name) == len;
+    return FAIL;
 }
 
 /*
@@ -1584,7 +1621,7 @@ reserve_local(cctx_T *cctx, char_u *name, size_t len, int isConst, type_T *type)
 {
     lvar_T  *lvar;
 
-    if (lookup_arg(name, len, cctx) >= 0 || lookup_vararg(name, len, cctx))
+    if (lookup_arg(name, len, NULL, NULL, NULL, cctx) == OK)
     {
        emsg_namelen(_("E1006: %s is used as an argument"), name, (int)len);
        return NULL;
@@ -2452,26 +2489,10 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error)
        if (name == NULL)
            return FAIL;
 
-       idx = lookup_arg(*arg, len, cctx);
-       if (idx >= 0)
+       if (lookup_arg(*arg, len, &idx, &type, &gen_load_outer, cctx) == OK)
        {
-           if (cctx->ctx_ufunc->uf_arg_types != NULL)
-               type = cctx->ctx_ufunc->uf_arg_types[idx];
-           else
-               type = &t_any;
-
-           // Arguments are located above the frame pointer.
-           idx -= cctx->ctx_ufunc->uf_args.ga_len + STACK_FRAME_SIZE;
-           if (cctx->ctx_ufunc->uf_va_name != NULL)
-               --idx;
-           gen_load = TRUE;
-       }
-       else if (lookup_vararg(*arg, len, cctx))
-       {
-           // varargs is always the last argument
-           idx = -STACK_FRAME_SIZE - 1;
-           type = cctx->ctx_ufunc->uf_va_type;
-           gen_load = TRUE;
+           if (!gen_load_outer)
+               gen_load = TRUE;
        }
        else
        {