Mercurial > vim
changeset 28035:9f8535cf6f1b v8.2.4542
patch 8.2.4542: Vim9: "break" inside try/catch not handled correctly
Commit: https://github.com/vim/vim/commit/873f8243f6feadec72d9bf6203e550cc1b66611a
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Mar 10 21:53:44 2022 +0000
patch 8.2.4542: Vim9: "break" inside try/catch not handled correctly
Problem: Vim9: "break" inside try/catch not handled correctly.
Solution: First jump to :endtry. (closes https://github.com/vim/vim/issues/9927)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 10 Mar 2022 23:00:04 +0100 |
parents | c6d9d86245e2 |
children | 3167a59d5fc2 |
files | src/testdir/test_vim9_script.vim src/version.c src/vim9.h src/vim9cmds.c |
diffstat | 4 files changed, 45 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -907,6 +907,28 @@ def Test_continue_in_try_in_while() unlet g:sequence enddef +def Test_break_in_try_in_for() + var lines =<< trim END + vim9script + def Ls(): list<string> + var ls: list<string> + for s in ['abc', 'def'] + for _ in [123, 456] + try + eval [][0] + catch + break + endtry + endfor + ls += [s] + endfor + return ls + enddef + assert_equal(['abc', 'def'], Ls()) + END + v9.CheckScriptSuccess(lines) +enddef + def Test_nocatch_return_in_try() # return in try block returns normally def ReturnInTry(): string
--- 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 */ /**/ + 4542, +/**/ 4541, /**/ 4540,
--- a/src/vim9.h +++ b/src/vim9.h @@ -121,7 +121,7 @@ typedef enum { ISN_CATCH, // drop v:exception ISN_FINALLY, // start of :finally block ISN_ENDTRY, // take entry off from ec_trystack - ISN_TRYCONT, // handle :continue inside a :try statement + ISN_TRYCONT, // handle :continue or :break inside a :try statement // more expression operations ISN_ADDLIST, // add two lists
--- a/src/vim9cmds.c +++ b/src/vim9cmds.c @@ -1206,6 +1206,7 @@ compile_continue(char_u *arg, cctx_T *cc compile_break(char_u *arg, cctx_T *cctx) { scope_T *scope = cctx->ctx_scope; + int try_scopes = 0; endlabel_T **el; for (;;) @@ -1215,16 +1216,29 @@ compile_break(char_u *arg, cctx_T *cctx) emsg(_(e_break_without_while_or_for)); return NULL; } - if (scope->se_type == FOR_SCOPE || scope->se_type == WHILE_SCOPE) + if (scope->se_type == FOR_SCOPE) + { + el = &scope->se_u.se_for.fs_end_label; break; + } + if (scope->se_type == WHILE_SCOPE) + { + el = &scope->se_u.se_while.ws_end_label; + break; + } + if (scope->se_type == TRY_SCOPE) + ++try_scopes; scope = scope->se_outer; } - // Jump to the end of the FOR or WHILE loop. - if (scope->se_type == FOR_SCOPE) - el = &scope->se_u.se_for.fs_end_label; - else - el = &scope->se_u.se_while.ws_end_label; + if (try_scopes > 0) + // Inside one or more try/catch blocks we first need to jump to the + // "finally" or "endtry" to cleanup. Then come to the next JUMP + // intruction, which we don't know the index of yet. + generate_TRYCONT(cctx, try_scopes, cctx->ctx_instr.ga_len + 1); + + // Jump to the end of the FOR or WHILE loop. The instruction index will be + // filled in later. if (compile_jump_to_end(el, JUMP_ALWAYS, cctx) == FAIL) return FAIL;