To: vim_dev@googlegroups.com Subject: Patch 8.2.0487 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0487 Problem: Vim9: compiling not sufficiently tested. Solution: Add more tests. Fix bug with PCALL. Files: src/vim9compile.c, src/vim9execute.c, src/vim9.h, src/testdir/test_vim9_script.vim, src/testdir/test_vim9_disassemble.vim *** ../vim-8.2.0486/src/vim9compile.c 2020-03-30 22:51:20.647982632 +0200 --- src/vim9compile.c 2020-03-31 22:14:42.410207941 +0200 *************** *** 1196,1201 **** --- 1196,1206 ---- // drop the funcref/partial, get back the return value ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_any; + // If partial is above the arguments it must be cleared and replaced with + // the return value. + if (at_top && generate_instr(cctx, ISN_PCALL_END) == NULL) + return FAIL; + return OK; } *************** *** 5200,5206 **** p = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@') ? ea.cmd + 1 : ea.cmd; p = to_name_end(p, TRUE); ! if ((p > ea.cmd && *p != NUL) || *p == '(') { int oplen; int heredoc; --- 5205,5211 ---- p = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@') ? ea.cmd + 1 : ea.cmd; p = to_name_end(p, TRUE); ! if (p > ea.cmd && *p != NUL) { int oplen; int heredoc; *************** *** 5538,5543 **** --- 5543,5549 ---- case ISN_OPFLOAT: case ISN_OPANY: case ISN_PCALL: + case ISN_PCALL_END: case ISN_PUSHF: case ISN_PUSHNR: case ISN_PUSHBOOL: *** ../vim-8.2.0486/src/vim9execute.c 2020-03-29 18:40:08.853652561 +0200 --- src/vim9execute.c 2020-03-31 22:57:21.186038745 +0200 *************** *** 345,351 **** static int call_partial(typval_T *tv, int argcount, ectx_T *ectx) { ! char_u *name; int called_emsg_before = called_emsg; if (tv->v_type == VAR_PARTIAL) --- 345,351 ---- static int call_partial(typval_T *tv, int argcount, ectx_T *ectx) { ! char_u *name = NULL; int called_emsg_before = called_emsg; if (tv->v_type == VAR_PARTIAL) *************** *** 356,364 **** return call_ufunc(pt->pt_func, argcount, ectx, NULL); name = pt->pt_name; } ! else name = tv->vval.v_string; ! if (call_by_name(name, argcount, ectx, NULL) == FAIL) { if (called_emsg == called_emsg_before) semsg(_(e_unknownfunc), name); --- 356,364 ---- return call_ufunc(pt->pt_func, argcount, ectx, NULL); name = pt->pt_name; } ! else if (tv->v_type == VAR_FUNC) name = tv->vval.v_string; ! if (name == NULL || call_by_name(name, argcount, ectx, NULL) == FAIL) { if (called_emsg == called_emsg_before) semsg(_(e_unknownfunc), name); *************** *** 421,427 **** typval_T *tv; int idx; int ret = FAIL; - dfunc_T *dfunc; int defcount = ufunc->uf_args.ga_len - argc; // Get pointer to item in the stack. --- 421,426 ---- *************** *** 467,479 **** ++ectx.ec_stack.ga_len; } ! // Reserve space for local variables. ! dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; ! for (idx = 0; idx < dfunc->df_varcount; ++idx) ! STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN; ! ectx.ec_stack.ga_len += dfunc->df_varcount; ! ectx.ec_instr = dfunc->df_instr; // Decide where to start execution, handles optional arguments. init_instr_idx(ufunc, argc, &ectx); --- 466,482 ---- ++ectx.ec_stack.ga_len; } ! { ! // Reserve space for local variables. ! dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) ! + ufunc->uf_dfunc_idx; ! ! for (idx = 0; idx < dfunc->df_varcount; ++idx) ! STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN; ! ectx.ec_stack.ga_len += dfunc->df_varcount; ! ectx.ec_instr = dfunc->df_instr; ! } // Decide where to start execution, handles optional arguments. init_instr_idx(ufunc, argc, &ectx); *************** *** 1022,1039 **** clear_tv(&partial); if (r == FAIL) goto failed; - - if (pfunc->cpf_top) - { - // Get the funcref from the stack, overwrite with the - // return value. - clear_tv(tv); - --ectx.ec_stack.ga_len; - *STACK_TV_BOT(-1) = *STACK_TV_BOT(0); - } } break; // call a user defined function or funcref/partial case ISN_UCALL: { --- 1025,1042 ---- clear_tv(&partial); if (r == FAIL) goto failed; } break; + case ISN_PCALL_END: + // PCALL finished, arguments have been consumed and replaced by + // the return value. Now clear the funcref from the stack, + // and move the return value in its place. + --ectx.ec_stack.ga_len; + clear_tv(STACK_TV_BOT(-1)); + *STACK_TV_BOT(-1) = *STACK_TV_BOT(0); + break; + // call a user defined function or funcref/partial case ISN_UCALL: { *************** *** 1078,1083 **** --- 1081,1087 ---- case ISN_FUNCREF: { partial_T *pt = NULL; + dfunc_T *dfunc; pt = ALLOC_CLEAR_ONE(partial_T); if (pt == NULL) *************** *** 2005,2010 **** --- 2009,2017 ---- cpfunc->cpf_top ? " top" : "", cpfunc->cpf_argcount); } break; + case ISN_PCALL_END: + smsg("%4d PCALL end", current); + break; case ISN_RETURN: smsg("%4d RETURN", current); break; *** ../vim-8.2.0486/src/vim9.h 2020-03-20 18:39:42.981273170 +0100 --- src/vim9.h 2020-03-31 23:06:03.492096623 +0200 *************** *** 57,62 **** --- 57,63 ---- ISN_DCALL, // call def function isn_arg.dfunc ISN_UCALL, // call user function or funcref/partial isn_arg.ufunc ISN_PCALL, // call partial, use isn_arg.pfunc + ISN_PCALL_END, // cleanup after ISN_PCALL with cpf_top set ISN_RETURN, // return, result is on top of stack ISN_FUNCREF, // push a function ref to dfunc isn_arg.number *************** *** 256,262 **** // Functions defined with :def are stored in this growarray. // They are never removed, so that they can be found by index. // Deleted functions have the df_deleted flag set. ! garray_T def_functions = {0, 0, sizeof(dfunc_T), 50, NULL}; #else extern garray_T def_functions; #endif --- 257,263 ---- // Functions defined with :def are stored in this growarray. // They are never removed, so that they can be found by index. // Deleted functions have the df_deleted flag set. ! garray_T def_functions = {0, 0, sizeof(dfunc_T), 200, NULL}; #else extern garray_T def_functions; #endif *** ../vim-8.2.0486/src/testdir/test_vim9_script.vim 2020-03-30 22:51:20.647982632 +0200 --- src/testdir/test_vim9_script.vim 2020-03-31 21:20:09.159386006 +0200 *************** *** 260,268 **** echo a:arg endfunc ! def Test_call_wrong_arg_count() call CheckDefFailure(['TakesOneArg()'], 'E119:') call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:') enddef " Default arg and varargs --- 260,269 ---- 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 *************** *** 1029,1034 **** --- 1030,1043 ---- assert_equal('1_3_', result) enddef + def Test_for_loop_fails() + call CheckDefFailure(['for # in range(5)'], 'E690:') + call CheckDefFailure(['for i In range(5)'], 'E690:') + call CheckDefFailure(['let x = 5', 'for x in range(5)'], 'E1023:') + call CheckScriptFailure(['def Func(arg)', 'for arg in range(5)', 'enddef'], 'E1006:') + call CheckDefFailure(['for i in "text"'], 'E1024:') + enddef + def Test_interrupt_loop() let caught = false let x = 0 *** ../vim-8.2.0486/src/testdir/test_vim9_disassemble.vim 2020-03-19 14:52:16.973228215 +0100 --- src/testdir/test_vim9_disassemble.vim 2020-03-31 22:53:33.458923423 +0200 *************** *** 224,229 **** --- 224,254 ---- enddef + def EchoArg(arg: string): string + return arg + enddef + def RefThis(): func + return function('EchoArg') + enddef + def s:ScriptPCall() + RefThis()("text") + enddef + + def Test_disassemble_pcall() + let res = execute('disass s:ScriptPCall') + assert_match('\d\+_ScriptPCall.*' + \ .. 'RefThis()("text").*' + \ .. '\d DCALL RefThis(argc 0).*' + \ .. '\d PUSHS "text".*' + \ .. '\d PCALL top (argc 1).*' + \ .. '\d PCALL end.*' + \ .. '\d DROP.*' + \ .. '\d PUSHNR 0.*' + \ .. '\d RETURN.*' + \, res) + enddef + + def FuncWithForwardCall(): string return DefinedLater("yes") enddef *** ../vim-8.2.0486/src/version.c 2020-03-30 22:51:20.647982632 +0200 --- src/version.c 2020-03-31 23:07:02.831880459 +0200 *************** *** 740,741 **** --- 740,743 ---- { /* Add new patch number below this line */ + /**/ + 487, /**/ -- My girlfriend told me I should be more affectionate. So I got TWO girlfriends. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///