diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-04-05 17:08:17 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-04-05 17:08:17 +0200 |
commit | 5deeb3f1f9db4eabd36e99cbf857fe376eb37e10 (patch) | |
tree | 929f788bcba4325b1bd8141182e433c47d53666f /src | |
parent | d7ffc0ba8ccb039dd19b255368302d9bfe0e010b (diff) |
patch 8.2.0512: Vim9: no optional arguments in func typev8.2.0512
Problem: Vim9: no optional arguments in func type.
Solution: Check for question mark after type. Find function reference
without function().
Diffstat (limited to 'src')
-rw-r--r-- | src/globals.h | 66 | ||||
-rw-r--r-- | src/structs.h | 10 | ||||
-rw-r--r-- | src/testdir/Make_all.mak | 2 | ||||
-rw-r--r-- | src/testdir/test_vim9_disassemble.vim | 14 | ||||
-rw-r--r-- | src/testdir/test_vim9_expr.vim | 4 | ||||
-rw-r--r-- | src/testdir/test_vim9_func.vim | 400 | ||||
-rw-r--r-- | src/testdir/test_vim9_script.vim | 356 | ||||
-rw-r--r-- | src/userfunc.c | 6 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim.h | 2 | ||||
-rw-r--r-- | src/vim9.h | 6 | ||||
-rw-r--r-- | src/vim9compile.c | 316 | ||||
-rw-r--r-- | src/vim9execute.c | 8 |
13 files changed, 733 insertions, 459 deletions
diff --git a/src/globals.h b/src/globals.h index 59f22d1af8..1a6a0d8d30 100644 --- a/src/globals.h +++ b/src/globals.h @@ -379,39 +379,39 @@ EXTERN sctx_T current_sctx INIT4(0, 0, 0, 0); // Commonly used types. -EXTERN type_T t_any INIT5(VAR_UNKNOWN, 0, 0, NULL, NULL); -EXTERN type_T t_void INIT5(VAR_VOID, 0, 0, NULL, NULL); -EXTERN type_T t_bool INIT5(VAR_BOOL, 0, 0, NULL, NULL); -EXTERN type_T t_special INIT5(VAR_SPECIAL, 0, 0, NULL, NULL); -EXTERN type_T t_number INIT5(VAR_NUMBER, 0, 0, NULL, NULL); -EXTERN type_T t_float INIT5(VAR_FLOAT, 0, 0, NULL, NULL); -EXTERN type_T t_string INIT5(VAR_STRING, 0, 0, NULL, NULL); -EXTERN type_T t_blob INIT5(VAR_BLOB, 0, 0, NULL, NULL); -EXTERN type_T t_job INIT5(VAR_JOB, 0, 0, NULL, NULL); -EXTERN type_T t_channel INIT5(VAR_CHANNEL, 0, 0, NULL, NULL); - -EXTERN type_T t_func_void INIT5(VAR_FUNC, -1, 0, &t_void, NULL); -EXTERN type_T t_func_any INIT5(VAR_FUNC, -1, 0, &t_any, NULL); -EXTERN type_T t_func_number INIT5(VAR_FUNC, -1, 0, &t_number, NULL); -EXTERN type_T t_func_string INIT5(VAR_FUNC, -1, 0, &t_string, NULL); -EXTERN type_T t_func_0_void INIT5(VAR_FUNC, 0, 0, &t_void, NULL); -EXTERN type_T t_func_0_any INIT5(VAR_FUNC, 0, 0, &t_any, NULL); -EXTERN type_T t_func_0_number INIT5(VAR_FUNC, 0, 0, &t_number, NULL); -EXTERN type_T t_func_0_string INIT5(VAR_FUNC, 0, 0, &t_string, NULL); - -EXTERN type_T t_list_any INIT5(VAR_LIST, 0, 0, &t_any, NULL); -EXTERN type_T t_dict_any INIT5(VAR_DICT, 0, 0, &t_any, NULL); -EXTERN type_T t_list_empty INIT5(VAR_LIST, 0, 0, &t_void, NULL); -EXTERN type_T t_dict_empty INIT5(VAR_DICT, 0, 0, &t_void, NULL); - -EXTERN type_T t_list_bool INIT5(VAR_LIST, 0, 0, &t_bool, NULL); -EXTERN type_T t_list_number INIT5(VAR_LIST, 0, 0, &t_number, NULL); -EXTERN type_T t_list_string INIT5(VAR_LIST, 0, 0, &t_string, NULL); -EXTERN type_T t_list_dict_any INIT5(VAR_LIST, 0, 0, &t_dict_any, NULL); - -EXTERN type_T t_dict_bool INIT5(VAR_DICT, 0, 0, &t_bool, NULL); -EXTERN type_T t_dict_number INIT5(VAR_DICT, 0, 0, &t_number, NULL); -EXTERN type_T t_dict_string INIT5(VAR_DICT, 0, 0, &t_string, NULL); +EXTERN type_T t_any INIT6(VAR_UNKNOWN, 0, 0, 0, NULL, NULL); +EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, 0, NULL, NULL); +EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, 0, NULL, NULL); +EXTERN type_T t_special INIT6(VAR_SPECIAL, 0, 0, 0, NULL, NULL); +EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, 0, NULL, NULL); +EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, 0, NULL, NULL); +EXTERN type_T t_string INIT6(VAR_STRING, 0, 0, 0, NULL, NULL); +EXTERN type_T t_blob INIT6(VAR_BLOB, 0, 0, 0, NULL, NULL); +EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, 0, NULL, NULL); +EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, 0, NULL, NULL); + +EXTERN type_T t_func_void INIT6(VAR_FUNC, -1, 0, 0, &t_void, NULL); +EXTERN type_T t_func_any INIT6(VAR_FUNC, -1, 0, 0, &t_any, NULL); +EXTERN type_T t_func_number INIT6(VAR_FUNC, -1, 0, 0, &t_number, NULL); +EXTERN type_T t_func_string INIT6(VAR_FUNC, -1, 0, 0, &t_string, NULL); +EXTERN type_T t_func_0_void INIT6(VAR_FUNC, 0, 0, 0, &t_void, NULL); +EXTERN type_T t_func_0_any INIT6(VAR_FUNC, 0, 0, 0, &t_any, NULL); +EXTERN type_T t_func_0_number INIT6(VAR_FUNC, 0, 0, 0, &t_number, NULL); +EXTERN type_T t_func_0_string INIT6(VAR_FUNC, 0, 0, 0, &t_string, NULL); + +EXTERN type_T t_list_any INIT6(VAR_LIST, 0, 0, 0, &t_any, NULL); +EXTERN type_T t_dict_any INIT6(VAR_DICT, 0, 0, 0, &t_any, NULL); +EXTERN type_T t_list_empty INIT6(VAR_LIST, 0, 0, 0, &t_void, NULL); +EXTERN type_T t_dict_empty INIT6(VAR_DICT, 0, 0, 0, &t_void, NULL); + +EXTERN type_T t_list_bool INIT6(VAR_LIST, 0, 0, 0, &t_bool, NULL); +EXTERN type_T t_list_number INIT6(VAR_LIST, 0, 0, 0, &t_number, NULL); +EXTERN type_T t_list_string INIT6(VAR_LIST, 0, 0, 0, &t_string, NULL); +EXTERN type_T t_list_dict_any INIT6(VAR_LIST, 0, 0, 0, &t_dict_any, NULL); + +EXTERN type_T t_dict_bool INIT6(VAR_DICT, 0, 0, 0, &t_bool, NULL); +EXTERN type_T t_dict_number INIT6(VAR_DICT, 0, 0, 0, &t_number, NULL); +EXTERN type_T t_dict_string INIT6(VAR_DICT, 0, 0, 0, &t_string, NULL); #endif diff --git a/src/structs.h b/src/structs.h index efc74da175..4a5128171b 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1341,10 +1341,11 @@ typedef enum typedef struct type_S type_T; struct type_S { vartype_T tt_type; - short tt_argcount; // for func, partial, -1 for unknown - short tt_flags; // TTFLAG_ values + char tt_argcount; // for func, -1 for unknown + char tt_min_argcount; // number of non-optional arguments + char tt_flags; // TTFLAG_ values type_T *tt_member; // for list, dict, func return type - type_T **tt_args; // func arguments, allocated + type_T **tt_args; // func argument types, allocated }; #define TTFLAG_VARARGS 1 // func args ends with "..." @@ -1520,7 +1521,7 @@ typedef struct int uf_calls; // nr of active calls int uf_cleared; // func_clear() was already called int uf_dfunc_idx; // >= 0 for :def function only - garray_T uf_args; // arguments + garray_T uf_args; // arguments, including optional arguments garray_T uf_def_args; // default argument expressions // for :def (for :function uf_ret_type is NULL) @@ -1531,6 +1532,7 @@ typedef struct // uf_def_args; length: uf_def_args.ga_len + 1 char_u *uf_va_name; // name from "...name" or NULL type_T *uf_va_type; // type from "...name: type" or NULL + type_T *uf_func_type; // type of the function, &t_func_any if unknown garray_T uf_lines; // function lines # ifdef FEAT_PROFILE diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index d0bfe1c7c7..1a47cfcda8 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -274,6 +274,7 @@ NEW_TESTS = \ test_vartabs \ test_vim9_disassemble \ test_vim9_expr \ + test_vim9_func \ test_vim9_script \ test_viminfo \ test_vimscript \ @@ -483,6 +484,7 @@ NEW_TESTS_RES = \ test_vartabs.res \ test_vim9_disassemble.res \ test_vim9_expr.res \ + test_vim9_func.res \ test_vim9_script.res \ test_viminfo.res \ test_vimscript.res \ diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index e71782b970..0299df5f5b 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -87,8 +87,10 @@ enddef def Test_disassemble_store() let res = execute('disass s:ScriptFuncStore') assert_match('<SNR>\d*_ScriptFuncStore.*' + \ .. 'let localnr = 1.*' \ .. 'localnr = 2.*' \ .. ' STORE 2 in $0.*' + \ .. 'let localstr = ''abc''.*' \ .. 'localstr = ''xyz''.*' \ .. ' STORE $1.*' \ .. 'v:char = ''abc''.*' @@ -360,22 +362,22 @@ def Test_disassemble_const_expr() enddef def WithFunc() - let funky1: func - let funky2: func = function("len") - let party2: func = funcref("UserFunc") + let Funky1: func + let Funky2: func = function("len") + let Party2: func = funcref("UserFunc") enddef def Test_disassemble_function() let instr = execute('disassemble WithFunc') assert_match('WithFunc.*' - \ .. 'let funky1: func.*' + \ .. 'let Funky1: func.*' \ .. '0 PUSHFUNC "\[none]".*' \ .. '1 STORE $0.*' - \ .. 'let funky2: func = function("len").*' + \ .. 'let Funky2: func = function("len").*' \ .. '2 PUSHS "len".*' \ .. '3 BCALL function(argc 1).*' \ .. '4 STORE $1.*' - \ .. 'let party2: func = funcref("UserFunc").*' + \ .. 'let Party2: func = funcref("UserFunc").*' \ .. '\d PUSHS "UserFunc".*' \ .. '\d BCALL funcref(argc 1).*' \ .. '\d STORE $2.*' diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index d9c20acb18..f11fc83893 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -460,8 +460,8 @@ func Test_expr4_fails() call CheckDefFailureMult(['let j: job', 'let chan: channel', 'let r = j == chan'], 'Cannot compare job with channel') call CheckDefFailureMult(['let j: job', 'let x: list<any>', 'let r = j == x'], 'Cannot compare job with list') - call CheckDefFailureMult(['let j: job', 'let x: func', 'let r = j == x'], 'Cannot compare job with func') - call CheckDefFailureMult(['let j: job', 'let x: func', 'let r = j == x'], 'Cannot compare job with func') + call CheckDefFailureMult(['let j: job', 'let Xx: func', 'let r = j == Xx'], 'Cannot compare job with func') + call CheckDefFailureMult(['let j: job', 'let Xx: func', 'let r = j == Xx'], 'Cannot compare job with func') endfunc " test addition, subtraction, concatenation diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim new file mode 100644 index 0000000000..6f61254f86 --- /dev/null +++ b/src/testdir/test_vim9_func.vim @@ -0,0 +1,400 @@ +" Test various aspects of the Vim9 script language. + +source check.vim +source view_util.vim + +" Check that "lines" inside ":def" results in an "error" message. +func CheckDefFailure(lines, error) + call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef') + call assert_fails('so Xdef', a:error, a:lines) + call delete('Xdef') +endfunc + +func CheckScriptFailure(lines, error) + call writefile(a:lines, 'Xdef') + call assert_fails('so Xdef', a:error, a:lines) + call delete('Xdef') +endfunc + +func Test_def_basic() + def SomeFunc(): string + return 'yes' + enddef + call assert_equal('yes', SomeFunc()) +endfunc + +def ReturnString(): string + return 'string' +enddef + +def ReturnNumber(): number + return 123 +enddef + +let g:notNumber = 'string' + +def ReturnGlobal(): number + return g:notNumber +enddef + +def Test_return_something() + assert_equal('string', ReturnString()) + assert_equal(123, ReturnNumber()) + assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string') +enddef + +let s:nothing = 0 +def ReturnNothing() + s:nothing = 1 + if true + return + endif + s:nothing = 2 +enddef + +def Test_return_nothing() + ReturnNothing() + assert_equal(1, s:nothing) +enddef + +func Increment() + let g:counter += 1 +endfunc + +def Test_call_ufunc_count() + g:counter = 1 + Increment() + Increment() + Increment() + " works with and without :call + assert_equal(4, g:counter) + call assert_equal(4, g:counter) + unlet g:counter +enddef + +def MyVarargs(arg: string, ...rest: list<string>): string + let res = arg + for s in rest + res ..= ',' .. s + endfor + return res +enddef + +def Test_call_varargs() + assert_equal('one', MyVarargs('one')) + assert_equal('one,two', MyVarargs('one', 'two')) + assert_equal('one,two,three', MyVarargs('one', 'two', 'three')) +enddef + +def MyDefaultArgs(name = 'string'): string + return name +enddef + +def Test_call_default_args() + assert_equal('string', MyDefaultArgs()) + assert_equal('one', MyDefaultArgs('one')) + assert_fails('call MyDefaultArgs("one", "two")', 'E118:') + + call CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:') +enddef + +func Test_call_default_args_from_func() + call assert_equal('string', MyDefaultArgs()) + call assert_equal('one', MyDefaultArgs('one')) + call assert_fails('call MyDefaultArgs("one", "two")', 'E118:') +endfunc + +func TakesOneArg(arg) + echo a:arg +endfunc + +def Test_call_wrong_args() + call CheckDefFailure(['TakesOneArg()'], 'E119:') + call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:') + call CheckDefFailure(['bufnr(xxx)'], 'E1001:') +enddef + +" Default arg and varargs +def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string + let res = one .. ',' .. two + for s in rest + res ..= ',' .. s + endfor + return res +enddef + +def Test_call_def_varargs() + call assert_fails('call MyDefVarargs()', 'E119:') + assert_equal('one,foo', MyDefVarargs('one')) + assert_equal('one,two', MyDefVarargs('one', 'two')) + assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three')) +enddef + +def Test_using_var_as_arg() + call writefile(['def Func(x: number)', 'let x = 234', 'enddef'], 'Xdef') + call assert_fails('so Xdef', 'E1006:') + call delete('Xdef') +enddef + +def Test_call_func_defined_later() + call assert_equal('one', DefinedLater('one')) + call assert_fails('call NotDefined("one")', 'E117:') +enddef + +func DefinedLater(arg) + return a:arg +endfunc + +def FuncWithForwardCall() + return DefinedEvenLater("yes") +enddef + +def DefinedEvenLater(arg: string): string + return arg +enddef + +def Test_error_in_nested_function() + " Error in called function requires unwinding the call stack. + assert_fails('call FuncWithForwardCall()', 'E1029') +enddef + +def Test_return_type_wrong() + CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string') + CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number') + CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string') + CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string') + + CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:') + + CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:') + CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:') +enddef + +def Test_arg_type_wrong() + CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>') +enddef + +def Test_vim9script_call() + let lines =<< trim END + vim9script + let var = '' + def MyFunc(arg: string) + var = arg + enddef + MyFunc('foobar') + assert_equal('foobar', var) + + let str = 'barfoo' + str->MyFunc() + assert_equal('barfoo', var) + + let g:value = 'value' + g:value->MyFunc() + assert_equal('value', var) + + let listvar = [] + def ListFunc(arg: list<number>) + listvar = arg + enddef + [1, 2, 3]->ListFunc() + assert_equal([1, 2, 3], listvar) + + let dictvar = {} + def DictFunc(arg: dict<number>) + dictvar = arg + enddef + {'a': 1, 'b': 2}->DictFunc() + assert_equal(#{a: 1, b: 2}, dictvar) + def CompiledDict() + {'a': 3, 'b': 4}->DictFunc() + enddef + CompiledDict() + assert_equal(#{a: 3, b: 4}, dictvar) + + #{a: 3, b: 4}->DictFunc() + assert_equal(#{a: 3, b: 4}, dictvar) + + ('text')->MyFunc() + assert_equal('text', var) + ("some")->MyFunc() + assert_equal('some', var) + END + writefile(lines, 'Xcall.vim') + source Xcall.vim + delete('Xcall.vim') +enddef + +def Test_vim9script_call_fail_decl() + let lines =<< trim END + vim9script + let var = '' + def MyFunc(arg: string) + let var = 123 + enddef + END + writefile(lines, 'Xcall_decl.vim') + assert_fails('source Xcall_decl.vim', 'E1054:') + delete('Xcall_decl.vim') +enddef + +def Test_vim9script_call_fail_const() + let lines =<< trim END + vim9script + const var = '' + def MyFunc(arg: string) + var = 'asdf' + enddef + END + writefile(lines, 'Xcall_const.vim') + assert_fails('source Xcall_const.vim', 'E46:') + delete('Xcall_const.vim') +enddef + +" Test that inside :function a Python function can be defined, :def is not +" recognized. +func Test_function_python() + CheckFeature python3 + let py = 'python3' + execute py "<< EOF" +def do_something(): + return 1 +EOF +endfunc + +def Test_delfunc() + let lines =<< trim END + vim9script + def GoneSoon() + echo 'hello' + enddef + + def CallGoneSoon() + GoneSoon() + enddef + + delfunc GoneSoon + CallGoneSoon() + END + writefile(lines, 'XToDelFunc') + assert_fails('so XToDelFunc', 'E933') + assert_fails('so XToDelFunc', 'E933') + + delete('XToDelFunc') +enddef + +def Test_redef_failure() + call writefile(['def Func0(): string', 'return "Func0"', 'enddef'], 'Xdef') + so Xdef + call writefile(['def Func1(): string', 'return "Func1"', 'enddef'], 'Xdef') + so Xdef + call writefile(['def! Func0(): string', 'enddef'], 'Xdef') + call assert_fails('so Xdef', 'E1027:') + call writefile(['def Func2(): string', 'return "Func2"', 'enddef'], 'Xdef') + so Xdef + call delete('Xdef') + + call assert_equal(0, Func0()) + call assert_equal('Func1', Func1()) + call assert_equal('Func2', Func2()) + + delfunc! Func0 + delfunc! Func1 + delfunc! Func2 +enddef + +" Test for internal functions returning different types +func Test_InternalFuncRetType() + let lines =<< trim END + def RetFloat(): float + return ceil(1.456) + enddef + + def RetListAny(): list<any> + return items({'k' : 'v'}) + enddef + + def RetListString(): list<string> + return split('a:b:c', ':') + enddef + + def RetListDictAny(): list<dict<any>> + return getbufinfo() + enddef + + def RetDictNumber(): dict<number> + return wordcount() + enddef + + def RetDictString(): dict<string> + return environ() + enddef + END + call writefile(lines, 'Xscript') + source Xscript + + call assert_equal(2.0, RetFloat()) + call assert_equal([['k', 'v']], RetListAny()) + call assert_equal(['a', 'b', 'c'], RetListString()) + call assert_notequal([], RetListDictAny()) + call assert_notequal({}, RetDictNumber()) + call assert_notequal({}, RetDictString()) + call delete('Xscript') +endfunc + +" Test for passing too many or too few arguments to internal functions +func Test_internalfunc_arg_error() + let l =<< trim END + def! FArgErr(): float + return ceil(1.1, 2) + enddef + END + call writefile(l, 'Xinvalidarg') + call assert_fails('so Xinvalidarg', 'E118:') + let l =<< trim END + def! FArgErr(): float + return ceil() + enddef + END + call writefile(l, 'Xinvalidarg') + call assert_fails('so Xinvalidarg', 'E119:') + call delete('Xinvalidarg') +endfunc + +let s:funcResult = 0 + +def FuncNoArgNoRet() + funcResult = 11 +enddef + +def FuncNoArgRetNumber(): number + funcResult = 22 + return 1234 +enddef + +def FuncOneArgNoRet(arg: number) + funcResult = arg +enddef + +def FuncOneArgRetNumber(arg: number): number + funcResult = arg + return arg +enddef + +def Test_func_type() + let Ref1: func() + funcResult = 0 + Ref1 = FuncNoArgNoRet + Ref1() + assert_equal(11, funcResult) +enddef + +def Test_func_type_fails() + CheckDefFailure(['let ref1: func()'], 'E704:') + + CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number') + CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)') + CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number') +enddef + + +" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index cf12e85bb7..01579a8a32 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -21,13 +21,6 @@ def Test_syntax() let other: list<string> = ['asdf'] enddef -func Test_def_basic() - def SomeFunc(): string - return 'yes' - enddef - call assert_equal('yes', SomeFunc()) -endfunc - let s:appendToMe = 'xxx' let s:addToMe = 111 let g:existing = 'yes' @@ -66,9 +59,9 @@ def Test_assignment() if has('float') let float1: float = 3.4 endif - let funky1: func - let funky2: func = function('len') - let party2: func = funcref('Test_syntax') + let Funky1: func + let Funky2: func = function('len') + let Party2: func = funcref('Test_syntax') " type becomes list<any> let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] @@ -134,6 +127,9 @@ def Test_assignment() assert_equal('noneagain', v:errmsg) call CheckDefFailure(['v:errmsg += "more"'], 'E1013:') call CheckDefFailure(['v:errmsg += 123'], 'E1013:') +enddef + +def Test_assignment_default() " Test default values. let thebool: bool @@ -153,8 +149,8 @@ def Test_assignment() let theblob: blob assert_equal(0z, theblob) - let thefunc: func - assert_equal(test_null_function(), thefunc) + let Thefunc: func + assert_equal(test_null_function(), Thefunc) let thelist: list<any> assert_equal([], thelist) @@ -264,157 +260,6 @@ def Test_cmd_modifier() enddef -def ReturnString(): string - return 'string' -enddef - -def ReturnNumber(): number - return 123 -enddef - -let g:notNumber = 'string' - -def ReturnGlobal(): number - return g:notNumber -enddef - -def Test_return_something() - assert_equal('string', ReturnString()) - assert_equal(123, ReturnNumber()) - assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string') -enddef - -let s:nothing = 0 -def ReturnNothing() - s:nothing = 1 - if true - return - endif - s:nothing = 2 -enddef - -def Test_return_nothing() - ReturnNothing() - assert_equal(1, s:nothing) -enddef - -func Increment() - let g:counter += 1 -endfunc - -def Test_call_ufunc_count() - g:counter = 1 - Increment() - Increment() - Increment() - " works with and without :call - assert_equal(4, g:counter) - call assert_equal(4, g:counter) - unlet g:counter -enddef - -def MyVarargs(arg: string, ...rest: list<string>): string - let res = arg - for s in rest - res ..= ',' .. s - endfor - return res -enddef - -def Test_call_varargs() - assert_equal('one', MyVarargs('one')) - assert_equal('one,two', MyVarargs('one', 'two')) - assert_equal('one,two,three', MyVarargs('one', 'two', 'three')) -enddef - -def MyDefaultArgs(name = 'string'): string - return name -enddef - -def Test_call_default_args() - assert_equal('string', MyDefaultArgs()) - assert_equal('one', MyDefaultArgs('one')) - assert_fails('call MyDefaultArgs("one", "two")', 'E118:') - - call CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:') -enddef - -func Test_call_default_args_from_func() - call assert_equal('string', MyDefaultArgs()) - call assert_equal('one', MyDefaultArgs('one')) - call assert_fails('call MyDefaultArgs("one", "two")', 'E118:') -endfunc - -func TakesOneArg(arg) - echo a:arg -endfunc - -def Test_call_wrong_args() - call CheckDefFailure(['TakesOneArg()'], 'E119:') - call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:') - call CheckDefFailure(['bufnr(xxx)'], 'E1001:') -enddef - -" Default arg and varargs -def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string - let res = one .. ',' .. two - for s in rest - res ..= ',' .. s - endfor - return res -enddef - -def Test_call_def_varargs() - call assert_fails('call MyDefVarargs()', 'E119:') - assert_equal('one,foo', MyDefVarargs('one')) - assert_equal('one,two', MyDefVarargs('one', 'two')) - assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three')) -enddef - -def Test_using_var_as_arg() - call writefile(['def Func(x: number)', 'let x = 234', 'enddef'], 'Xdef') - call assert_fails('so Xdef', 'E1006:') - call delete('Xdef') -enddef - -def Test_call_func_defined_later() - call assert_equal('one', DefinedLater('one')) - call assert_fails('call NotDefined("one")', 'E117:') -enddef - -func DefinedLater(arg) - return a:arg -endfunc - -def FuncWithForwardCall() - return DefinedEvenLater("yes") -enddef - -def DefinedEvenLater(arg: string): string - return arg -enddef - -def Test_error_in_nested_function() - " Error in called function requires unwinding the call stack. - assert_fails('call FuncWithForwardCall()', 'E1029') -enddef - -def Test_return_type_wrong() - CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string') - CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number') - CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string') - CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string') - - CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:') - - CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:') - CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:') -enddef - -def Test_arg_type_wrong() - CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>') -enddef - def Test_try_catch() let l = [] try @@ -732,82 +577,6 @@ def Test_vim9script_fails() assert_fails('export something', 'E1042') enddef -def Test_vim9script_call() - let lines =<< trim END - vim9script - let var = '' - def MyFunc(arg: string) - var = arg - enddef - MyFunc('foobar') - assert_equal('foobar', var) - - let str = 'barfoo' - str->MyFunc() - assert_equal('barfoo', var) - - let g:value = 'value' - g:value->MyFunc() - assert_equal('value', var) - - let listvar = [] - def ListFunc(arg: list<number>) - listvar = arg - enddef - [1, 2, 3]->ListFunc() - assert_equal([1, 2, 3], listvar) - - let dictvar = {} - def DictFunc(arg: dict<number>) - dictvar = arg - enddef - {'a': 1, 'b': 2}->DictFunc() - assert_equal(#{a: 1, b: 2}, dictvar) - def CompiledDict() - {'a': 3, 'b': 4}->DictFunc() - enddef - CompiledDict() - assert_equal(#{a: 3, b: 4}, dictvar) - - #{a: 3, b: 4}->DictFunc() - assert_equal(#{a: 3, b: 4}, dictvar) - - ('text')->MyFunc() - assert_equal('text', var) - ("some")->MyFunc() - assert_equal('some', var) - END - writefile(lines, 'Xcall.vim') - source Xcall.vim - delete('Xcall.vim') -enddef - -def Test_vim9script_call_fail_decl() - let lines =<< trim END - vim9script - let var = '' - def MyFunc(arg: string) - let var = 123 - enddef - END - writefile(lines, 'Xcall_decl.vim') - assert_fails('source Xcall_decl.vim', 'E1054:') - delete('Xcall_decl.vim') -enddef - -def Test_vim9script_call_fail_const() - let lines =<< trim END - vim9script - const var = '' - def MyFunc(arg: string) - var = 'asdf' - enddef - END - writefile(lines, 'Xcall_const.vim') - assert_fails('source Xcall_const.vim', 'E46:') - delete('Xcall_const.vim') -enddef - def Test_vim9script_reload() let lines =<< trim END vim9script @@ -926,17 +695,6 @@ def Test_fixed_size_list() assert_equal([2, 99, 3, 4, 5], l) enddef -" Test that inside :function a Python function can be defined, :def is not -" recognized. -func Test_function_python() - CheckFeature python3 - let py = 'python3' - execute py "<< EOF" -def do_something(): - return 1 -EOF -endfunc - def IfElse(what: number): string let res = '' if what == 1 @@ -1087,27 +845,6 @@ def Test_if_const_expr_fails() call CheckDefFailure(["if has('aaa') ? true false"], 'E109:') enddef -def Test_delfunc() - let lines =<< trim END - vim9script - def GoneSoon() - echo 'hello' - enddef - - def CallGoneSoon() - GoneSoon() - enddef - - delfunc GoneSoon - CallGoneSoon() - END - writefile(lines, 'XToDelFunc') - assert_fails('so XToDelFunc', 'E933') - assert_fails('so XToDelFunc', 'E933') - - delete('XToDelFunc') -enddef - def Test_execute_cmd() new setline(1, 'default') @@ -1222,83 +959,6 @@ def Test_interrupt_loop() assert_true(caught, 'should have caught an exception') enddef -def Test_redef_failure() - call writefile(['def Func0(): string', 'return "Func0"', 'enddef'], 'Xdef') - so Xdef - call writefile(['def Func1(): string', 'return "Func1"', 'enddef'], 'Xdef') - so Xdef - call writefile(['def! Func0(): string', 'enddef'], 'Xdef') - call assert_fails('so Xdef', 'E1027:') - call writefile(['def Func2(): string', 'return "Func2"', 'enddef'], 'Xdef') - so Xdef - call delete('Xdef') - - call assert_equal(0, Func0()) - call assert_equal('Func1', Func1()) - call assert_equal('Func2', Func2()) - - delfunc! Func0 - delfunc! Func1 - delfunc! Func2 -enddef - -" Test for internal functions returning different types -func Test_InternalFuncRetType() - let lines =<< trim END - def RetFloat(): float - return ceil(1.456) - enddef - - def RetListAny(): list<any> - return items({'k' : 'v'}) - enddef - - def RetListString(): list<string> - return split('a:b:c', ':') - enddef - - def RetListDictAny(): list<dict<any>> - return getbufinfo() - enddef - - def RetDictNumber(): dict<number> - return wordcount() - enddef - - def RetDictString(): dict<string> - return environ() - enddef - END - call writefile(lines, 'Xscript') - source Xscript - - call assert_equal(2.0, RetFloat()) - call assert_equal([['k', 'v']], RetListAny()) - call assert_equal(['a', 'b', 'c'], RetListString()) - call assert_notequal([], RetListDictAny()) - call assert_notequal({}, RetDictNumber()) - call assert_notequal({}, RetDictString()) - call delete('Xscript') -endfunc - -" Test for passing too many or too few arguments to internal functions -func Test_internalfunc_arg_error() - let l =<< trim END - def! FArgErr(): float - return ceil(1.1, 2) - enddef - END - call writefile(l, 'Xinvalidarg') - call assert_fails('so Xinvalidarg', 'E118:') - let l =<< trim END - def! FArgErr(): float - return ceil() - enddef - END - call writefile(l, 'Xinvalidarg') - call assert_fails('so Xinvalidarg', 'E119:') - call delete('Xinvalidarg') -endfunc " Keep this last, it messes up highlighting. def Test_substitute_cmd() diff --git a/src/userfunc.c b/src/userfunc.c index 71591eb5e9..cff86da6fd 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -951,6 +951,9 @@ func_clear_items(ufunc_T *fp) VIM_CLEAR(fp->uf_arg_types); VIM_CLEAR(fp->uf_def_ |