Skip to content

Commit

Permalink
patch 8.2.2861: Vim9: "legacy return" is not recognized as a return s…
Browse files Browse the repository at this point in the history
…tatement

Problem:    Vim9: "legacy return" is not recognized as a return statement.
Solution:   Specifically check for a return command. (closes #8213)
  • Loading branch information
brammool committed May 16, 2021
1 parent 1764faa commit 3b1373b
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 7 deletions.
15 changes: 15 additions & 0 deletions src/testdir/test_vim9_expr.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2861,
/**/
2860,
/**/
Expand Down
1 change: 1 addition & 0 deletions src/vim9.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 52 additions & 7 deletions src/vim9compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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')
{
// 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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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:
Expand Down
25 changes: 25 additions & 0 deletions src/vim9execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
{
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 3b1373b

Please sign in to comment.