]> granicus.if.org Git - vim/commitdiff
patch 8.2.0683: Vim9: parsing type does not always work v8.2.0683
authorBram Moolenaar <Bram@vim.org>
Sat, 2 May 2020 21:12:58 +0000 (23:12 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 2 May 2020 21:12:58 +0000 (23:12 +0200)
Problem:    Vim9: parsing type does not always work.
Solution:   Handle func type without return value.  Test more closures.
            Fix type check offset.  Fix garbage collection.

src/proto/vim9execute.pro
src/testdir/test_vim9_func.vim
src/userfunc.c
src/version.c
src/vim9compile.c
src/vim9execute.c

index 4f7262d7419f1e3d94083fd62bb7a6ff3a578c5e..578fe81e1ba27214a203fd4fdb2ed271fca76968 100644 (file)
@@ -1,6 +1,7 @@
 /* vim9execute.c */
-int call_def_function(ufunc_T *ufunc, int argc, typval_T *argv, typval_T *rettv);
+int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, typval_T *rettv);
 void ex_disassemble(exarg_T *eap);
 int tv2bool(typval_T *tv);
 int check_not_string(typval_T *tv);
+int set_ref_in_dfunc(ufunc_T *ufunc, int copyID);
 /* vim: set ft=c : */
index e1b3b7ffd6cda536efcfb1d6b68cb8621073d69a..a01e27c72961f98fac524781646428607dd9aaed 100644 (file)
@@ -662,5 +662,49 @@ def Test_closure_ref_after_return()
   unlet g:Ref
 enddef
 
+def MakeTwoRefs()
+  let local = ['some']
+  g:Extend = {s -> local->add(s)}
+  g:Read = {-> local}
+enddef
+
+def Test_closure_two_refs()
+  MakeTwoRefs()
+  assert_equal('some', join(g:Read(), ' '))
+  g:Extend('more')
+  assert_equal('some more', join(g:Read(), ' '))
+  g:Extend('even')
+  assert_equal('some more even', join(g:Read(), ' '))
+
+  unlet g:Extend
+  unlet g:Read
+enddef
+
+" TODO: fix memory leak when using same function again.
+def MakeTwoRefs_2()
+  let local = ['some']
+  g:Extend = {s -> local->add(s)}
+  g:Read = {-> local}
+enddef
+
+def ReadRef(Ref: func(): list<string>): string
+  return join(Ref(), ' ')
+enddef
+
+def ExtendRef(Ref: func(string), add: string)
+  Ref(add)
+enddef
+
+def Test_closure_two_indirect_refs()
+  MakeTwoRefs_2()
+  assert_equal('some', ReadRef(g:Read))
+  ExtendRef(g:Extend, 'more')
+  assert_equal('some more', ReadRef(g:Read))
+  ExtendRef(g:Extend, 'even')
+  assert_equal('some more even', ReadRef(g:Read))
+
+  unlet g:Extend
+  unlet g:Read
+enddef
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
index 2493dfea0c43f08692a5c9441dbbe9dd8612bc67..6aee37795391eec8b8d552725a52bbb2621f74a0 100644 (file)
@@ -4392,6 +4392,8 @@ set_ref_in_functions(int copyID)
            fp = HI2UF(hi);
            if (!func_name_refcount(fp->uf_name))
                abort = abort || set_ref_in_func(NULL, fp, copyID);
+           else if (fp->uf_dfunc_idx >= 0)
+               abort = abort || set_ref_in_dfunc(fp, copyID);
        }
     }
     return abort;
@@ -4439,7 +4441,10 @@ set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
     {
        for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped)
            abort = abort || set_ref_in_funccal(fc, copyID);
+       if (fp->uf_dfunc_idx >= 0)
+           abort = abort || set_ref_in_dfunc(fp, copyID);
     }
+
     vim_free(tofree);
     return abort;
 }
index 21cda476a55f49d6bb09feb7c6211784b7a3c83f..ae0855405ccbe17f56b3e48b326e0ba3638995ad 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    683,
 /**/
     682,
 /**/
index eb84e3590904a849f5212b82ff5a0369421e9b4f..a4a71de1f37ec9d26e0210f9bf8787493ca4c337 100644 (file)
@@ -824,7 +824,7 @@ generate_TYPECHECK(cctx_T *cctx, type_T *vartype, int offset)
     isn->isn_arg.type.ct_off = offset;
 
     // type becomes vartype
-    ((type_T **)stack->ga_data)[stack->ga_len - 1] = vartype;
+    ((type_T **)stack->ga_data)[stack->ga_len + offset] = vartype;
 
     return OK;
 }
@@ -1671,8 +1671,13 @@ skip_type(char_u *start)
            if (*p == ',')
                p = skipwhite(p + 1);
        }
-       if (*p == ')' && p[1] == ':')
-           p = skip_type(skipwhite(p + 2));
+       if (*p == ')')
+       {
+           if (p[1] == ':')
+               p = skip_type(skipwhite(p + 2));
+           else
+               p = skipwhite(p + 1);
+       }
     }
 
     return p;
index c27bcf0ab26ba5ca5daf60dda64b4853dd4df78b..2404282f8a7f5fcabfbb13dfa69f98932957df48 100644 (file)
@@ -2437,11 +2437,12 @@ ex_disassemble(exarg_T *eap)
                break;
            case ISN_FUNCREF:
                {
+                   funcref_T   *funcref = &iptr->isn_arg.funcref;
                    dfunc_T     *df = ((dfunc_T *)def_functions.ga_data)
-                                              + iptr->isn_arg.funcref.fr_func;
+                                                           + funcref->fr_func;
 
                    smsg("%4d FUNCREF %s $%d", current, df->df_ufunc->uf_name,
-                          iptr->isn_arg.funcref.fr_var_idx + df->df_varcount);
+                                    funcref->fr_var_idx + dfunc->df_varcount);
                }
                break;
 
@@ -2675,5 +2676,25 @@ check_not_string(typval_T *tv)
     return OK;
 }
 
+/*
+ * Mark items in a def function as used.
+ */
+    int
+set_ref_in_dfunc(ufunc_T *ufunc, int copyID)
+{
+    dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
+    int            abort = FALSE;
+
+    if (dfunc->df_funcstack != NULL)
+    {
+       typval_T    *stack = dfunc->df_funcstack->fs_ga.ga_data;
+       int         idx;
+
+       for (idx = 0; idx < dfunc->df_funcstack->fs_ga.ga_len; ++idx)
+           abort = abort || set_ref_in_item(stack + idx, copyID, NULL, NULL);
+    }
+    return abort;
+}
+
 
 #endif // FEAT_EVAL