Patch 7.4.1836
Problem:    When using a partial on a dictionary it always gets bound to that
            dictionary.
Solution:   Make a difference between binding a function to a dictionary
            explicitly or automatically.
Files:      src/structs.h, src/eval.c, src/testdir/test_partial.vim,
            runtime/doc/eval.txt


*** ../vim-7.4.1835/src/structs.h       2016-05-09 17:57:59.810722519 +0200
--- src/structs.h       2016-05-24 13:13:50.267420387 +0200
***************
*** 1261,1266 ****
--- 1261,1268 ----
  {
      int               pt_refcount;    /* reference count */
      char_u    *pt_name;       /* function name */
+     int               pt_auto;        /* when TRUE the partial was created 
for using
+                                  dict.member in handle_subscript() */
      int               pt_argc;        /* number of arguments */
      typval_T  *pt_argv;       /* arguments in allocated array */
      dict_T    *pt_dict;       /* dict for "self" */
*** ../vim-7.4.1835/src/eval.c  2016-05-15 18:00:11.510811069 +0200
--- src/eval.c  2016-05-24 15:37:25.719301875 +0200
***************
*** 9069,9082 ****
  
      if (partial != NULL)
      {
!       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)
        {
            for (argv_clear = 0; argv_clear < partial->pt_argc; ++argv_clear)
--- 9069,9080 ----
  
      if (partial != NULL)
      {
!       /* When the function has a partial with a dict and there is a dict
!        * argument, use the dict argument.  That is backwards compatible.
!        * When the dict was bound explicitly use the one from the partial. */
!       if (partial->pt_dict != NULL
!               && (selfdict_in == NULL || !partial->pt_auto))
!           selfdict = partial->pt_dict;
        if (error == ERROR_NONE && partial->pt_argc > 0)
        {
            for (argv_clear = 0; argv_clear < partial->pt_argc; ++argv_clear)
***************
*** 12330,12341 ****
--- 12328,12343 ----
                 * use "dict".  That is backwards compatible. */
                if (dict_idx > 0)
                {
+                   /* The dict is bound explicitly, pt_auto is FALSE. */
                    pt->pt_dict = argvars[dict_idx].vval.v_dict;
                    ++pt->pt_dict->dv_refcount;
                }
                else if (arg_pt != NULL)
                {
+                   /* If the dict was bound automatically the result is also
+                    * bound automatically. */
                    pt->pt_dict = arg_pt->pt_dict;
+                   pt->pt_auto = arg_pt->pt_auto;
                    if (pt->pt_dict != NULL)
                        ++pt->pt_dict->dv_refcount;
                }
***************
*** 22279,22286 ****
        }
      }
  
!     if ((rettv->v_type == VAR_FUNC || rettv->v_type == VAR_PARTIAL)
!                                                         && selfdict != NULL)
      {
        char_u      *fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
                                             : rettv->vval.v_partial->pt_name;
--- 22281,22294 ----
        }
      }
  
!     /* Turn "dict.Func" into a partial for "Func" bound to "dict".
!      * Don't do this when "Func" is already a partial that was bound
!      * explicitly (pt_auto is FALSE). */
!     if (selfdict != NULL
!           && (rettv->v_type == VAR_FUNC
!               || (rettv->v_type == VAR_PARTIAL
!                   && (rettv->vval.v_partial->pt_auto
!                       || rettv->vval.v_partial->pt_dict == NULL))))
      {
        char_u      *fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
                                             : rettv->vval.v_partial->pt_name;
***************
*** 22294,22300 ****
        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))
        {
            partial_T   *pt = (partial_T *)alloc_clear(sizeof(partial_T));
--- 22302,22307 ----
***************
*** 22303,22308 ****
--- 22310,22316 ----
            {
                pt->pt_refcount = 1;
                pt->pt_dict = selfdict;
+               pt->pt_auto = TRUE;
                selfdict = NULL;
                if (rettv->v_type == VAR_FUNC)
                {
*** ../vim-7.4.1835/src/testdir/test_partial.vim        2016-04-08 
17:25:15.198702510 +0200
--- src/testdir/test_partial.vim        2016-05-24 15:41:07.923298818 +0200
***************
*** 257,259 ****
--- 257,281 ----
      call job_setoptions(g:ref_job, {'exit_cb': function('string', [], d)})
    endif
  endfunc
+ 
+ func Test_auto_partial_rebind()
+   let dict1 = {'name': 'dict1'}
+   func! dict1.f1()
+     return self.name
+   endfunc
+   let dict1.f2 = function(dict1.f1, dict1)
+ 
+   call assert_equal('dict1', dict1.f1())
+   call assert_equal('dict1', dict1['f1']())
+   call assert_equal('dict1', dict1.f2())
+   call assert_equal('dict1', dict1['f2']())
+ 
+   let dict2 = {'name': 'dict2'}
+   let dict2.f1 = dict1.f1
+   let dict2.f2 = dict1.f2
+ 
+   call assert_equal('dict2', dict2.f1())
+   call assert_equal('dict2', dict2['f1']())
+   call assert_equal('dict1', dict2.f2())
+   call assert_equal('dict1', dict2['f2']())
+ endfunc
*** ../vim-7.4.1835/runtime/doc/eval.txt        2016-04-14 13:51:16.211410903 
+0200
--- runtime/doc/eval.txt        2016-05-24 12:46:44.923442745 +0200
***************
*** 61,72 ****
  
  Funcref               A reference to a function |Funcref|.
                Example: function("strlen")
  
  Special               |v:false|, |v:true|, |v:none| and |v:null|.  *Special*
  
! Job           Used for a job, see |job_start()|. *Job*
  
! Channel               Used for a channel, see |ch_open()|. *Channel*
  
  The Number and String types are converted automatically, depending on how they
  are used.
--- 59,73 ----
  
  Funcref               A reference to a function |Funcref|.
                Example: function("strlen")
+               It can be bound to a dictionary and arguments, it then works
+               like a Partial.
+               Example: function("Callback", [arg], myDict)
  
  Special               |v:false|, |v:true|, |v:none| and |v:null|.  *Special*
  
! Job           Used for a job, see |job_start()|. *Job* *Jobs*
  
! Channel               Used for a channel, see |ch_open()|. *Channel* 
*Channels*
  
  The Number and String types are converted automatically, depending on how they
  are used.
***************
*** 150,159 ****
  You can use |call()| to invoke a Funcref and use a list variable for the
  arguments: >
        :let r = call(Fn, mylist)
  
  
  1.3 Lists ~
!                                                       *List* *Lists* *E686*
  A List is an ordered sequence of items.  An item can be of any type.  Items
  can be accessed by their index number.        Items can be added and removed 
at any
  position in the sequence.
--- 153,199 ----
  You can use |call()| to invoke a Funcref and use a list variable for the
  arguments: >
        :let r = call(Fn, mylist)
+ <
+                                                               *Partial*
+ A Funcref optionally binds a Dictionary and/or arguments.  This is also called
+ a Partial.  This is created by passing the Dictionary and/or arguments to
+ function().  When calling the function the Dictionary and/or arguments will be
+ passed to the function.  Example: >
+ 
+       let Cb = function('Callback', ['foo'], myDict)
+       call Cb()
+ 
+ This will invoke the function as if using: >
+       call myDict.Callback('foo')
+ 
+ This is very useful when passing a function around, e.g. in the arguments of
+ |ch_open()|.
+ 
+ Note that binding a function to a Dictionary also happens when the function is
+ a member of the Dictionary: >
+ 
+       let myDict.myFunction = MyFunction
+       call myDict.myFunction()
+ 
+ Here MyFunction() will get myDict passed as "self".  This happens when the
+ "myFunction" member is accessed.  When making assigning "myFunction" to
+ otherDict and calling it, it will be bound to otherDict: >
+ 
+       let otherDict.myFunction = myDict.myFunction
+       call otherDict.myFunction()
+ 
+ Now "self" will be "otherDict".  But when the dictionary was bound explicitly
+ this won't happen: >
+ 
+       let myDict.myFunction = function(MyFunction, myDict)
+       let otherDict.myFunction = myDict.myFunction
+       call otherDict.myFunction()
+ 
+ Here "self" will be "myDict", because it was bound explitly.
  
  
  1.3 Lists ~
!                                               *list* *List* *Lists* *E686*
  A List is an ordered sequence of items.  An item can be of any type.  Items
  can be accessed by their index number.        Items can be added and removed 
at any
  position in the sequence.
*** ../vim-7.4.1835/src/version.c       2016-05-24 11:31:10.523505120 +0200
--- src/version.c       2016-05-24 15:41:19.031298666 +0200
***************
*** 755,756 ****
--- 755,758 ----
  {   /* Add new patch number below this line */
+ /**/
+     1836,
  /**/

-- 
It's totally unfair to suggest - as many have - that engineers are socially
inept.  Engineers simply have different objectives when it comes to social
interaction.
                                (Scott Adams - The Dilbert principle)

 /// 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