changeset 27084:6fc63c6a7ee7 v8.2.4071

patch 8.2.4071: Vim9: no detection of return in try/endtry Commit: https://github.com/vim/vim/commit/53c296112edd8471eb63afbca03f96bad164c813 Author: Bram Moolenaar <Bram@vim.org> 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.
author Bram Moolenaar <Bram@vim.org>
date Wed, 12 Jan 2022 17:30:07 +0100
parents 15f9359846ad
children 40b273e28f26
files src/testdir/test_vim9_script.vim src/version.c src/vim9.h src/vim9cmds.c src/vim9compile.c
diffstat 5 files changed, 73 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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,
--- 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 {
--- 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)
--- 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);