]> granicus.if.org Git - vim/commitdiff
patch 8.2.2861: Vim9: "legacy return" is not recognized as a return statement v8.2.2861
authorBram Moolenaar <Bram@vim.org>
Sun, 16 May 2021 22:01:42 +0000 (00:01 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 16 May 2021 22:01:42 +0000 (00:01 +0200)
Problem:    Vim9: "legacy return" is not recognized as a return statement.
Solution:   Specifically check for a return command. (closes #8213)

src/testdir/test_vim9_expr.vim
src/version.c
src/vim9.h
src/vim9compile.c
src/vim9execute.c

index 718db8b70e54a4be23fad86de8860f5376e90b0b..fe5de29d0bb6628df980cb70c1ae81d2c7bee88d 100644 (file)
@@ -2777,6 +2777,10 @@ def Test_expr7_negate_add()
   CheckDefAndScriptFailure(lines, 'E15:')
 enddef
 
+def LegacyReturn(): string
+  legacy return #{key: 'ok'}.key
+enddef
+
 def Test_expr7_legacy_script()
   var lines =<< trim END
       let s:legacy = 'legacy'
@@ -2790,6 +2794,17 @@ def Test_expr7_legacy_script()
       call assert_equal('legacy', GetLocalPrefix())
   END
   CheckScriptSuccess(lines)
+
+  assert_equal('ok', LegacyReturn())
+
+  lines =<< trim END
+      vim9script 
+      def GetNumber(): number   
+          legacy return range(3)->map('v:val + 1') 
+      enddef 
+      echo GetNumber()
+  END
+  CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<number>')
 enddef
 
 def Echo(arg: any): string
index cd42c0a7ea8242952bbff0ff89502e5f642e43b8..fca2cd8c4ff7a991d018bf578b535995a544d45f 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2861,
 /**/
     2860,
 /**/
index 9f45ea41252afa7d284e2258681bcb16cd2a57be..b260bdf1f368d185acf542474ee4b4fcfacb9be7 100644 (file)
@@ -14,6 +14,7 @@
 typedef enum {
     ISN_EXEC,      // execute Ex command line isn_arg.string
     ISN_EXECCONCAT, // execute Ex command from isn_arg.number items on stack
+    ISN_LEGACY_EVAL, // evaluate expression isn_arg.string with legacy syntax.
     ISN_ECHO,      // echo isn_arg.echo.echo_count items on top of stack
     ISN_EXECUTE,    // execute Ex commands isn_arg.number items on top of stack
     ISN_ECHOMSG,    // echo Ex commands isn_arg.number items on top of stack
index 9aa93de7b21459a21b0c3f7646c8c76286640da2..160c8e428f97226b74a617e899a5f53907d74f4a 100644 (file)
@@ -2173,6 +2173,25 @@ generate_EXEC(cctx_T *cctx, char_u *line)
     return OK;
 }
 
+    static int
+generate_LEGACY_EVAL(cctx_T *cctx, char_u *line)
+{
+    isn_T      *isn;
+    garray_T   *stack = &cctx->ctx_type_stack;
+
+    RETURN_OK_IF_SKIP(cctx);
+    if ((isn = generate_instr(cctx, ISN_LEGACY_EVAL)) == NULL)
+       return FAIL;
+    isn->isn_arg.string = vim_strsave(line);
+
+    if (ga_grow(stack, 1) == FAIL)
+       return FAIL;
+    ((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
+    ++stack->ga_len;
+
+    return OK;
+}
+
     static int
 generate_EXECCONCAT(cctx_T *cctx, int count)
 {
@@ -5321,10 +5340,11 @@ compile_expr0(char_u **arg,  cctx_T *cctx)
 }
 
 /*
- * compile "return [expr]"
+ * Compile "return [expr]".
+ * When "legacy" is TRUE evaluate [expr] with legacy syntax
  */
     static char_u *
-compile_return(char_u *arg, int check_return_type, cctx_T *cctx)
+compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx)
 {
     char_u     *p = arg;
     garray_T   *stack = &cctx->ctx_type_stack;
@@ -5332,9 +5352,24 @@ compile_return(char_u *arg, int check_return_type, cctx_T *cctx)
 
     if (*p != NUL && *p != '|' && *p != '\n')
     {
-       // compile return argument into instructions
-       if (compile_expr0(&p, cctx) == FAIL)
-           return NULL;
+       if (legacy)
+       {
+           int save_flags = cmdmod.cmod_flags;
+
+           generate_LEGACY_EVAL(cctx, p);
+           if (need_type(&t_any, cctx->ctx_ufunc->uf_ret_type, -1,
+                                               0, cctx, FALSE, FALSE) == FAIL)
+               return NULL;
+           cmdmod.cmod_flags |= CMOD_LEGACY;
+           (void)skip_expr(&p, NULL);
+           cmdmod.cmod_flags = save_flags;
+       }
+       else
+       {
+           // compile return argument into instructions
+           if (compile_expr0(&p, cctx) == FAIL)
+               return NULL;
+       }
 
        if (cctx->ctx_skip != SKIP_YES)
        {
@@ -9193,7 +9228,15 @@ compile_def_function(
 
        // When using ":legacy cmd" always use compile_exec().
        if (local_cmdmod.cmod_flags & CMOD_LEGACY)
-           ea.cmdidx = CMD_legacy;
+       {
+           char_u *start = ea.cmd;
+
+           // ":legacy return expr" needs to be handled differently.
+           if (checkforcmd(&start, "return", 4))
+               ea.cmdidx = CMD_return;
+           else
+               ea.cmdidx = CMD_legacy;
+       }
 
        if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
        {
@@ -9254,7 +9297,8 @@ compile_def_function(
                    goto erret;
 
            case CMD_return:
-                   line = compile_return(p, check_return_type, &cctx);
+                   line = compile_return(p, check_return_type,
+                                local_cmdmod.cmod_flags & CMOD_LEGACY, &cctx);
                    cctx.ctx_had_return = TRUE;
                    break;
 
@@ -9605,6 +9649,7 @@ delete_instr(isn_T *isn)
     {
        case ISN_DEF:
        case ISN_EXEC:
+       case ISN_LEGACY_EVAL:
        case ISN_LOADAUTO:
        case ISN_LOADB:
        case ISN_LOADENV:
index 425cdb9bb24bb0c5d0a60aeef9bf68ff95176cd9..7f56597b3084ed5f18643624b08b6d1dce52741c 100644 (file)
@@ -1388,6 +1388,27 @@ exec_instructions(ectx_T *ectx)
                }
                break;
 
+           // Evaluate an expression with legacy syntax, push it onto the
+           // stack.
+           case ISN_LEGACY_EVAL:
+               {
+                   char_u  *arg = iptr->isn_arg.string;
+                   int     res;
+                   int     save_flags = cmdmod.cmod_flags;
+
+                   if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+                       return FAIL;
+                   tv = STACK_TV_BOT(0);
+                   init_tv(tv);
+                   cmdmod.cmod_flags |= CMOD_LEGACY;
+                   res = eval0(arg, tv, NULL, &EVALARG_EVALUATE);
+                   cmdmod.cmod_flags = save_flags;
+                   if (res == FAIL)
+                       goto on_error;
+                   ++ectx->ec_stack.ga_len;
+               }
+               break;
+
            // push typeval VAR_INSTR with instructions to be executed
            case ISN_INSTR:
                {
@@ -4464,6 +4485,10 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
            case ISN_EXEC:
                smsg("%s%4d EXEC %s", pfx, current, iptr->isn_arg.string);
                break;
+           case ISN_LEGACY_EVAL:
+               smsg("%s%4d EVAL legacy %s", pfx, current,
+                                                        iptr->isn_arg.string);
+               break;
            case ISN_REDIRSTART:
                smsg("%s%4d REDIR", pfx, current);
                break;