1
0
forked from aniani/vim

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 #8213)
This commit is contained in:
Bram Moolenaar
2021-05-17 00:01:42 +02:00
parent 1764faa386
commit 3b1373b193
5 changed files with 95 additions and 7 deletions

View 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

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2861,
/**/
2860,
/**/

View 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

View 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,20 +5340,36 @@ 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;
type_T *stack_type;
if (*p != NUL && *p != '|' && *p != '\n')
{
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)
{
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:

View 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;