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:') CheckDefAndScriptFailure(lines, 'E15:')
enddef enddef
def LegacyReturn(): string
legacy return #{key: 'ok'}.key
enddef
def Test_expr7_legacy_script() def Test_expr7_legacy_script()
var lines =<< trim END var lines =<< trim END
let s:legacy = 'legacy' let s:legacy = 'legacy'
@@ -2790,6 +2794,17 @@ def Test_expr7_legacy_script()
call assert_equal('legacy', GetLocalPrefix()) call assert_equal('legacy', GetLocalPrefix())
END END
CheckScriptSuccess(lines) 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 enddef
def Echo(arg: any): string def Echo(arg: any): string

View File

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

View File

@@ -14,6 +14,7 @@
typedef enum { typedef enum {
ISN_EXEC, // execute Ex command line isn_arg.string ISN_EXEC, // execute Ex command line isn_arg.string
ISN_EXECCONCAT, // execute Ex command from isn_arg.number items on stack 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_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_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 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; 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 static int
generate_EXECCONCAT(cctx_T *cctx, int count) 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 * 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; char_u *p = arg;
garray_T *stack = &cctx->ctx_type_stack; garray_T *stack = &cctx->ctx_type_stack;
type_T *stack_type; type_T *stack_type;
if (*p != NUL && *p != '|' && *p != '\n') 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 // compile return argument into instructions
if (compile_expr0(&p, cctx) == FAIL) if (compile_expr0(&p, cctx) == FAIL)
return NULL; return NULL;
}
if (cctx->ctx_skip != SKIP_YES) if (cctx->ctx_skip != SKIP_YES)
{ {
@@ -9193,7 +9228,15 @@ compile_def_function(
// When using ":legacy cmd" always use compile_exec(). // When using ":legacy cmd" always use compile_exec().
if (local_cmdmod.cmod_flags & CMOD_LEGACY) 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; ea.cmdidx = CMD_legacy;
}
if (p == ea.cmd && ea.cmdidx != CMD_SIZE) if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
{ {
@@ -9254,7 +9297,8 @@ compile_def_function(
goto erret; goto erret;
case CMD_return: 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; cctx.ctx_had_return = TRUE;
break; break;
@@ -9605,6 +9649,7 @@ delete_instr(isn_T *isn)
{ {
case ISN_DEF: case ISN_DEF:
case ISN_EXEC: case ISN_EXEC:
case ISN_LEGACY_EVAL:
case ISN_LOADAUTO: case ISN_LOADAUTO:
case ISN_LOADB: case ISN_LOADB:
case ISN_LOADENV: case ISN_LOADENV:

View File

@@ -1388,6 +1388,27 @@ exec_instructions(ectx_T *ectx)
} }
break; 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 // push typeval VAR_INSTR with instructions to be executed
case ISN_INSTR: case ISN_INSTR:
{ {
@@ -4464,6 +4485,10 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
case ISN_EXEC: case ISN_EXEC:
smsg("%s%4d EXEC %s", pfx, current, iptr->isn_arg.string); smsg("%s%4d EXEC %s", pfx, current, iptr->isn_arg.string);
break; break;
case ISN_LEGACY_EVAL:
smsg("%s%4d EVAL legacy %s", pfx, current,
iptr->isn_arg.string);
break;
case ISN_REDIRSTART: case ISN_REDIRSTART:
smsg("%s%4d REDIR", pfx, current); smsg("%s%4d REDIR", pfx, current);
break; break;