Compare commits

...

13 Commits

Author SHA1 Message Date
Bram Moolenaar
128d307963 patch 8.2.1010: build failure in libvterm with debug enabled
Problem:    Build failure in libvterm with debug enabled. (John Little)
Solution:   Use "->" instead of ".".
2020-06-19 17:20:41 +02:00
Bram Moolenaar
c5b1c20b6b patch 8.2.1009: Vim9: some failures not checked for
Problem:    Vim9: some failures not checked for.
Solution:   Add test cases.  Remove unused code.
2020-06-18 22:43:27 +02:00
Bram Moolenaar
0779fab297 patch 8.2.1008: Vim9: no test for disassambling newly added instructions
Problem:    Vim9: no test for disassambling newly added instructions.
Solution:   Add a function and check disassembly.
2020-06-18 22:18:18 +02:00
Bram Moolenaar
c8cb883015 patch 8.2.1007: completion doesn't work after ":r ++arg !"
Problem:    Completion doesn't work after ":r ++arg !".
Solution:   Skip over "++arg". (Christian Brabandt, closes #6275,
            closes #6258)
2020-06-18 21:14:30 +02:00
Bram Moolenaar
efd8855594 patch 8.2.1006: Vim9: require unnecessary return statement
Problem:    Vim9: require unnecessary return statement.
Solution:   Improve the use of the had_return flag. (closes #6270)
2020-06-18 20:50:10 +02:00
Bram Moolenaar
9b68c82b7c patch 8.2.1005: Vim9: using TRUE/FALSE/MAYBE for ctx_skip is confusing
Problem:    Vim9: using TRUE/FALSE/MAYBE for ctx_skip is confusing.
Solution:   Use an enum value.
2020-06-18 19:31:08 +02:00
Bram Moolenaar
511feec6f0 patch 8.2.1004: line numbers below filler lines not always updated
Problem:    Line numbers below filler lines not always updated.
Solution:   Don't break out of the win_line() loop too early. (Christian
            Brabandt, closes #6294, closes #6138)
2020-06-18 19:15:27 +02:00
Bram Moolenaar
865af6b990 patch 8.2.1003: Vim9: return type of sort() is too generic
Problem:    Vim9: return type of sort() is too generic.
Solution:   Get type from the first argument. (closes #6292)
2020-06-18 18:45:49 +02:00
Bram Moolenaar
ceb2e77510 patch 8.2.1002: test may fail when run directly
Problem:    Test may fail when run directly.
Solution:   Check if g:run_nr exists. (Christian Brabandt, closes #6285)
2020-06-18 18:33:59 +02:00
Bram Moolenaar
72abcf42d4 patch 8.2.1001: Vim9: crash with nested "if" and assignment
Problem:    Vim9: crash with nested "if" and assignment.
Solution:   Skip more of the assignment.  Do not set ctx_skip when code is
            reachable.
2020-06-18 18:26:24 +02:00
Bram Moolenaar
158ea175a9 patch 8.2.1000: get error when leaving Ex mode with :visual
Problem:    Get error when leaving Ex mode with :visual and a CmdLineEnter
            autocommand was used.
Solution:   Reset ex_pressedreturn. (closes #6293)
2020-06-18 17:28:39 +02:00
Bram Moolenaar
2f03e5a0a9 patch 8.2.0999: moving to next sentence gets stuck on quote
Problem:    Moving to next sentence gets stuck on quote.
Solution:   When moving to the next sentence doesn't result in moving, advance
            a character and try again. (closes #6291)
2020-06-18 15:33:25 +02:00
Bram Moolenaar
3d9207ad2f patch 8.2.0998: not all tag code is tested
Problem:    Not all tag code is tested.
Solution:   Add a few more test cases. (Yegappan Lakshmanan, closes #6284)
2020-06-17 22:58:35 +02:00
21 changed files with 543 additions and 99 deletions

View File

@@ -1146,6 +1146,15 @@ set_one_cmd_context(
arg = skipwhite(arg);
}
// Skip over ++argopt argument
if ((ea.argt & EX_ARGOPT) && *arg != NUL && STRNCMP(arg, "++", 2) == 0)
{
p = arg;
while (*p && !vim_isspace(*p))
MB_PTR_ADV(p);
arg = skipwhite(p);
}
// Check for '|' to separate commands and '"' to start comments.
// Don't do this for ":read !cmd" and ":write !cmd".
if ((ea.argt & EX_TRLBAR) && !usefilter)

View File

@@ -1287,13 +1287,13 @@ win_line(
// When still displaying '$' of change command, stop at cursor.
// When only displaying the (relative) line number and that's done,
// stop here.
if ((dollar_vcol >= 0 && wp == curwin
&& lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
if (((dollar_vcol >= 0 && wp == curwin
&& lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol)
|| (number_only && draw_state > WL_NR))
#ifdef FEAT_DIFF
&& filler_todo <= 0
#endif
)
|| (number_only && draw_state > WL_NR))
{
screen_line(screen_row, wp->w_wincol, col, -(int)wp->w_width,
screen_line_flags);

View File

@@ -339,6 +339,14 @@ ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
return &t_job;
}
static type_T *
ret_first_arg(int argcount, type_T **argtypes)
{
if (argcount > 0)
return argtypes[0];
return &t_void;
}
static type_T *ret_f_function(int argcount, type_T **argtypes);
/*
@@ -849,7 +857,7 @@ static funcentry_T global_functions[] =
{"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
{"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
{"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
{"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
{"sort", 1, 3, FEARG_1, ret_first_arg, f_sort},
{"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
{"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
{"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},

View File

@@ -1895,7 +1895,7 @@ do_one_cmd(
p = ea.cmd;
while (ASCII_ISALNUM(*p))
++p;
p = vim_strnsave(ea.cmd, (int)(p - ea.cmd));
p = vim_strnsave(ea.cmd, p - ea.cmd);
ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, TRUE, NULL);
vim_free(p);
// If the autocommands did something and didn't cause an error, try
@@ -6215,6 +6215,7 @@ do_exedit(
|| eap->cmdidx == CMD_view))
{
exmode_active = FALSE;
ex_pressedreturn = FALSE;
if (*eap->arg == NUL)
{
// Special case: ":global/pat/visual\NLvi-commands"

View File

@@ -291,7 +291,7 @@ static int on_text(const char bytes[], size_t len, void *user)
if (state->pos.row >= state->rows)
{
DEBUG_LOG2("libvterm: on_text() pos.row %d out of range (rows = %d)\n", state->pos.row, state.rows);
DEBUG_LOG2("libvterm: on_text() pos.row %d out of range (rows = %d)\n", state->pos.row, state->rows);
return 0;
}
// We'll have at most len codepoints, plus one from a previous incomplete

View File

@@ -0,0 +1,20 @@
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&|1+0#af5f00255&| @2>a+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|1| |a+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|2| |a+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|x+2#0000000#ff404010| +0&#ffd7ff255@33||+1&#ffffff0| +0#af5f00255&@1|3| |y+2#0000000#ff404010| +0&#ffd7ff255@31
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|4| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|5| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|6| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|7| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|8| |b+0#0000000&| @31
|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|1|,|1| @11|A|l@1
| +0&&@74

View File

@@ -0,0 +1,20 @@
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|1| |a+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&|2+0#af5f00255&| @2>a+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|1| |a+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|x+2#0000000#ff404010| +0&#ffd7ff255@33||+1&#ffffff0| +0#af5f00255&@1|2| |y+2#0000000#ff404010| +0&#ffd7ff255@31
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|3| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|4| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|5| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|6| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|7| |b+0#0000000&| @31
|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|2|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|2|,|1| @11|A|l@1
| +0&&@74

View File

@@ -0,0 +1,20 @@
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|2| |a+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|1| |a+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|a+0#0000000#ffffff0| @33||+1&&|3+0#af5f00255&| @2>a+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|x+2#0000000#ff404010| +0&#ffd7ff255@33||+1&#ffffff0| +0#af5f00255&@1|1| |y+2#0000000#ff404010| +0&#ffd7ff255@31
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
| +0#0000e05#a8a8a8255@1|x+0#0000000#5fd7ff255| @33||+1&#ffffff0| +0#af5f00255&@3|-+0#4040ff13#afffff255@32
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|2| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|3| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|4| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|5| |b+0#0000000&| @31
| +0#0000e05#a8a8a8255@1|b+0#0000000#ffffff0| @33||+1&&| +0#af5f00255&@1|6| |b+0#0000000&| @31
|~+0#4040ff13&| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|~| @35||+1#0000000&|~+0#4040ff13&| @35
|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]| @5|3|,|1| @11|A|l@1| |[+3&&|N|o| |N|a|m|e|]| |[|+|]| @5|3|,|1| @11|A|l@1
| +0&&@74

View File

@@ -28,10 +28,12 @@ endfunc
" The second argument is the minimum time to wait in msec, 10 if omitted.
func TermWait(buf, ...)
let wait_time = a:0 ? a:1 : 10
if g:run_nr == 2
let wait_time *= 4
elseif g:run_nr > 2
let wait_time *= 10
if exists('g:run_nr')
if g:run_nr == 2
let wait_time *= 4
elseif g:run_nr > 2
let wait_time *= 10
endif
endif
call term_wait(a:buf, wait_time)

View File

@@ -1568,5 +1568,20 @@ func Test_zero_line_search()
q!
endfunc
func Test_read_shellcmd()
CheckUnix
if executable('ls')
" There should be ls in the $PATH
call feedkeys(":r! l\<c-a>\<c-b>\"\<cr>", 'tx')
call assert_match('^"r! .*\<ls\>', @:)
endif
if executable('rm')
call feedkeys(":r! ++enc=utf-8 r\<c-a>\<c-b>\"\<cr>", 'tx')
call assert_notmatch('^"r!.*\<runtest.vim\>', @:)
call assert_match('^"r!.*\<rm\>', @:)
endif
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -1093,4 +1093,29 @@ func Test_patchexpr()
%bwipe!
endfunc
func Test_diff_rnu()
CheckScreendump
let content =<< trim END
call setline(1, ['a', 'a', 'a', 'y', 'b', 'b', 'b', 'b', 'b'])
vnew
call setline(1, ['a', 'a', 'a', 'x', 'x', 'x', 'b', 'b', 'b', 'b', 'b'])
windo diffthis
setlocal number rnu foldcolumn=0
END
call writefile(content, 'Xtest_diff_rnu')
let buf = RunVimInTerminal('-S Xtest_diff_rnu', {})
call VerifyScreenDump(buf, 'Test_diff_rnu_01', {})
call term_sendkeys(buf, "j")
call VerifyScreenDump(buf, 'Test_diff_rnu_02', {})
call term_sendkeys(buf, "j")
call VerifyScreenDump(buf, 'Test_diff_rnu_03', {})
" clean up
call StopVimInTerminal(buf)
call delete('Xtest_diff_rnu')
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -166,6 +166,17 @@ func Test_ex_mode_errors()
endtry
call assert_equal(1, caught_e565)
au! InsertCharPre
new
au CmdLineEnter * call ExEnterFunc()
func ExEnterFunc()
endfunc
call feedkeys("gQvi\r", 'xt')
au! CmdLineEnter
delfunc ExEnterFunc
quit
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -263,8 +263,52 @@ func Test_tagjump_etags()
ta foo
call assert_equal('void foo() {}', getline('.'))
" Test for including another tags file
call writefile([
\ "\x0c",
\ "Xmain.c,64",
\ "void foo() {}\x7ffoo\x011,0",
\ "\x0c",
\ "Xnonexisting,include",
\ "\x0c",
\ "Xtags2,include"
\ ], 'Xtags')
call writefile([
\ "\x0c",
\ "Xmain.c,64",
\ "int main(int argc, char **argv)\x7fmain\x012,14",
\ ], 'Xtags2')
tag main
call assert_equal(2, line('.'))
" corrupted tag line
call writefile([
\ "\x0c",
\ "Xmain.c,8",
\ "int main"
\ ], 'Xtags', 'b')
call assert_fails('tag foo', 'E426:')
" invalid line number
call writefile([
\ "\x0c",
\ "Xmain.c,64",
\ "void foo() {}\x7ffoo\x0abc,0",
\ ], 'Xtags')
call assert_fails('tag foo', 'E426:')
" invalid tag name
call writefile([
\ "\x0c",
\ "Xmain.c,64",
\ ";;;;\x7f1,0",
\ ], 'Xtags')
call assert_fails('tag foo', 'E426:')
call delete('Xtags')
call delete('Xtags2')
call delete('Xmain.c')
set tags&
bwipe!
endfunc
@@ -1268,4 +1312,29 @@ func Test_comment_search()
close!
endfunc
" Test for the 'taglength' option
func Test_tag_length()
set tags=Xtags
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "tame\tXfile1\t1;",
\ "tape\tXfile2\t1;"], 'Xtags')
call writefile(['tame'], 'Xfile1')
call writefile(['tape'], 'Xfile2')
" Jumping to the tag 'tape', should instead jump to 'tame'
new
set taglength=2
tag tape
call assert_equal('Xfile1', @%)
" Tag search should jump to the right tag
enew
tag /^tape$
call assert_equal('Xfile2', @%)
call delete('Xtags')
call delete('Xfile1')
call delete('Xfile2')
set tags& taglength&
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -311,6 +311,17 @@ func Test_sentence_with_cursor_on_delimiter()
normal! 17|yas
call assert_equal("A '([sentence.])' ", @")
" don't get stuck on a quote at the start of a sentence
%delete _
call setline(1, ['A sentence.', '"A sentence"?', 'A sentence!'])
normal gg))
call assert_equal(3, getcurpos()[1])
%delete _
call setline(1, ['A sentence.', "'A sentence'?", 'A sentence!'])
normal gg))
call assert_equal(3, getcurpos()[1])
%delete _
endfunc

View File

@@ -185,6 +185,42 @@ def Test_disassemble_store_member()
res)
enddef
def s:ListAssign()
let x: string
let y: string
let l: list<any>
[x, y; l] = g:stringlist
enddef
def Test_disassemble_list_assign()
let res = execute('disass s:ListAssign')
assert_match('<SNR>\d*_ListAssign\_s*' ..
'let x: string\_s*' ..
'\d PUSHS "\[NULL\]"\_s*' ..
'\d STORE $0\_s*' ..
'let y: string\_s*' ..
'\d PUSHS "\[NULL\]"\_s*' ..
'\d STORE $1\_s*' ..
'let l: list<any>\_s*' ..
'\d NEWLIST size 0\_s*' ..
'\d STORE $2\_s*' ..
'\[x, y; l\] = g:stringlist\_s*' ..
'\d LOADG g:stringlist\_s*' ..
'\d CHECKTYPE list stack\[-1\]\_s*' ..
'\d CHECKLEN >= 2\_s*' ..
'\d\+ ITEM 0\_s*' ..
'\d\+ CHECKTYPE string stack\[-1\]\_s*' ..
'\d\+ STORE $0\_s*' ..
'\d\+ ITEM 1\_s*' ..
'\d\+ CHECKTYPE string stack\[-1\]\_s*' ..
'\d\+ STORE $1\_s*' ..
'\d\+ SLICE 2\_s*' ..
'\d\+ STORE $2\_s*' ..
'\d\+ PUSHNR 0\_s*' ..
'\d\+ RETURN',
res)
enddef
def s:ScriptFuncUnlet()
g:somevar = "value"
unlet g:somevar
@@ -533,6 +569,30 @@ def Test_disassemble_const_expr()
assert_notmatch('JUMP', instr)
enddef
def ReturnInIf(): string
if g:cond
return "yes"
else
return "no"
endif
enddef
def Test_disassemble_return_in_if()
let instr = execute('disassemble ReturnInIf')
assert_match('ReturnInIf\_s*' ..
'if g:cond\_s*' ..
'0 LOADG g:cond\_s*' ..
'1 JUMP_IF_FALSE -> 4\_s*' ..
'return "yes"\_s*' ..
'2 PUSHS "yes"\_s*' ..
'3 RETURN\_s*' ..
'else\_s*' ..
' return "no"\_s*' ..
'4 PUSHS "no"\_s*' ..
'5 RETURN$',
instr)
enddef
def WithFunc()
let Funky1: func
let Funky2: func = function("len")

View File

@@ -31,6 +31,31 @@ def Test_return_something()
assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string')
enddef
def Test_missing_return()
CheckDefFailure(['def Missing(): number',
' if g:cond',
' echo "no return"',
' else',
' return 0',
' endif'
'enddef'], 'E1027:')
CheckDefFailure(['def Missing(): number',
' if g:cond',
' return 1',
' else',
' echo "no return"',
' endif'
'enddef'], 'E1027:')
CheckDefFailure(['def Missing(): number',
' if g:cond',
' return 1',
' else',
' return 2',
' endif'
' return 3'
'enddef'], 'E1095:')
enddef
let s:nothing = 0
def ReturnNothing()
s:nothing = 1
@@ -807,5 +832,10 @@ def Test_call_closure_not_compiled()
assert_equal('sometext', GetResult(g:Ref))
enddef
def Test_sort_return_type()
let res: list<number>
res = [1, 2, 3]->sort()
enddef
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

View File

@@ -127,6 +127,7 @@ def Test_assignment_list()
list2[-3] = 77
assert_equal([77, 88, 99], list2)
call CheckDefExecFailure(['let ll = [1, 2, 3]', 'll[-4] = 6'], 'E684:')
call CheckDefExecFailure(['let [v1, v2] = [1, 2]'], 'E1092:')
# type becomes list<any>
let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
@@ -1162,6 +1163,26 @@ def Test_if_const_expr_fails()
call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
enddef
def RunNested(i: number): number
let x: number = 0
if i % 2
if 1
" comment
else
" comment
endif
x += 1
else
x += 1000
endif
return x
enddef
def Test_nested_if()
assert_equal(1, RunNested(1))
assert_equal(1000, RunNested(2))
enddef
def Test_execute_cmd()
new
setline(1, 'default')
@@ -1900,6 +1921,20 @@ def Test_let_declaration()
unlet g:other_var
enddef
def Test_let_declaration_fails()
let lines =<< trim END
vim9script
const var: string
END
CheckScriptFailure(lines, 'E1021:')
lines =<< trim END
vim9script
let 9var: string
END
CheckScriptFailure(lines, 'E475:')
enddef
def Test_let_type_check()
let lines =<< trim END
vim9script
@@ -1913,6 +1948,12 @@ def Test_let_type_check()
let var:string
END
CheckScriptFailure(lines, 'E1069:')
lines =<< trim END
vim9script
let var: asdf
END
CheckScriptFailure(lines, 'E1010:')
enddef
def Test_forward_declaration()

View File

@@ -26,6 +26,7 @@ static int skip_chars(int, int);
findsent(int dir, long count)
{
pos_T pos, tpos;
pos_T prev_pos;
int c;
int (*func)(pos_T *);
int startlnum;
@@ -41,6 +42,8 @@ findsent(int dir, long count)
while (count--)
{
prev_pos = pos;
/*
* if on an empty line, skip up to a non-empty line
*/
@@ -133,6 +136,18 @@ found:
while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t'))
if (incl(&pos) == -1)
break;
if (EQUAL_POS(prev_pos, pos))
{
// didn't actually move, advance one character and try again
if ((*func)(&pos) == -1)
{
if (count)
return FAIL;
break;
}
++count;
}
}
setpcmark();

View File

@@ -754,6 +754,32 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1010,
/**/
1009,
/**/
1008,
/**/
1007,
/**/
1006,
/**/
1005,
/**/
1004,
/**/
1003,
/**/
1002,
/**/
1001,
/**/
1000,
/**/
999,
/**/
998,
/**/
997,
/**/

View File

@@ -23,6 +23,13 @@
#define DEFINE_VIM9_GLOBALS
#include "vim9.h"
// values for ctx_skip
typedef enum {
SKIP_NOT, // condition is a constant, produce code
SKIP_YES, // condition is a constant, do NOT produce code
SKIP_UNKNONW // condition is not a constant, produce code
} skip_T;
/*
* Chain of jump instructions where the end label needs to be set.
*/
@@ -36,6 +43,8 @@ struct endlabel_S {
* info specific for the scope of :if / elseif / else
*/
typedef struct {
int is_seen_else;
int is_had_return; // every block ends in :return
int is_if_label; // instruction idx at IF or ELSEIF
endlabel_T *is_end_label; // instructions to set end label
} ifscope_T;
@@ -83,6 +92,7 @@ struct scope_S {
scope_T *se_outer; // scope containing this one
scopetype_T se_type;
int se_local_count; // ctx_locals.ga_len before scope
skip_T se_skip_save; // ctx_skip before the block
union {
ifscope_T se_if;
whilescope_T se_while;
@@ -121,9 +131,9 @@ struct cctx_S {
garray_T ctx_imports; // imported items
int ctx_skip; // when TRUE skip commands, when FALSE skip
// commands after "else"
skip_T ctx_skip;
scope_T *ctx_scope; // current scope, NULL at toplevel
int ctx_had_return; // last seen statement was "return"
cctx_T *ctx_outer; // outer scope for lambda or nested
// function
@@ -545,8 +555,8 @@ check_type(type_T *expected, type_T *actual, int give_msg)
/////////////////////////////////////////////////////////////////////
// Following generate_ functions expect the caller to call ga_grow().
#define RETURN_NULL_IF_SKIP(cctx) if (cctx->ctx_skip == TRUE) return NULL
#define RETURN_OK_IF_SKIP(cctx) if (cctx->ctx_skip == TRUE) return OK
#define RETURN_NULL_IF_SKIP(cctx) if (cctx->ctx_skip == SKIP_YES) return NULL
#define RETURN_OK_IF_SKIP(cctx) if (cctx->ctx_skip == SKIP_YES) return OK
/*
* Generate an instruction without arguments.
@@ -2493,7 +2503,7 @@ generate_ppconst(cctx_T *cctx, ppconst_T *ppconst)
int ret = OK;
int save_skip = cctx->ctx_skip;
cctx->ctx_skip = FALSE;
cctx->ctx_skip = SKIP_NOT;
for (i = 0; i < ppconst->pp_used; ++i)
if (generate_tv_PUSH(cctx, &ppconst->pp_tv[i]) == FAIL)
ret = FAIL;
@@ -3851,7 +3861,7 @@ compile_expr7(
}
start_leader = end_leader; // don't apply again below
if (cctx->ctx_skip == TRUE)
if (cctx->ctx_skip == SKIP_YES)
clear_tv(rettv);
else
// A constant expression can possibly be handled compile time,
@@ -4347,7 +4357,8 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
const_value = tv2bool(&ppconst->pp_tv[ppconst_used]);
clear_tv(&ppconst->pp_tv[ppconst_used]);
--ppconst->pp_used;
cctx->ctx_skip = save_skip == TRUE || !const_value;
cctx->ctx_skip = save_skip == SKIP_YES || !const_value
? SKIP_YES : SKIP_NOT;
}
else
{
@@ -4393,7 +4404,8 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
// evaluate the third expression
if (has_const_expr)
cctx->ctx_skip = save_skip == TRUE || const_value;
cctx->ctx_skip = save_skip == SKIP_YES || const_value
? SKIP_YES : SKIP_NOT;
*arg = skipwhite(p + 1);
if (may_get_next_line(p + 1, arg, cctx) == FAIL)
return FAIL;
@@ -4521,7 +4533,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
eap->arg = name_end;
eap->getline = exarg_getline;
eap->cookie = cctx;
eap->skip = cctx->ctx_skip == TRUE;
eap->skip = cctx->ctx_skip == SKIP_YES;
eap->forceit = FALSE;
ufunc = def_function(eap, name);
@@ -4728,7 +4740,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
return NULL;
end = p;
if (cctx->ctx_skip != TRUE)
if (cctx->ctx_skip != SKIP_YES)
{
type_T *stacktype;
@@ -4787,7 +4799,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
if (!heredoc)
type = &t_any;
if (cctx->ctx_skip != TRUE)
if (cctx->ctx_skip != SKIP_YES)
{
if (*var_start == '&')
{
@@ -5013,7 +5025,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
goto theend;
}
if (lvar == NULL && dest == dest_local && cctx->ctx_skip != TRUE)
if (lvar == NULL && dest == dest_local && cctx->ctx_skip != SKIP_YES)
{
if (oplen > 1 && !heredoc)
{
@@ -5067,8 +5079,19 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
if (!heredoc)
{
if (oplen > 0)
if (cctx->ctx_skip == SKIP_YES)
{
if (oplen > 0 && var_count == 0)
{
// skip over the "=" and the expression
p = skipwhite(op + oplen);
compile_expr0(&p, cctx);
}
}
else if (oplen > 0)
{
type_T *stacktype;
// For "var = expr" evaluate the expression.
if (var_count == 0)
{
@@ -5113,52 +5136,47 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
return FAIL;
}
if (cctx->ctx_skip != TRUE)
stacktype = stack->ga_len == 0 ? &t_void
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (lvar != NULL && (is_decl || !has_type))
{
type_T *stacktype;
stacktype = stack->ga_len == 0 ? &t_void
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (lvar != NULL && (is_decl || !has_type))
if (new_local && !has_type)
{
if (new_local && !has_type)
if (stacktype->tt_type == VAR_VOID)
{
if (stacktype->tt_type == VAR_VOID)
{
emsg(_(e_cannot_use_void));
goto theend;
}
else
{
// An empty list or dict has a &t_void member,
// for a variable that implies &t_any.
if (stacktype == &t_list_empty)
lvar->lv_type = &t_list_any;
else if (stacktype == &t_dict_empty)
lvar->lv_type = &t_dict_any;
else
lvar->lv_type = stacktype;
}
emsg(_(e_cannot_use_void));
goto theend;
}
else
{
type_T *use_type = lvar->lv_type;
if (has_index)
{
use_type = use_type->tt_member;
if (use_type == NULL)
use_type = &t_void;
}
if (need_type(stacktype, use_type, -1, cctx)
== FAIL)
goto theend;
// An empty list or dict has a &t_void member,
// for a variable that implies &t_any.
if (stacktype == &t_list_empty)
lvar->lv_type = &t_list_any;
else if (stacktype == &t_dict_empty)
lvar->lv_type = &t_dict_any;
else
lvar->lv_type = stacktype;
}
}
else if (*p != '=' && need_type(stacktype, member_type, -1,
cctx) == FAIL)
goto theend;
else
{
type_T *use_type = lvar->lv_type;
if (has_index)
{
use_type = use_type->tt_member;
if (use_type == NULL)
use_type = &t_void;
}
if (need_type(stacktype, use_type, -1, cctx)
== FAIL)
goto theend;
}
}
else if (*p != '=' && need_type(stacktype, member_type, -1,
cctx) == FAIL)
goto theend;
}
else if (cmdidx == CMD_const)
{
@@ -5220,6 +5238,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
end = p;
}
// no need to parse more when skipping
if (cctx->ctx_skip == SKIP_YES)
break;
if (oplen > 0 && *op != '=')
{
type_T *expected = &t_number;
@@ -5646,6 +5668,7 @@ compile_if(char_u *arg, cctx_T *cctx)
garray_T *instr = &cctx->ctx_instr;
int instr_count = instr->ga_len;
scope_T *scope;
skip_T skip_save = cctx->ctx_skip;
ppconst_T ppconst;
CLEAR_FIELD(ppconst);
@@ -5654,17 +5677,18 @@ compile_if(char_u *arg, cctx_T *cctx)
clear_ppconst(&ppconst);
return NULL;
}
if (instr->ga_len == instr_count && ppconst.pp_used == 1)
if (cctx->ctx_skip == SKIP_YES)
clear_ppconst(&ppconst);
else if (instr->ga_len == instr_count && ppconst.pp_used == 1)
{
// The expression results in a constant.
// TODO: how about nesting?
cctx->ctx_skip = tv2bool(&ppconst.pp_tv[0]) ? FALSE : TRUE;
cctx->ctx_skip = tv2bool(&ppconst.pp_tv[0]) ? SKIP_NOT : SKIP_YES;
clear_ppconst(&ppconst);
}
else
{
// Not a constant, generate instructions for the expression.
cctx->ctx_skip = MAYBE;
cctx->ctx_skip = SKIP_UNKNONW;
if (generate_ppconst(cctx, &ppconst) == FAIL)
return NULL;
}
@@ -5672,8 +5696,11 @@ compile_if(char_u *arg, cctx_T *cctx)
scope = new_scope(cctx, IF_SCOPE);
if (scope == NULL)
return NULL;
scope->se_skip_save = skip_save;
// "is_had_return" will be reset if any block does not end in :return
scope->se_u.se_if.is_had_return = TRUE;
if (cctx->ctx_skip == MAYBE)
if (cctx->ctx_skip == SKIP_UNKNONW)
{
// "where" is set when ":elseif", "else" or ":endif" is found
scope->se_u.se_if.is_if_label = instr->ga_len;
@@ -5701,8 +5728,10 @@ compile_elseif(char_u *arg, cctx_T *cctx)
return NULL;
}
unwind_locals(cctx, scope->se_local_count);
if (!cctx->ctx_had_return)
scope->se_u.se_if.is_had_return = FALSE;
if (cctx->ctx_skip == MAYBE)
if (cctx->ctx_skip == SKIP_UNKNONW)
{
if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
JUMP_ALWAYS, cctx) == FAIL)
@@ -5719,18 +5748,20 @@ compile_elseif(char_u *arg, cctx_T *cctx)
clear_ppconst(&ppconst);
return NULL;
}
if (instr->ga_len == instr_count && ppconst.pp_used == 1)
if (scope->se_skip_save == SKIP_YES)
clear_ppconst(&ppconst);
else if (instr->ga_len == instr_count && ppconst.pp_used == 1)
{
// The expression results in a constant.
// TODO: how about nesting?
cctx->ctx_skip = tv2bool(&ppconst.pp_tv[0]) ? FALSE : TRUE;
cctx->ctx_skip = tv2bool(&ppconst.pp_tv[0]) ? SKIP_NOT : SKIP_YES;
clear_ppconst(&ppconst);
scope->se_u.se_if.is_if_label = -1;
}
else
{
// Not a constant, generate instructions for the expression.
cctx->ctx_skip = MAYBE;
cctx->ctx_skip = SKIP_UNKNONW;
if (generate_ppconst(cctx, &ppconst) == FAIL)
return NULL;
@@ -5756,28 +5787,35 @@ compile_else(char_u *arg, cctx_T *cctx)
return NULL;
}
unwind_locals(cctx, scope->se_local_count);
if (!cctx->ctx_had_return)
scope->se_u.se_if.is_had_return = FALSE;
scope->se_u.se_if.is_seen_else = TRUE;
// jump from previous block to the end, unless the else block is empty
if (cctx->ctx_skip == MAYBE)
if (scope->se_skip_save != SKIP_YES)
{
if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
JUMP_ALWAYS, cctx) == FAIL)
return NULL;
}
if (cctx->ctx_skip == MAYBE)
{
if (scope->se_u.se_if.is_if_label >= 0)
// jump from previous block to the end, unless the else block is empty
if (cctx->ctx_skip == SKIP_UNKNONW)
{
// previous "if" or "elseif" jumps here
isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
isn->isn_arg.jump.jump_where = instr->ga_len;
scope->se_u.se_if.is_if_label = -1;
if (!cctx->ctx_had_return
&& compile_jump_to_end(&scope->se_u.se_if.is_end_label,
JUMP_ALWAYS, cctx) == FAIL)
return NULL;
}
}
if (cctx->ctx_skip != MAYBE)
cctx->ctx_skip = !cctx->ctx_skip;
if (cctx->ctx_skip == SKIP_UNKNONW)
{
if (scope->se_u.se_if.is_if_label >= 0)
{
// previous "if" or "elseif" jumps here
isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
isn->isn_arg.jump.jump_where = instr->ga_len;
scope->se_u.se_if.is_if_label = -1;
}
}
if (cctx->ctx_skip != SKIP_UNKNONW)
cctx->ctx_skip = cctx->ctx_skip == SKIP_YES ? SKIP_NOT : SKIP_YES;
}
return p;
}
@@ -5797,6 +5835,8 @@ compile_endif(char_u *arg, cctx_T *cctx)
}
ifscope = &scope->se_u.se_if;
unwind_locals(cctx, scope->se_local_count);
if (!cctx->ctx_had_return)
ifscope->is_had_return = FALSE;
if (scope->se_u.se_if.is_if_label >= 0)
{
@@ -5806,7 +5846,11 @@ compile_endif(char_u *arg, cctx_T *cctx)
}
// Fill in the "end" label in jumps at the end of the blocks.
compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
cctx->ctx_skip = FALSE;
cctx->ctx_skip = scope->se_skip_save;
// If all the blocks end in :return and there is an :else then the
// had_return flag is set.
cctx->ctx_had_return = ifscope->is_had_return && ifscope->is_seen_else;
drop_scope(cctx);
return arg;
@@ -6405,7 +6449,7 @@ compile_exec(char_u *line, exarg_T *eap, cctx_T *cctx)
char_u *p;
int has_expr = FALSE;
if (cctx->ctx_skip == TRUE)
if (cctx->ctx_skip == SKIP_YES)
goto theend;
if (eap->cmdidx >= 0 && eap->cmdidx < CMD_SIZE)
@@ -6509,7 +6553,6 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
char_u *line = NULL;
char_u *p;
char *errormsg = NULL; // error message
int had_return = FALSE;
cctx_T cctx;
garray_T *instr;
int called_emsg_before = called_emsg;
@@ -6629,7 +6672,6 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
}
emsg_before = called_emsg;
had_return = FALSE;
CLEAR_FIELD(ea);
ea.cmdlinep = &line;
ea.cmd = skipwhite(line);
@@ -6770,7 +6812,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
{
if (cctx.ctx_skip == TRUE)
if (cctx.ctx_skip == SKIP_YES)
{
line += STRLEN(line);
continue;
@@ -6795,7 +6837,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
p = skipwhite(p);
if (cctx.ctx_skip == TRUE
if (cctx.ctx_skip == SKIP_YES
&& ea.cmdidx != CMD_elseif
&& ea.cmdidx != CMD_else
&& ea.cmdidx != CMD_endif)
@@ -6804,6 +6846,22 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
continue;
}
if (ea.cmdidx != CMD_elseif
&& ea.cmdidx != CMD_else
&& ea.cmdidx != CMD_endif
&& ea.cmdidx != CMD_endfor
&& ea.cmdidx != CMD_endwhile
&& ea.cmdidx != CMD_catch
&& ea.cmdidx != CMD_finally
&& ea.cmdidx != CMD_endtry)
{
if (cctx.ctx_had_return)
{
emsg(_("E1095: Unreachable code after :return"));
goto erret;
}
}
switch (ea.cmdidx)
{
case CMD_def:
@@ -6817,7 +6875,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
case CMD_return:
line = compile_return(p, set_return_type, &cctx);
had_return = TRUE;
cctx.ctx_had_return = TRUE;
break;
case CMD_let:
@@ -6842,9 +6900,11 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
break;
case CMD_elseif:
line = compile_elseif(p, &cctx);
cctx.ctx_had_return = FALSE;
break;
case CMD_else:
line = compile_else(p, &cctx);
cctx.ctx_had_return = FALSE;
break;
case CMD_endif:
line = compile_endif(p, &cctx);
@@ -6855,6 +6915,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
break;
case CMD_endwhile:
line = compile_endwhile(p, &cctx);
cctx.ctx_had_return = FALSE;
break;
case CMD_for:
@@ -6862,6 +6923,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
break;
case CMD_endfor:
line = compile_endfor(p, &cctx);
cctx.ctx_had_return = FALSE;
break;
case CMD_continue:
line = compile_continue(p, &cctx);
@@ -6875,12 +6937,15 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
break;
case CMD_catch:
line = compile_catch(p, &cctx);
cctx.ctx_had_return = FALSE;
break;
case CMD_finally:
line = compile_finally(p, &cctx);
cctx.ctx_had_return = FALSE;
break;
case CMD_endtry:
line = compile_endtry(p, &cctx);
cctx.ctx_had_return = FALSE;
break;
case CMD_throw:
line = compile_throw(p, &cctx);
@@ -6925,7 +6990,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
goto erret;
}
if (!had_return)
if (!cctx.ctx_had_return)
{
if (ufunc->uf_ret_type->tt_type != VAR_VOID)
{

View File

@@ -2119,12 +2119,8 @@ call_def_function(
list_T *list;
int count = iptr->isn_arg.number;
// type will have been checked to be a list
tv = STACK_TV_BOT(-1);
if (tv->v_type != VAR_LIST)
{
emsg(_(e_listreq));
goto failed;
}
list = tv->vval.v_list;
// no error for short list, expect it to be checked earlier