# HG changeset patch # User Bram Moolenaar # Date 1588454103 -7200 # Node ID aac52c32a91f8b3634d471152bffeb68952f4809 # Parent c7a2968adc2461ac27c241fcf43a919df3dc491d patch 8.2.0683: Vim9: parsing type does not always work Commit: https://github.com/vim/vim/commit/5adc55cb746893c6ddf7865ff654582902dee2e3 Author: Bram Moolenaar Date: Sat May 2 23:12:58 2020 +0200 patch 8.2.0683: Vim9: parsing type does not always work 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. diff --git a/src/proto/vim9execute.pro b/src/proto/vim9execute.pro --- a/src/proto/vim9execute.pro +++ b/src/proto/vim9execute.pro @@ -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 : */ 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 @@ -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 + 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 diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -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 *f { 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; } 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 */ /**/ + 683, +/**/ 682, /**/ 681, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -824,7 +824,7 @@ generate_TYPECHECK(cctx_T *cctx, type_T 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; diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -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