To: vim_dev@googlegroups.com Subject: Patch 8.2.0823 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0823 Problem: Vim9: script reload test is disabled. Solution: Compile a function in the context of the script where it was defined. Set execution stack for compiled function. Add a test that an error is reported for the right file/function. Files: src/vim9compile.c, src/vim9execute.c, src/scriptfile.c, src/proto/scriptfile.pro, src/userfunc.c, src/globals.h, src/structs.h, src/ex_docmd.c, src/ex_eval.c, src/testdir/test_vim9_script.vim *** ../vim-8.2.0822/src/vim9compile.c 2020-05-25 00:28:29.604712788 +0200 --- src/vim9compile.c 2020-05-25 21:43:32.142303773 +0200 *************** *** 2323,2330 **** } line = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum]; cctx->ctx_line_start = line; ! SOURCING_LNUM = cctx->ctx_ufunc->uf_script_ctx.sc_lnum ! + cctx->ctx_lnum + 1; } while (line == NULL || *skipwhite(line) == NUL); return line; } --- 2323,2329 ---- } line = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum]; cctx->ctx_line_start = line; ! SOURCING_LNUM = cctx->ctx_lnum + 1; } while (line == NULL || *skipwhite(line) == NUL); return line; } *************** *** 6349,6362 **** int called_emsg_before = called_emsg; int ret = FAIL; sctx_T save_current_sctx = current_sctx; int emsg_before = called_emsg; if (ufunc->uf_dfunc_idx >= 0) { - // Redefining a function that was compiled before. dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; - // Free old instructions. delete_def_function_contents(dfunc); } else if (add_def_function(ufunc) == FAIL) --- 6348,6362 ---- int called_emsg_before = called_emsg; int ret = FAIL; sctx_T save_current_sctx = current_sctx; + int do_estack_push; int emsg_before = called_emsg; + // When using a function that was compiled before: Free old instructions. + // Otherwise add a new entry in "def_functions". if (ufunc->uf_dfunc_idx >= 0) { dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; delete_def_function_contents(dfunc); } else if (add_def_function(ufunc) == FAIL) *************** *** 6373,6381 **** ga_init2(&cctx.ctx_instr, sizeof(isn_T), 50); instr = &cctx.ctx_instr; ! // Most modern script version. current_sctx.sc_version = SCRIPT_VERSION_VIM9; if (ufunc->uf_def_args.ga_len > 0) { int count = ufunc->uf_def_args.ga_len; --- 6373,6389 ---- ga_init2(&cctx.ctx_instr, sizeof(isn_T), 50); instr = &cctx.ctx_instr; ! // Set the context to the function, it may be compiled when called from ! // another script. Set the script version to the most modern one. ! // The line number will be set in next_line_from_context(). ! current_sctx = ufunc->uf_script_ctx; current_sctx.sc_version = SCRIPT_VERSION_VIM9; + // Make sure error messages are OK. + do_estack_push = !estack_top_is_ufunc(ufunc, 1); + if (do_estack_push) + estack_push_ufunc(ufunc, 1); + if (ufunc->uf_def_args.ga_len > 0) { int count = ufunc->uf_def_args.ga_len; *************** *** 6795,6800 **** --- 6803,6811 ---- } current_sctx = save_current_sctx; + if (do_estack_push) + estack_pop(); + free_imported(&cctx); free_locals(&cctx); ga_clear(&cctx.ctx_type_stack); *** ../vim-8.2.0822/src/vim9execute.c 2020-05-24 23:00:06.444196001 +0200 --- src/vim9execute.c 2020-05-25 21:47:59.449426891 +0200 *************** *** 230,236 **** // Set execution state to the start of the called function. ectx->ec_dfunc_idx = cdf_idx; ectx->ec_instr = dfunc->df_instr; ! estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); // Decide where to start execution, handles optional arguments. init_instr_idx(ufunc, argcount, ectx); --- 230,236 ---- // Set execution state to the start of the called function. ectx->ec_dfunc_idx = cdf_idx; ectx->ec_instr = dfunc->df_instr; ! estack_push_ufunc(dfunc->df_ufunc, 1); // Decide where to start execution, handles optional arguments. init_instr_idx(ufunc, argcount, ectx); *************** *** 656,661 **** --- 656,662 ---- int defcount = ufunc->uf_args.ga_len - argc; int save_sc_version = current_sctx.sc_version; int breakcheck_count = 0; + int called_emsg_before = called_emsg; // Get pointer to item in the stack. #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx) *************** *** 673,679 **** --- 674,686 ---- if (ufunc->uf_dfunc_idx == UF_NOT_COMPILED || (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED && compile_def_function(ufunc, FALSE, NULL) == FAIL)) + { + if (called_emsg == called_emsg_before) + semsg(_("E1091: Function is not compiled: %s"), + ufunc->uf_name_exp == NULL + ? ufunc->uf_name : ufunc->uf_name_exp); return FAIL; + } { // Check the function was really compiled. *** ../vim-8.2.0822/src/scriptfile.c 2020-05-25 20:33:51.766542661 +0200 --- src/scriptfile.c 2020-05-25 21:40:41.370882220 +0200 *************** *** 69,82 **** * Add a user function to the execution stack. */ void ! estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum) { ! estack_T *entry = estack_push(type, ufunc->uf_name_exp != NULL ? ufunc->uf_name_exp : ufunc->uf_name, lnum); if (entry != NULL) entry->es_info.ufunc = ufunc; } #endif /* --- 69,99 ---- * Add a user function to the execution stack. */ void ! estack_push_ufunc(ufunc_T *ufunc, long lnum) { ! estack_T *entry = estack_push(ETYPE_UFUNC, ufunc->uf_name_exp != NULL ? ufunc->uf_name_exp : ufunc->uf_name, lnum); if (entry != NULL) entry->es_info.ufunc = ufunc; } + + /* + * Return TRUE if "ufunc" with "lnum" is already at the top of the exe stack. + */ + int + estack_top_is_ufunc(ufunc_T *ufunc, long lnum) + { + estack_T *entry; + + if (exestack.ga_len == 0) + return FALSE; + entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; + return entry->es_type == ETYPE_UFUNC + && STRCMP( entry->es_name, ufunc->uf_name_exp != NULL + ? ufunc->uf_name_exp : ufunc->uf_name) == 0 + && entry->es_lnum == lnum; + } #endif /* *** ../vim-8.2.0822/src/proto/scriptfile.pro 2020-05-25 20:33:51.766542661 +0200 --- src/proto/scriptfile.pro 2020-05-25 21:43:04.822395175 +0200 *************** *** 1,7 **** /* scriptfile.c */ void estack_init(void); estack_T *estack_push(etype_T type, char_u *name, long lnum); ! void estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum); void estack_pop(void); char_u *estack_sfile(void); void ex_runtime(exarg_T *eap); --- 1,8 ---- /* scriptfile.c */ void estack_init(void); estack_T *estack_push(etype_T type, char_u *name, long lnum); ! void estack_push_ufunc(ufunc_T *ufunc, long lnum); ! int estack_top_is_ufunc(ufunc_T *ufunc, long lnum); void estack_pop(void); char_u *estack_sfile(void); void ex_runtime(exarg_T *eap); *** ../vim-8.2.0822/src/userfunc.c 2020-05-24 23:45:20.529386094 +0200 --- src/userfunc.c 2020-05-25 21:43:27.258320081 +0200 *************** *** 1114,1124 **** if (fp->uf_dfunc_idx != UF_NOT_COMPILED) { ! estack_push_ufunc(ETYPE_UFUNC, fp, 1); save_current_sctx = current_sctx; current_sctx = fp->uf_script_ctx; ! // Execute the compiled function. call_def_function(fp, argcount, argvars, funcexe->partial, rettv); --depth; current_funccal = fc->caller; --- 1114,1124 ---- if (fp->uf_dfunc_idx != UF_NOT_COMPILED) { ! estack_push_ufunc(fp, 1); save_current_sctx = current_sctx; current_sctx = fp->uf_script_ctx; ! // Execute the function, possibly compiling it first. call_def_function(fp, argcount, argvars, funcexe->partial, rettv); --depth; current_funccal = fc->caller; *************** *** 1288,1294 **** ++sandbox; } ! estack_push_ufunc(ETYPE_UFUNC, fp, 1); ESTACK_CHECK_SETUP if (p_verbose >= 12) { --- 1288,1294 ---- ++sandbox; } ! estack_push_ufunc(fp, 1); ESTACK_CHECK_SETUP if (p_verbose >= 12) { *** ../vim-8.2.0822/src/globals.h 2020-05-24 17:23:41.834154785 +0200 --- src/globals.h 2020-05-25 22:13:26.909284260 +0200 *************** *** 344,350 **** * field of a later list element, when the "emsg_severe" flag was set when the * emsg() call was made. */ ! EXTERN struct msglist **msg_list INIT(= NULL); /* * suppress_errthrow: When TRUE, don't convert an error to an exception. Used --- 344,350 ---- * field of a later list element, when the "emsg_severe" flag was set when the * emsg() call was made. */ ! EXTERN msglist_T **msg_list INIT(= NULL); /* * suppress_errthrow: When TRUE, don't convert an error to an exception. Used *** ../vim-8.2.0822/src/structs.h 2020-05-24 23:00:06.440196016 +0200 --- src/structs.h 2020-05-25 22:20:33.992326158 +0200 *************** *** 927,939 **** * A list of error messages that can be converted to an exception. "throw_msg" * is only set in the first element of the list. Usually, it points to the * original message stored in that element, but sometimes it points to a later ! * message in the list. See cause_errthrow() below. */ struct msglist { ! char *msg; // original message ! char *throw_msg; // msg to throw: usually original one ! struct msglist *next; // next of several messages in a row }; /* --- 927,942 ---- * A list of error messages that can be converted to an exception. "throw_msg" * is only set in the first element of the list. Usually, it points to the * original message stored in that element, but sometimes it points to a later ! * message in the list. See cause_errthrow(). */ + typedef struct msglist msglist_T; struct msglist { ! char *msg; // original message, allocated ! char *throw_msg; // msg to throw: usually original one ! char_u *sfile; // value from estack_sfile(), allocated ! long slnum; // line number for "sfile" ! msglist_T *next; // next of several messages in a row }; /* *************** *** 1516,1521 **** --- 1519,1525 ---- #if defined(FEAT_EVAL) || defined(PROTO) typedef struct funccall_S funccall_T; + // values used for "uf_dfunc_idx" # define UF_NOT_COMPILED -2 # define UF_TO_BE_COMPILED -1 *** ../vim-8.2.0822/src/ex_docmd.c 2020-05-25 20:33:51.770542645 +0200 --- src/ex_docmd.c 2020-05-25 22:11:45.593473909 +0200 *************** *** 634,641 **** int *dbg_tick = NULL; // ptr to dbg_tick field in cookie struct dbg_stuff debug_saved; // saved things for debug mode int initial_trylevel; ! struct msglist **saved_msg_list = NULL; ! struct msglist *private_msg_list; // "fgetline" and "cookie" passed to do_one_cmd() char_u *(*cmd_getline)(int, void *, int, int); --- 634,641 ---- int *dbg_tick = NULL; // ptr to dbg_tick field in cookie struct dbg_stuff debug_saved; // saved things for debug mode int initial_trylevel; ! msglist_T **saved_msg_list = NULL; ! msglist_T *private_msg_list; // "fgetline" and "cookie" passed to do_one_cmd() char_u *(*cmd_getline)(int, void *, int, int); *************** *** 1238,1244 **** if (did_throw) { void *p = NULL; ! struct msglist *messages = NULL, *next; /* * If the uncaught exception is a user exception, report it as an --- 1238,1244 ---- if (did_throw) { void *p = NULL; ! msglist_T *messages = NULL, *next; /* * If the uncaught exception is a user exception, report it as an *** ../vim-8.2.0822/src/ex_eval.c 2020-05-14 22:41:10.225637575 +0200 --- src/ex_eval.c 2020-05-25 22:28:03.135166892 +0200 *************** *** 146,153 **** int severe, int *ignore) { ! struct msglist *elem; ! struct msglist **plist; /* * Do nothing when displaying the interrupt message or reporting an --- 146,153 ---- int severe, int *ignore) { ! msglist_T *elem; ! msglist_T **plist; /* * Do nothing when displaying the interrupt message or reporting an *************** *** 251,257 **** while (*plist != NULL) plist = &(*plist)->next; ! elem = ALLOC_ONE(struct msglist); if (elem == NULL) { suppress_errthrow = TRUE; --- 251,257 ---- while (*plist != NULL) plist = &(*plist)->next; ! elem = ALLOC_CLEAR_ONE(msglist_T); if (elem == NULL) { suppress_errthrow = TRUE; *************** *** 287,292 **** --- 287,297 ---- else (*msg_list)->throw_msg = tmsg; } + + // Get the source name and lnum now, it may change before + // reaching do_errthrow(). + elem->sfile = estack_sfile(); + elem->slnum = SOURCING_LNUM; } } } *************** *** 298,312 **** * Free a "msg_list" and the messages it contains. */ static void ! free_msglist(struct msglist *l) { ! struct msglist *messages, *next; messages = l; while (messages != NULL) { next = messages->next; vim_free(messages->msg); vim_free(messages); messages = next; } --- 303,318 ---- * Free a "msg_list" and the messages it contains. */ static void ! free_msglist(msglist_T *l) { ! msglist_T *messages, *next; messages = l; while (messages != NULL) { next = messages->next; vim_free(messages->msg); + vim_free(messages->sfile); vim_free(messages); messages = next; } *************** *** 428,434 **** if (type == ET_ERROR) { *should_free = TRUE; ! mesg = ((struct msglist *)value)->throw_msg; if (cmdname != NULL && *cmdname != NUL) { cmdlen = (int)STRLEN(cmdname); --- 434,440 ---- if (type == ET_ERROR) { *should_free = TRUE; ! mesg = ((msglist_T *)value)->throw_msg; if (cmdname != NULL && *cmdname != NUL) { cmdlen = (int)STRLEN(cmdname); *************** *** 526,548 **** if (type == ET_ERROR) // Store the original message and prefix the exception value with // "Vim:" or, if a command name is given, "Vim(cmdname):". ! excp->messages = (struct msglist *)value; excp->value = get_exception_string(value, type, cmdname, &should_free); if (excp->value == NULL && should_free) goto nomem; excp->type = type; ! excp->throw_name = estack_sfile(); ! if (excp->throw_name == NULL) ! excp->throw_name = vim_strsave((char_u *)""); ! if (excp->throw_name == NULL) { ! if (should_free) ! vim_free(excp->value); ! goto nomem; } - excp->throw_lnum = SOURCING_LNUM; if (p_verbose >= 13 || debug_break_level > 0) { --- 532,565 ---- if (type == ET_ERROR) // Store the original message and prefix the exception value with // "Vim:" or, if a command name is given, "Vim(cmdname):". ! excp->messages = (msglist_T *)value; excp->value = get_exception_string(value, type, cmdname, &should_free); if (excp->value == NULL && should_free) goto nomem; excp->type = type; ! if (type == ET_ERROR && ((msglist_T *)value)->sfile != NULL) { ! msglist_T *entry = (msglist_T *)value; ! ! excp->throw_name = entry->sfile; ! entry->sfile = NULL; ! excp->throw_lnum = entry->slnum; ! } ! else ! { ! excp->throw_name = estack_sfile(); ! if (excp->throw_name == NULL) ! excp->throw_name = vim_strsave((char_u *)""); ! if (excp->throw_name == NULL) ! { ! if (should_free) ! vim_free(excp->value); ! goto nomem; ! } ! excp->throw_lnum = SOURCING_LNUM; } if (p_verbose >= 13 || debug_break_level > 0) { *** ../vim-8.2.0822/src/testdir/test_vim9_script.vim 2020-05-24 23:00:06.444196001 +0200 --- src/testdir/test_vim9_script.vim 2020-05-25 22:30:21.946792717 +0200 *************** *** 745,753 **** enddef def Test_vim9script_reload_import() - " TODO: make it work to compile when not in the script context anymore - return - let lines =<< trim END vim9script const var = '' --- 745,750 ---- *************** *** 797,805 **** enddef def Test_vim9script_reload_delfunc() - " TODO: make it work to compile when not in the script context anymore - return - let first_lines =<< trim END vim9script def FuncYes(): string --- 794,799 ---- *************** *** 920,925 **** --- 914,950 ---- delete('import', 'rf') enddef + def Test_import_compile_error() + let export_lines = [ + 'vim9script', + 'export def ExpFunc(): string', + ' return notDefined', + 'enddef', + ] + writefile(export_lines, 'Xexported.vim') + + let import_lines = [ + 'vim9script', + 'import ExpFunc from "./Xexported.vim"', + 'def ImpFunc()', + ' echo ExpFunc()', + 'enddef', + 'defcompile', + ] + writefile(import_lines, 'Ximport.vim') + + try + source Ximport.vim + catch /E1001/ + " Error should be fore the Xexported.vim file. + assert_match('E1001: variable not found: notDefined', v:exception) + assert_match('function \d\+_ImpFunc\[1\]..\d\+_ExpFunc, line 1', v:throwpoint) + endtry + + delete('Xexported.vim') + delete('Ximport.vim') + enddef + def Test_fixed_size_list() " will be allocated as one piece of memory, check that changes work let l = [1, 2, 3, 4] *** ../vim-8.2.0822/src/version.c 2020-05-25 20:33:51.770542645 +0200 --- src/version.c 2020-05-25 20:44:18.332277232 +0200 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 823, /**/ -- hundred-and-one symptoms of being an internet addict: 176. You lie, even to user-friends, about how long you were online yesterday. /// 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 ///