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.