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.
diff --git a/src/eval.c b/src/eval.c
index 891cbad..6280323 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -110,7 +110,6 @@
#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"
@@ -8678,6 +8677,67 @@
return ret;
}
+#define ERROR_UNKNOWN 0
+#define ERROR_TOOMANY 1
+#define ERROR_TOOFEW 2
+#define ERROR_SCRIPT 3
+#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)
+ {
+ fname_buf[0] = K_SPECIAL;
+ fname_buf[1] = KS_EXTRA;
+ fname_buf[2] = (int)KE_SNR;
+ i = 3;
+ 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);
+ i = (int)STRLEN(fname_buf);
+ }
+ }
+ if (i + STRLEN(name + llen) < FLEN_FIXED)
+ {
+ STRCPY(fname_buf + i, name + llen);
+ fname = fname_buf;
+ }
+ else
+ {
+ 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);
+ }
+ }
+ }
+ else
+ fname = name;
+ return fname;
+}
/*
* Call a function with its resolved parameters
@@ -8700,20 +8760,11 @@
dict_T *selfdict_in) /* Dictionary for "self" */
{
int ret = FAIL;
-#define ERROR_UNKNOWN 0
-#define ERROR_TOOMANY 1
-#define ERROR_TOOFEW 2
-#define ERROR_SCRIPT 3
-#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 *tofree = NULL;
char_u *fname;
char_u *name;
int argcount = argcount_in;
@@ -8728,47 +8779,7 @@
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)
- {
- fname_buf[0] = K_SPECIAL;
- fname_buf[1] = KS_EXTRA;
- fname_buf[2] = (int)KE_SNR;
- i = 3;
- 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);
- i = (int)STRLEN(fname_buf);
- }
- }
- if (i + STRLEN(name + llen) < FLEN_FIXED)
- {
- STRCPY(fname_buf + i, name + llen);
- fname = fname_buf;
- }
- else
- {
- 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);
- }
- }
- }
- else
- fname = name;
+ fname = fname_trans_sid(name, fname_buf, &tofree, &error);
*doesrange = FALSE;
@@ -8776,9 +8787,11 @@
{
if (partial->pt_dict != NULL)
{
- if (selfdict_in != NULL)
- error = ERROR_BOTH;
- 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.
+ */
+ if (selfdict_in == NULL)
+ selfdict = partial->pt_dict;
}
if (error == ERROR_NONE && partial->pt_argc > 0)
{
@@ -8934,16 +8947,12 @@
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(tofree);
vim_free(name);
return ret;
@@ -11876,12 +11885,6 @@
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;
}
@@ -11925,16 +11928,18 @@
}
}
- 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)
+ /* 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;
+ }
pt->pt_refcount = 1;
pt->pt_name = name;
@@ -21714,7 +21719,17 @@
if (rettv->v_type == VAR_FUNC && selfdict != NULL)
{
- ufunc_T *fp = find_func(rettv->vval.v_string);
+ 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))