changeset 24645:668df21d8bc6 v8.2.2861

patch 8.2.2861: Vim9: "legacy return" is not recognized as a return statement Commit: https://github.com/vim/vim/commit/3b1373b193ce5fbf25e852277a4ecc98688c7bb8 Author: Bram Moolenaar <Bram@vim.org> Date: Mon May 17 00:01:42 2021 +0200 patch 8.2.2861: Vim9: "legacy return" is not recognized as a return statement Problem: Vim9: "legacy return" is not recognized as a return statement. Solution: Specifically check for a return command. (closes https://github.com/vim/vim/issues/8213)
author Bram Moolenaar <Bram@vim.org>
date Mon, 17 May 2021 00:15:03 +0200
parents 20eabe0f4d72
children e0fe4fd5cf3c
files src/testdir/test_vim9_expr.vim src/version.c src/vim9.h src/vim9compile.c src/vim9execute.c
diffstat 5 files changed, 95 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -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
--- 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 */
 /**/
+    2861,
+/**/
     2860,
 /**/
     2859,
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -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
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2174,6 +2174,25 @@ generate_EXEC(cctx_T *cctx, char_u *line
 }
 
     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)
 {
     isn_T	*isn;
@@ -5321,10 +5340,11 @@ compile_expr0(char_u **arg,  cctx_T *cct
 }
 
 /*
- * 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_re
 
     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:
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -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 *inst
 	    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;