To: vim_dev@googlegroups.com Subject: Patch 8.2.3783 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3783 Problem: Confusing error for using a variable as a function. Solution: If a function is not found but there is a variable, give a more useful error. (issue #9310) Files: src/eval.c, src/userfunc.c, src/proto/userfunc.pro, src/structs.h, src/vim9execute.c, src/testdir/test_functions.vim, src/testdir/test_vim9_script.vim, src/testdir/test_vim9_func.vim *** ../vim-8.2.3782/src/eval.c 2021-12-09 17:43:53.847057125 +0000 --- src/eval.c 2021-12-11 16:03:34.776046478 +0000 *************** *** 1988,1993 **** --- 1988,1994 ---- partial_T *partial; int ret = OK; type_T *type = NULL; + int found_var = FALSE; if (!evaluate) check_vars(s, len); *************** *** 1995,2001 **** // If "s" is the name of a variable of type VAR_FUNC // use its contents. s = deref_func_name(s, &len, &partial, ! in_vim9script() ? &type : NULL, !evaluate); // Need to make a copy, in case evaluating the arguments makes // the name invalid. --- 1996,2002 ---- // If "s" is the name of a variable of type VAR_FUNC // use its contents. s = deref_func_name(s, &len, &partial, ! in_vim9script() ? &type : NULL, !evaluate, &found_var); // Need to make a copy, in case evaluating the arguments makes // the name invalid. *************** *** 2014,2019 **** --- 2015,2021 ---- funcexe.partial = partial; funcexe.basetv = basetv; funcexe.check_type = type; + funcexe.fe_found_var = found_var; ret = get_func_tv(s, len, rettv, arg, evalarg, &funcexe); } vim_free(s); *** ../vim-8.2.3782/src/userfunc.c 2021-12-11 13:54:43.123245009 +0000 --- src/userfunc.c 2021-12-11 16:06:39.940010971 +0000 *************** *** 1544,1549 **** --- 1544,1550 ---- * "partialp". * If "type" is not NULL and a Vim9 script-local variable is found look up the * type of the variable. + * If "found_var" is not NULL and a variable was found set it to TRUE. */ char_u * deref_func_name( *************** *** 1551,1557 **** int *lenp, partial_T **partialp, type_T **type, ! int no_autoload) { dictitem_T *v; typval_T *tv = NULL; --- 1552,1559 ---- int *lenp, partial_T **partialp, type_T **type, ! int no_autoload, ! int *found_var) { dictitem_T *v; typval_T *tv = NULL; *************** *** 1609,1614 **** --- 1611,1618 ---- if (tv != NULL) { + if (found_var != NULL) + *found_var = TRUE; if (tv->v_type == VAR_FUNC) { if (tv->vval.v_string == NULL) *************** *** 3199,3210 **** * Nothing if "error" is FCERR_NONE. */ void ! user_func_error(int error, char_u *name) { switch (error) { case FCERR_UNKNOWN: ! emsg_funcname(e_unknownfunc, name); break; case FCERR_NOTMETHOD: emsg_funcname( --- 3203,3217 ---- * Nothing if "error" is FCERR_NONE. */ void ! user_func_error(int error, char_u *name, funcexe_T *funcexe) { switch (error) { case FCERR_UNKNOWN: ! if (funcexe->fe_found_var) ! semsg(_(e_not_callable_type_str), name); ! else ! emsg_funcname(e_unknownfunc, name); break; case FCERR_NOTMETHOD: emsg_funcname( *************** *** 3448,3454 **** */ if (!aborting()) { ! user_func_error(error, (name != NULL) ? name : funcname); } // clear the copies made from the partial --- 3455,3461 ---- */ if (!aborting()) { ! user_func_error(error, (name != NULL) ? name : funcname, funcexe); } // clear the copies made from the partial *************** *** 3677,3683 **** { len = (int)STRLEN(lv.ll_exp_name); name = deref_func_name(lv.ll_exp_name, &len, partial, type, ! flags & TFN_NO_AUTOLOAD); if (name == lv.ll_exp_name) name = NULL; } --- 3684,3690 ---- { len = (int)STRLEN(lv.ll_exp_name); name = deref_func_name(lv.ll_exp_name, &len, partial, type, ! flags & TFN_NO_AUTOLOAD, NULL); if (name == lv.ll_exp_name) name = NULL; } *************** *** 3685,3691 **** { len = (int)(end - *pp); name = deref_func_name(*pp, &len, partial, type, ! flags & TFN_NO_AUTOLOAD); if (name == *pp) name = NULL; } --- 3692,3698 ---- { len = (int)(end - *pp); name = deref_func_name(*pp, &len, partial, type, ! flags & TFN_NO_AUTOLOAD, NULL); if (name == *pp) name = NULL; } *************** *** 5004,5009 **** --- 5011,5017 ---- partial_T *partial = NULL; evalarg_T evalarg; type_T *type = NULL; + int found_var = FALSE; fill_evalarg_from_eap(&evalarg, eap, eap->skip); if (eap->skip) *************** *** 5040,5046 **** // from trans_function_name(). len = (int)STRLEN(tofree); name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial, ! in_vim9script() && type == NULL ? &type : NULL, FALSE); // Skip white space to allow ":call func ()". Not good, but required for // backward compatibility. --- 5048,5054 ---- // from trans_function_name(). len = (int)STRLEN(tofree); name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial, ! in_vim9script() && type == NULL ? &type : NULL, FALSE, &found_var); // Skip white space to allow ":call func ()". Not good, but required for // backward compatibility. *************** *** 5096,5101 **** --- 5104,5110 ---- funcexe.partial = partial; funcexe.selfdict = fudi.fd_dict; funcexe.check_type = type; + funcexe.fe_found_var = found_var; rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL) { *** ../vim-8.2.3782/src/proto/userfunc.pro 2021-12-06 15:06:49.335517805 +0000 --- src/proto/userfunc.pro 2021-12-11 16:00:54.644001292 +0000 *************** *** 4,10 **** char_u *get_lambda_name(void); char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state); int get_lambda_tv(char_u **arg, typval_T *rettv, int types_optional, evalarg_T *evalarg); ! char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, type_T **type, int no_autoload); void emsg_funcname(char *ermsg, char_u *name); int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, funcexe_T *funcexe); char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error); --- 4,10 ---- char_u *get_lambda_name(void); char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state); int get_lambda_tv(char_u **arg, typval_T *rettv, int types_optional, evalarg_T *evalarg); ! char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, type_T **type, int no_autoload, int *found_var); void emsg_funcname(char *ermsg, char_u *name); int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, funcexe_T *funcexe); char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error); *************** *** 30,36 **** int get_callback_depth(void); int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars); varnumber_T call_callback_retnr(callback_T *callback, int argcount, typval_T *argvars); ! void user_func_error(int error, char_u *name); int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe); char_u *printable_func_name(ufunc_T *fp); char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial, type_T **type); --- 30,36 ---- int get_callback_depth(void); int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars); varnumber_T call_callback_retnr(callback_T *callback, int argcount, typval_T *argvars); ! void user_func_error(int error, char_u *name, funcexe_T *funcexe); int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe); char_u *printable_func_name(ufunc_T *fp); char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial, type_T **type); *** ../vim-8.2.3782/src/structs.h 2021-12-10 13:40:05.060213928 +0000 --- src/structs.h 2021-12-11 15:58:50.743900913 +0000 *************** *** 2001,2006 **** --- 2001,2008 ---- dict_T *selfdict; // Dictionary for "self" typval_T *basetv; // base for base->method() type_T *check_type; // type from funcref or NULL + int fe_found_var; // if the function is not found then give an + // error that a variable is not callable. } funcexe_T; /* *** ../vim-8.2.3782/src/vim9execute.c 2021-12-09 14:23:40.261634977 +0000 --- src/vim9execute.c 2021-12-11 16:01:25.788016783 +0000 *************** *** 890,896 **** if (error != FCERR_NONE) { ! user_func_error(error, ufunc->uf_name); return FAIL; } if (did_emsg > did_emsg_before) --- 890,896 ---- if (error != FCERR_NONE) { ! user_func_error(error, ufunc->uf_name, &funcexe); return FAIL; } if (did_emsg > did_emsg_before) *************** *** 2343,2349 **** long n = 0; char_u *s = NULL; char *msg; ! callback_T cb = {NULL, NULL, 0}; --ectx->ec_stack.ga_len; tv = STACK_TV_BOT(0); --- 2343,2350 ---- long n = 0; char_u *s = NULL; char *msg; ! char_u numbuf[NUMBUFLEN]; ! char_u *tofree = NULL; --ectx->ec_stack.ga_len; tv = STACK_TV_BOT(0); *************** *** 2356,2383 **** else if (iptr->isn_type == ISN_STOREFUNCOPT) { SOURCING_LNUM = iptr->isn_lnum; ! cb = get_callback(tv); ! if (cb.cb_name == NULL || *cb.cb_name == NUL) { clear_tv(tv); - free_callback(&cb); goto on_error; } - s = cb.cb_name; } else // must be VAR_NUMBER, CHECKTYPE makes sure n = tv->vval.v_number; msg = set_option_value(opt_name, n, s, opt_flags); clear_tv(tv); if (msg != NULL) { SOURCING_LNUM = iptr->isn_lnum; emsg(_(msg)); goto on_error; } - if (cb.cb_name != NULL) - free_callback(&cb); } break; --- 2357,2385 ---- else if (iptr->isn_type == ISN_STOREFUNCOPT) { SOURCING_LNUM = iptr->isn_lnum; ! // If the option can be set to a function reference or ! // a lambda and the passed value is a function ! // reference, then convert it to the name (string) of ! // the function reference. ! s = tv2string(tv, &tofree, numbuf, 0); ! if (s == NULL || *s == NUL) { clear_tv(tv); goto on_error; } } else // must be VAR_NUMBER, CHECKTYPE makes sure n = tv->vval.v_number; msg = set_option_value(opt_name, n, s, opt_flags); clear_tv(tv); + vim_free(tofree); if (msg != NULL) { SOURCING_LNUM = iptr->isn_lnum; emsg(_(msg)); goto on_error; } } break; *** ../vim-8.2.3782/src/testdir/test_functions.vim 2021-12-09 16:40:14.541024052 +0000 --- src/testdir/test_functions.vim 2021-12-11 16:08:25.003959665 +0000 *************** *** 2234,2239 **** --- 2234,2245 ---- call call(test_null_partial(), []) call assert_fails('call test_null_function()()', 'E1192:') call assert_fails('call test_null_partial()()', 'E117:') + + let lines =<< trim END + let Time = 'localtime' + call Time() + END + CheckScriptFailure(lines, 'E1085:') endfunc func Test_char2nr() *** ../vim-8.2.3782/src/testdir/test_vim9_script.vim 2021-12-11 13:54:43.123245009 +0000 --- src/testdir/test_vim9_script.vim 2021-12-11 16:09:41.655910979 +0000 *************** *** 1922,1927 **** --- 1922,1936 ---- CheckDefAndScriptFailure(lines, 'E1207:', 2) enddef + def Test_vim9script_call_wrong_type() + var lines =<< trim END + vim9script + var Time = 'localtime' + Time() + END + CheckScriptFailure(lines, 'E1085:') + enddef + def s:RetSome(): string return 'some' enddef *** ../vim-8.2.3782/src/testdir/test_vim9_func.vim 2021-12-10 10:37:30.855830802 +0000 --- src/testdir/test_vim9_func.vim 2021-12-11 16:11:48.911813318 +0000 *************** *** 1459,1465 **** def Test_call_funcref() g:SomeFunc('abc')->assert_equal(3) assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call ! assert_fails('g:NotAFunc()', 'E117:', '', 3, 'Test_call_funcref') var lines =<< trim END vim9script --- 1459,1465 ---- def Test_call_funcref() g:SomeFunc('abc')->assert_equal(3) assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call ! assert_fails('g:NotAFunc()', 'E1085:', '', 3, 'Test_call_funcref') var lines =<< trim END vim9script *** ../vim-8.2.3782/src/version.c 2021-12-11 13:54:43.123245009 +0000 --- src/version.c 2021-12-11 16:12:53.703756731 +0000 *************** *** 755,756 **** --- 755,758 ---- { /* Add new patch number below this line */ + /**/ + 3783, /**/ -- How To Keep A Healthy Level Of Insanity: 8. Don't use any punctuation marks. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///