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 <SNR>\d\+_ImpFunc\[1\]..<SNR>\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 -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202005252037.04PKbFck409552%40masaka.moolenaar.net.

Raspunde prin e-mail lui