diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 030ff833ef..79bb9d8216 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -550,6 +550,47 @@ def Test_not_missing_return() v9.CheckScriptSuccess(lines) enddef +" Test for an if-else block ending in a throw statement +def Test_if_else_with_throw() + var lines =<< trim END + def Ifelse_Throw1(): number + if false + return 1 + else + throw 'Error' + endif + enddef + defcompile + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + def Ifelse_Throw2(): number + if true + throw 'Error' + else + return 2 + endif + enddef + defcompile + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + def Ifelse_Throw3(): number + if true + return 1 + elseif false + throw 'Error' + else + return 3 + endif + enddef + defcompile + END + v9.CheckScriptSuccess(lines) +enddef + def Test_return_bool() var lines =<< trim END vim9script diff --git a/src/version.c b/src/version.c index ca353c28c8..d4fd17e6c6 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 976, /**/ 975, /**/ diff --git a/src/vim9cmds.c b/src/vim9cmds.c index c7fa60aa4f..f8ebfb1288 100644 --- a/src/vim9cmds.c +++ b/src/vim9cmds.c @@ -602,7 +602,9 @@ compile_elseif(char_u *arg, cctx_T *cctx) return NULL; } unwind_locals(cctx, scope->se_local_count, TRUE); - if (!cctx->ctx_had_return) + if (!cctx->ctx_had_return && !cctx->ctx_had_throw) + // the previous if block didn't end in a "return" or a "throw" + // statement. scope->se_u.se_if.is_had_return = FALSE; if (cctx->ctx_skip == SKIP_NOT) @@ -749,7 +751,9 @@ compile_else(char_u *arg, cctx_T *cctx) return NULL; } unwind_locals(cctx, scope->se_local_count, TRUE); - if (!cctx->ctx_had_return) + if (!cctx->ctx_had_return && !cctx->ctx_had_throw) + // the previous if block didn't end in a "return" or a "throw" + // statement. scope->se_u.se_if.is_had_return = FALSE; scope->se_u.se_if.is_seen_else = TRUE; @@ -821,7 +825,9 @@ compile_endif(char_u *arg, cctx_T *cctx) } ifscope = &scope->se_u.se_if; unwind_locals(cctx, scope->se_local_count, TRUE); - if (!cctx->ctx_had_return) + if (!cctx->ctx_had_return && !cctx->ctx_had_throw) + // the previous if block didn't end in a "return" or a "throw" + // statement. ifscope->is_had_return = FALSE; if (scope->se_u.se_if.is_if_label >= 0) diff --git a/src/vim9compile.c b/src/vim9compile.c index c8a50cf4c1..a2dd77a441 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4407,7 +4407,16 @@ compile_def_function_body( cctx->ctx_had_return ? "return" : "throw"); return FAIL; } - cctx->ctx_had_throw = FALSE; + + // When processing the end of an if-else block, don't clear the + // "ctx_had_throw" flag. If an if-else block ends in a "throw" + // statement, then it is considered to end in a "return" statement. + // The "ctx_had_throw" is cleared immediately after processing the + // if-else block ending statement. + // Otherwise, clear the "had_throw" flag. + if (ea.cmdidx != CMD_else && ea.cmdidx != CMD_elseif + && ea.cmdidx != CMD_endif) + cctx->ctx_had_throw = FALSE; p = skipwhite(p); if (ea.cmdidx != CMD_SIZE @@ -4474,13 +4483,16 @@ compile_def_function_body( case CMD_elseif: line = compile_elseif(p, cctx); cctx->ctx_had_return = FALSE; + cctx->ctx_had_throw = FALSE; break; case CMD_else: line = compile_else(p, cctx); cctx->ctx_had_return = FALSE; + cctx->ctx_had_throw = FALSE; break; case CMD_endif: line = compile_endif(p, cctx); + cctx->ctx_had_throw = FALSE; break; case CMD_while: @@ -4695,7 +4707,7 @@ compile_dfunc_scope_end_missing(cctx_T *cctx) } /* - * When compiling a def function, if it doesn not have an explicit return + * When compiling a def function, if it doesn't have an explicit return * statement, then generate a default return instruction. For an object * constructor, return the object. */