diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-10-01 13:01:34 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-10-01 13:01:34 +0200 |
commit | 5366e1aecfff4546df6af86cf98013f23ed5c3bd (patch) | |
tree | bb7d5a1c8452bcc7572828402b25232c3df75b2a /src | |
parent | 55759b522814995af36803823d342d51d68c0b67 (diff) | |
download | vim-git-5366e1aecfff4546df6af86cf98013f23ed5c3bd.tar.gz |
patch 8.2.1778: Vim9: returning from a partial call clears outer contextv8.2.1778
Problem: Vim9: returning from a partial call clears outer context, causing
a crash.
Solution: Put the outer context in the stack frame. (closes #7044)
Diffstat (limited to 'src')
-rw-r--r-- | src/testdir/test_vim9_func.vim | 15 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9.h | 10 | ||||
-rw-r--r-- | src/vim9execute.c | 10 |
4 files changed, 31 insertions, 6 deletions
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index c9f902773..eec5af62f 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -1384,6 +1384,21 @@ def Test_nested_closure_fails() CheckScriptFailure(lines, 'E1012:') enddef +def Test_nested_lambda() + var lines =<< trim END + vim9script + def Func() + var x = 4 + var Lambda1 = {-> 7} + var Lambda2 = {-> [Lambda1(), x]} + var res = Lambda2() + assert_equal([7, 4], res) + enddef + Func() + END + CheckScriptSuccess(lines) +enddef + def Test_sort_return_type() var res: list<number> res = [1, 2, 3]->sort() diff --git a/src/version.c b/src/version.c index 446ac55eb..b92e99be5 100644 --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1778, +/**/ 1777, /**/ 1776, diff --git a/src/vim9.h b/src/vim9.h index a39fbbb4e..663faa680 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -326,10 +326,12 @@ struct dfunc_S { }; // Number of entries used by stack frame for a function call. -// - function index -// - instruction index -// - previous frame index -#define STACK_FRAME_SIZE 3 +// - ec_dfunc_idx: function index +// - ec_iidx: instruction index +// - ec_outer_stack: stack used for closures TODO: can we avoid this? +// - ec_outer_frame: stack frame for closures +// - ec_frame_idx: previous frame index +#define STACK_FRAME_SIZE 5 #ifdef DEFINE_VIM9_GLOBALS diff --git a/src/vim9execute.c b/src/vim9execute.c index 5a9435429..4013571a0 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -239,7 +239,9 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) // Store current execution state in stack frame for ISN_RETURN. STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx; STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx; - STACK_TV_BOT(2)->vval.v_number = ectx->ec_frame_idx; + STACK_TV_BOT(2)->vval.v_string = (void *)ectx->ec_outer_stack; + STACK_TV_BOT(3)->vval.v_number = ectx->ec_outer_frame; + STACK_TV_BOT(4)->vval.v_number = ectx->ec_frame_idx; ectx->ec_frame_idx = ectx->ec_stack.ga_len; // Initialize local variables @@ -455,7 +457,11 @@ func_return(ectx_T *ectx) // Restore the previous frame. ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx)->vval.v_number; ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx + 1)->vval.v_number; - ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx + 2)->vval.v_number; + ectx->ec_outer_stack = + (void *)STACK_TV(ectx->ec_frame_idx + 2)->vval.v_string; + ectx->ec_outer_frame = STACK_TV(ectx->ec_frame_idx + 3)->vval.v_number; + // restoring ec_frame_idx must be last + ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx + 4)->vval.v_number; dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; ectx->ec_instr = dfunc->df_instr; |