vim-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.

1d429610bf
This commit is contained in:
Michael Ennen 2016-10-28 12:38:36 -07:00 committed by James McCoy
parent eb337c9949
commit c82dc7a6fd
4 changed files with 63 additions and 13 deletions

View File

@ -1,6 +1,5 @@
*eval.txt* For Vim version 7.4. Last change: 2016 Jun 04
VIM REFERENCE MANUAL by Bram Moolenaar
@ -49,6 +48,9 @@ String A NUL terminated string of 8-bit unsigned characters (bytes).
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)
List An ordered sequence of items |List|.
Example: [1, 2, ['a', 'b']]
@ -139,6 +141,43 @@ The name of the referenced function can be obtained with |string()|. >
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 ~

View File

@ -7099,12 +7099,11 @@ call_func(
*doesrange = FALSE;
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;
}
// 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) {
@ -9643,10 +9642,14 @@ static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// 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)++;
// 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)++;
}
@ -18424,8 +18427,14 @@ handle_subscript (
}
}
if ((rettv->v_type == VAR_FUNC || rettv->v_type == VAR_PARTIAL)
&& selfdict != NULL) {
// 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 (self != 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;
char_u *tofree = NULL;
@ -18446,6 +18455,7 @@ handle_subscript (
if (pt != NULL) {
pt->pt_refcount = 1;
pt->pt_dict = selfdict;
pt->pt_auto = true;
selfdict = NULL;
if (rettv->v_type == VAR_FUNC) {
// Just a function: Take over the function name and use

View File

@ -150,6 +150,8 @@ struct dictvar_S {
struct partial_S {
int pt_refcount; ///< Reference count.
char_u *pt_name; ///< Function name.
bool 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".

View File

@ -604,9 +604,8 @@ static int included_patches[] = {
// 1839,
// 1838,
// 1837,
// 1836,
1836,
1835,
// 1834,
1833,
1832,
1831,