]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.0976: Vim9: missing return statement with throw v9.1.0976
authorYegappan Lakshmanan <yegappan@yahoo.com>
Mon, 30 Dec 2024 08:56:34 +0000 (09:56 +0100)
committerChristian Brabandt <cb@256bit.org>
Mon, 30 Dec 2024 08:56:34 +0000 (09:56 +0100)
Problem:  Vim9: missing return statement with throw
          (atitcreate)
Solution: Treat a throw statement at the end of an if-else block as a
          return statement (Yegappan Lakshmanan)

fixes: #16312
closes: #16338

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/testdir/test_vim9_func.vim
src/version.c
src/vim9cmds.c
src/vim9compile.c

index 030ff833ef40c1a3f3a5507d280c2e8797cff60a..79bb9d8216cdacbaf27352bb25708d9dc13dabaa 100644 (file)
@@ -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
index ca353c28c85810b95858ea8a4b3e9dd48450a038..d4fd17e6c6b8b0c88b23fa04d50e5b66fe1379ce 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    976,
 /**/
     975,
 /**/
index c7fa60aa4f29de01d0eee8c5ce76d82540277d5d..f8ebfb12888d01cc1afb3dbdc2b464d4e11104d0 100644 (file)
@@ -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)
index c8a50cf4c1ac1dd00d5c646224da37ba6678baab..a2dd77a4416867bc8076c3eb9af0ef3546ba064d 100644 (file)
@@ -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.
  */