# HG changeset patch # User Bram Moolenaar # Date 1642005007 -3600 # Node ID 6fc63c6a7ee7531aba4c47f8bd722cc346205f64 # Parent 15f9359846ad28ec2706e539b34dd5fe8d7dd5f5 patch 8.2.4071: Vim9: no detection of return in try/endtry Commit: https://github.com/vim/vim/commit/53c296112edd8471eb63afbca03f96bad164c813 Author: Bram Moolenaar Date: Wed Jan 12 16:18:18 2022 +0000 patch 8.2.4071: Vim9: no detection of return in try/endtry Problem: Vim9: no detection of return in try/endtry. (Dominique Pell?) Solution: Check if any of the blocks inside try/endtry did not end in return. diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -667,7 +667,6 @@ def Test_try_catch_throw() finally return 6 endtry - return -1 enddef assert_equal(6, ReturnInFinally()) @@ -708,6 +707,64 @@ def Test_try_catch_throw() CheckDefAndScriptSuccess(lines) enddef +def Test_try_ends_in_return() + var lines =<< trim END + vim9script + def Foo(): string + try + return 'foo' + catch + return 'caught' + endtry + enddef + assert_equal('foo', Foo()) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + def Foo(): string + try + return 'foo' + catch + return 'caught' + endtry + echo 'notreached' + enddef + assert_equal('foo', Foo()) + END + CheckScriptFailure(lines, 'E1095:') + + lines =<< trim END + vim9script + def Foo(): string + try + return 'foo' + catch /x/ + return 'caught' + endtry + enddef + assert_equal('foo', Foo()) + END + CheckScriptFailure(lines, 'E1027:') + + lines =<< trim END + vim9script + def Foo(): string + try + echo 'foo' + catch + echo 'caught' + finally + return 'done' + endtry + enddef + assert_equal('done', Foo()) + END + CheckScriptSuccess(lines) + +enddef + def Test_try_in_catch() var lines =<< trim END vim9script diff --git a/src/version.c b/src/version.c --- 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 */ /**/ + 4071, +/**/ 4070, /**/ 4069, diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -594,6 +594,8 @@ typedef struct { endlabel_T *ts_end_label; // jump to :finally or :endtry int ts_catch_label; // instruction idx of last CATCH int ts_caught_all; // "catch" without argument encountered + int ts_has_finally; // "finally" encountered + int ts_no_return; // one of the blocks did not end in return } tryscope_T; typedef enum { diff --git a/src/vim9cmds.c b/src/vim9cmds.c --- a/src/vim9cmds.c +++ b/src/vim9cmds.c @@ -1343,6 +1343,8 @@ compile_catch(char_u *arg, cctx_T *cctx emsg(_(e_catch_unreachable_after_catch_all)); return NULL; } + if (!cctx->ctx_had_return) + scope->se_u.se_try.ts_no_return = TRUE; if (cctx->ctx_skip != SKIP_YES) { @@ -1498,6 +1500,7 @@ compile_finally(char_u *arg, cctx_T *cct isn->isn_arg.jump.jump_where = this_instr; scope->se_u.se_try.ts_catch_label = 0; } + scope->se_u.se_try.ts_has_finally = TRUE; if (generate_instr(cctx, ISN_FINALLY) == NULL) return NULL; } @@ -1567,6 +1570,14 @@ compile_endtry(char_u *arg, cctx_T *cctx } } + // If there is a finally clause that ends in return then we will return. + // If one of the blocks didn't end in "return" or we did not catch all + // exceptions reset the had_return flag. + if (!(scope->se_u.se_try.ts_has_finally && cctx->ctx_had_return) + && (scope->se_u.se_try.ts_no_return + || !scope->se_u.se_try.ts_caught_all)) + cctx->ctx_had_return = FALSE; + compile_endblock(cctx); if (cctx->ctx_skip != SKIP_YES) diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3041,7 +3041,6 @@ compile_def_function( break; case CMD_endtry: line = compile_endtry(p, &cctx); - cctx.ctx_had_return = FALSE; break; case CMD_throw: line = compile_throw(p, &cctx);