To: vim_dev@googlegroups.com Subject: Patch 7.4.1582 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 name() and s:name() to K_SNR 123_name(). - * Change 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 name() and s:name() to K_SNR 123_name(). ! * Change 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)) /* "" 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)) /* "" 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 -- Bram@Moolenaar.net -- 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 ///