Patch 7.4.1582
Problem:    Get E923 when using function(dict.func, [], dict). (Kent Sibilev)
            Storing a function with a dict in a variable drops the dict if the
            function is script-local.
Solution:   Translate the function name.  Use dict arg if present.
Files:      src/eval.c, src/testdir/test_partial.vim


*** ../vim-7.4.1581/src/eval.c  2016-03-16 21:40:25.908329269 +0100
--- src/eval.c  2016-03-16 22:47:21.014095263 +0100
***************
*** 110,116 ****
  #ifdef FEAT_FLOAT
  static char *e_float_as_string = N_("E806: using Float as a String");
  #endif
- static char *e_dict_both = N_("E924: can't have both a \"self\" dict and a 
partial: %s");
  
  #define NAMESPACE_CHAR        (char_u *)"abglstvw"
  
--- 110,115 ----
***************
*** 8678,8705 ****
      return ret;
  }
  
- 
- /*
-  * Call a function with its resolved parameters
-  * Return FAIL when the function can't be called,  OK otherwise.
-  * Also returns OK when an error was encountered while executing the function.
-  */
-     int
- call_func(
-     char_u    *funcname,      /* name of the function */
-     int               len,            /* length of "name" */
-     typval_T  *rettv,         /* return value goes here */
-     int               argcount_in,    /* number of "argvars" */
-     typval_T  *argvars_in,    /* vars for arguments, must have "argcount"
-                                  PLUS ONE elements! */
-     linenr_T  firstline,      /* first line of range */
-     linenr_T  lastline,       /* last line of range */
-     int               *doesrange,     /* return: function handled range */
-     int               evaluate,
-     partial_T *partial,       /* optional, can be NULL */
-     dict_T    *selfdict_in)   /* Dictionary for "self" */
- {
-     int               ret = FAIL;
  #define ERROR_UNKNOWN 0
  #define ERROR_TOOMANY 1
  #define ERROR_TOOFEW  2
--- 8677,8682 ----
***************
*** 8707,8738 ****
  #define ERROR_DICT    4
  #define ERROR_NONE    5
  #define ERROR_OTHER   6
- #define ERROR_BOTH    7
-     int               error = ERROR_NONE;
-     int               i;
-     int               llen;
-     ufunc_T   *fp;
  #define FLEN_FIXED 40
-     char_u    fname_buf[FLEN_FIXED + 1];
-     char_u    *fname;
-     char_u    *name;
-     int               argcount = argcount_in;
-     typval_T  *argvars = argvars_in;
-     dict_T    *selfdict = selfdict_in;
-     typval_T  argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */
-     int               argv_clear = 0;
  
!     /* Make a copy of the name, if it comes from a funcref variable it could
!      * be changed or deleted in the called function. */
!     name = vim_strnsave(funcname, len);
!     if (name == NULL)
!       return ret;
  
-     /*
-      * In a script change <SID>name() and s:name() to K_SNR 123_name().
-      * Change <SNR>123_name() to K_SNR 123_name().
-      * Use fname_buf[] when it fits, otherwise allocate memory (slow).
-      */
      llen = eval_fname_script(name);
      if (llen > 0)
      {
--- 8684,8704 ----
  #define ERROR_DICT    4
  #define ERROR_NONE    5
  #define ERROR_OTHER   6
  #define FLEN_FIXED 40
  
! /*
!  * In a script change <SID>name() and s:name() to K_SNR 123_name().
!  * Change <SNR>123_name() to K_SNR 123_name().
!  * Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory
!  * (slow).
!  */
!     static char_u *
! fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
! {
!     int               llen;
!     char_u    *fname;
!     int               i;
  
      llen = eval_fname_script(name);
      if (llen > 0)
      {
***************
*** 8743,8749 ****
        if (eval_fname_sid(name))       /* "<SID>" or "s:" */
        {
            if (current_SID <= 0)
!               error = ERROR_SCRIPT;
            else
            {
                sprintf((char *)fname_buf + 3, "%ld_", (long)current_SID);
--- 8709,8715 ----
        if (eval_fname_sid(name))       /* "<SID>" or "s:" */
        {
            if (current_SID <= 0)
!               *error = ERROR_SCRIPT;
            else
            {
                sprintf((char *)fname_buf + 3, "%ld_", (long)current_SID);
***************
*** 8759,8767 ****
        {
            fname = alloc((unsigned)(i + STRLEN(name + llen) + 1));
            if (fname == NULL)
!               error = ERROR_OTHER;
            else
            {
                mch_memmove(fname, fname_buf, (size_t)i);
                STRCPY(fname + i, name + llen);
            }
--- 8725,8734 ----
        {
            fname = alloc((unsigned)(i + STRLEN(name + llen) + 1));
            if (fname == NULL)
!               *error = ERROR_OTHER;
            else
            {
+               *tofree = fname;
                mch_memmove(fname, fname_buf, (size_t)i);
                STRCPY(fname + i, name + llen);
            }
***************
*** 8769,8774 ****
--- 8736,8785 ----
      }
      else
        fname = name;
+     return fname;
+ }
+ 
+ /*
+  * Call a function with its resolved parameters
+  * Return FAIL when the function can't be called,  OK otherwise.
+  * Also returns OK when an error was encountered while executing the function.
+  */
+     int
+ call_func(
+     char_u    *funcname,      /* name of the function */
+     int               len,            /* length of "name" */
+     typval_T  *rettv,         /* return value goes here */
+     int               argcount_in,    /* number of "argvars" */
+     typval_T  *argvars_in,    /* vars for arguments, must have "argcount"
+                                  PLUS ONE elements! */
+     linenr_T  firstline,      /* first line of range */
+     linenr_T  lastline,       /* last line of range */
+     int               *doesrange,     /* return: function handled range */
+     int               evaluate,
+     partial_T *partial,       /* optional, can be NULL */
+     dict_T    *selfdict_in)   /* Dictionary for "self" */
+ {
+     int               ret = FAIL;
+     int               error = ERROR_NONE;
+     int               i;
+     ufunc_T   *fp;
+     char_u    fname_buf[FLEN_FIXED + 1];
+     char_u    *tofree = NULL;
+     char_u    *fname;
+     char_u    *name;
+     int               argcount = argcount_in;
+     typval_T  *argvars = argvars_in;
+     dict_T    *selfdict = selfdict_in;
+     typval_T  argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */
+     int               argv_clear = 0;
+ 
+     /* Make a copy of the name, if it comes from a funcref variable it could
+      * be changed or deleted in the called function. */
+     name = vim_strnsave(funcname, len);
+     if (name == NULL)
+       return ret;
+ 
+     fname = fname_trans_sid(name, fname_buf, &tofree, &error);
  
      *doesrange = FALSE;
  
***************
*** 8776,8784 ****
      {
        if (partial->pt_dict != NULL)
        {
!           if (selfdict_in != NULL)
!               error = ERROR_BOTH;
!           selfdict = partial->pt_dict;
        }
        if (error == ERROR_NONE && partial->pt_argc > 0)
        {
--- 8787,8797 ----
      {
        if (partial->pt_dict != NULL)
        {
!           /* When the function has a partial with a dict and there is a dict
!            * argument, use the dict argument.  That is backwards compatible.
!            */
!           if (selfdict_in == NULL)
!               selfdict = partial->pt_dict;
        }
        if (error == ERROR_NONE && partial->pt_argc > 0)
        {
***************
*** 8934,8949 ****
                    emsg_funcname(N_("E725: Calling dict function without 
Dictionary: %s"),
                                                                        name);
                    break;
-           case ERROR_BOTH:
-                   emsg_funcname(e_dict_both, name);
-                   break;
        }
      }
  
      while (argv_clear > 0)
        clear_tv(&argv[--argv_clear]);
!     if (fname != name && fname != fname_buf)
!       vim_free(fname);
      vim_free(name);
  
      return ret;
--- 8947,8958 ----
                    emsg_funcname(N_("E725: Calling dict function without 
Dictionary: %s"),
                                                                        name);
                    break;
        }
      }
  
      while (argv_clear > 0)
        clear_tv(&argv[--argv_clear]);
!     vim_free(tofree);
      vim_free(name);
  
      return ret;
***************
*** 11876,11887 ****
                    vim_free(name);
                    return;
                }
-               if (argvars[0].v_type == VAR_PARTIAL)
-               {
-                   EMSG2(_(e_dict_both), name);
-                   vim_free(name);
-                   return;
-               }
                if (argvars[dict_idx].vval.v_dict == NULL)
                    dict_idx = 0;
            }
--- 11885,11890 ----
***************
*** 11925,11938 ****
                    }
                }
  
!               if (argvars[0].v_type == VAR_PARTIAL)
                {
!                   pt->pt_dict = argvars[0].vval.v_partial->pt_dict;
                    ++pt->pt_dict->dv_refcount;
                }
!               else if (dict_idx > 0)
                {
!                   pt->pt_dict = argvars[dict_idx].vval.v_dict;
                    ++pt->pt_dict->dv_refcount;
                }
  
--- 11928,11943 ----
                    }
                }
  
!               /* For "function(dict.func, [], dict)" and "func" is a partial
!                * use "dict".  That is backwards compatible. */
!               if (dict_idx > 0)
                {
!                   pt->pt_dict = argvars[dict_idx].vval.v_dict;
                    ++pt->pt_dict->dv_refcount;
                }
!               else if (argvars[0].v_type == VAR_PARTIAL)
                {
!                   pt->pt_dict = argvars[0].vval.v_partial->pt_dict;
                    ++pt->pt_dict->dv_refcount;
                }
  
***************
*** 21714,21720 ****
  
      if (rettv->v_type == VAR_FUNC && selfdict != NULL)
      {
!       ufunc_T *fp = find_func(rettv->vval.v_string);
  
        /* Turn "dict.Func" into a partial for "Func" with "dict". */
        if (fp != NULL && (fp->uf_flags & FC_DICT))
--- 21719,21735 ----
  
      if (rettv->v_type == VAR_FUNC && selfdict != NULL)
      {
!       char_u      *fname;
!       char_u      *tofree = NULL;
!       ufunc_T     *fp;
!       char_u      fname_buf[FLEN_FIXED + 1];
!       int         error;
! 
!       /* Translate "s:func" to the stored function name. */
!       fname = fname_trans_sid(rettv->vval.v_string, fname_buf,
!                                                            &tofree, &error);
!       fp = find_func(fname);
!       vim_free(tofree);
  
        /* Turn "dict.Func" into a partial for "Func" with "dict". */
        if (fp != NULL && (fp->uf_flags & FC_DICT))
*** ../vim-7.4.1581/src/testdir/test_partial.vim        2016-03-16 
21:40:25.908329269 +0100
--- src/testdir/test_partial.vim        2016-03-16 22:48:01.261665324 +0100
***************
*** 70,77 ****
  
    let Func = function(dict.MyFunc, ['bbb'])
    call assert_equal('foo/bbb', Func())
- 
-   call assert_fails('call function(dict.MyFunc, ["bbb"], dict)', 'E924:')
  endfunc
  
  fun InnerCall(funcref)
--- 70,75 ----
***************
*** 87,89 ****
--- 85,108 ----
    call OuterCall()
  endfunc
  
+ function! s:cache_clear() dict
+   return self.name
+ endfunction
+ 
+ func Test_script_function_in_dict()
+   let s:obj = {'name': 'foo'}
+   let s:obj2 = {'name': 'bar'}
+ 
+   let s:obj['clear'] = function('s:cache_clear')
+ 
+   call assert_equal('foo', s:obj.clear())
+   let F = s:obj.clear
+   call assert_equal('foo', F())
+   call assert_equal('foo', call(s:obj.clear, [], s:obj))
+   call assert_equal('bar', call(s:obj.clear, [], s:obj2))
+ 
+   let s:obj2['clear'] = function('s:cache_clear')
+   call assert_equal('bar', s:obj2.clear())
+   let B = s:obj2.clear
+   call assert_equal('bar', B())
+ endfunc
*** ../vim-7.4.1581/src/version.c       2016-03-16 21:40:25.908329269 +0100
--- src/version.c       2016-03-16 22:35:31.337689969 +0100
***************
*** 750,751 ****
--- 750,753 ----
  {   /* Add new patch number below this line */
+ /**/
+     1582,
  /**/

-- 
Be thankful to be in a traffic jam, because it means you own a car.

 /// 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].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui