mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.3783: confusing error for using a variable as a function
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)
This commit is contained in:
parent
052ff291d7
commit
2ef9156b42
@ -1988,6 +1988,7 @@ eval_func(
|
|||||||
partial_T *partial;
|
partial_T *partial;
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
type_T *type = NULL;
|
type_T *type = NULL;
|
||||||
|
int found_var = FALSE;
|
||||||
|
|
||||||
if (!evaluate)
|
if (!evaluate)
|
||||||
check_vars(s, len);
|
check_vars(s, len);
|
||||||
@ -1995,7 +1996,7 @@ eval_func(
|
|||||||
// If "s" is the name of a variable of type VAR_FUNC
|
// If "s" is the name of a variable of type VAR_FUNC
|
||||||
// use its contents.
|
// use its contents.
|
||||||
s = deref_func_name(s, &len, &partial,
|
s = deref_func_name(s, &len, &partial,
|
||||||
in_vim9script() ? &type : NULL, !evaluate);
|
in_vim9script() ? &type : NULL, !evaluate, &found_var);
|
||||||
|
|
||||||
// Need to make a copy, in case evaluating the arguments makes
|
// Need to make a copy, in case evaluating the arguments makes
|
||||||
// the name invalid.
|
// the name invalid.
|
||||||
@ -2014,6 +2015,7 @@ eval_func(
|
|||||||
funcexe.partial = partial;
|
funcexe.partial = partial;
|
||||||
funcexe.basetv = basetv;
|
funcexe.basetv = basetv;
|
||||||
funcexe.check_type = type;
|
funcexe.check_type = type;
|
||||||
|
funcexe.fe_found_var = found_var;
|
||||||
ret = get_func_tv(s, len, rettv, arg, evalarg, &funcexe);
|
ret = get_func_tv(s, len, rettv, arg, evalarg, &funcexe);
|
||||||
}
|
}
|
||||||
vim_free(s);
|
vim_free(s);
|
||||||
|
@ -4,7 +4,7 @@ hashtab_T *func_tbl_get(void);
|
|||||||
char_u *get_lambda_name(void);
|
char_u *get_lambda_name(void);
|
||||||
char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state);
|
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);
|
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);
|
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);
|
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);
|
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);
|
char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error);
|
||||||
@ -30,7 +30,7 @@ int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict
|
|||||||
int get_callback_depth(void);
|
int get_callback_depth(void);
|
||||||
int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars);
|
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);
|
varnumber_T call_callback_retnr(callback_T *callback, int argcount, typval_T *argvars);
|
||||||
void user_func_error(int error, char_u *name);
|
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);
|
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 *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);
|
char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial, type_T **type);
|
||||||
|
@ -2001,6 +2001,8 @@ typedef struct {
|
|||||||
dict_T *selfdict; // Dictionary for "self"
|
dict_T *selfdict; // Dictionary for "self"
|
||||||
typval_T *basetv; // base for base->method()
|
typval_T *basetv; // base for base->method()
|
||||||
type_T *check_type; // type from funcref or NULL
|
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;
|
} funcexe_T;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2234,6 +2234,12 @@ func Test_call()
|
|||||||
call call(test_null_partial(), [])
|
call call(test_null_partial(), [])
|
||||||
call assert_fails('call test_null_function()()', 'E1192:')
|
call assert_fails('call test_null_function()()', 'E1192:')
|
||||||
call assert_fails('call test_null_partial()()', 'E117:')
|
call assert_fails('call test_null_partial()()', 'E117:')
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
let Time = 'localtime'
|
||||||
|
call Time()
|
||||||
|
END
|
||||||
|
CheckScriptFailure(lines, 'E1085:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_char2nr()
|
func Test_char2nr()
|
||||||
|
@ -1459,7 +1459,7 @@ endfunc
|
|||||||
def Test_call_funcref()
|
def Test_call_funcref()
|
||||||
g:SomeFunc('abc')->assert_equal(3)
|
g:SomeFunc('abc')->assert_equal(3)
|
||||||
assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call
|
assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call
|
||||||
assert_fails('g:NotAFunc()', 'E117:', '', 3, 'Test_call_funcref')
|
assert_fails('g:NotAFunc()', 'E1085:', '', 3, 'Test_call_funcref')
|
||||||
|
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
|
@ -1922,6 +1922,15 @@ def Test_script_var_shadows_command()
|
|||||||
CheckDefAndScriptFailure(lines, 'E1207:', 2)
|
CheckDefAndScriptFailure(lines, 'E1207:', 2)
|
||||||
enddef
|
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
|
def s:RetSome(): string
|
||||||
return 'some'
|
return 'some'
|
||||||
enddef
|
enddef
|
||||||
|
@ -1544,6 +1544,7 @@ errret:
|
|||||||
* "partialp".
|
* "partialp".
|
||||||
* If "type" is not NULL and a Vim9 script-local variable is found look up the
|
* If "type" is not NULL and a Vim9 script-local variable is found look up the
|
||||||
* type of the variable.
|
* type of the variable.
|
||||||
|
* If "found_var" is not NULL and a variable was found set it to TRUE.
|
||||||
*/
|
*/
|
||||||
char_u *
|
char_u *
|
||||||
deref_func_name(
|
deref_func_name(
|
||||||
@ -1551,7 +1552,8 @@ deref_func_name(
|
|||||||
int *lenp,
|
int *lenp,
|
||||||
partial_T **partialp,
|
partial_T **partialp,
|
||||||
type_T **type,
|
type_T **type,
|
||||||
int no_autoload)
|
int no_autoload,
|
||||||
|
int *found_var)
|
||||||
{
|
{
|
||||||
dictitem_T *v;
|
dictitem_T *v;
|
||||||
typval_T *tv = NULL;
|
typval_T *tv = NULL;
|
||||||
@ -1609,6 +1611,8 @@ deref_func_name(
|
|||||||
|
|
||||||
if (tv != NULL)
|
if (tv != NULL)
|
||||||
{
|
{
|
||||||
|
if (found_var != NULL)
|
||||||
|
*found_var = TRUE;
|
||||||
if (tv->v_type == VAR_FUNC)
|
if (tv->v_type == VAR_FUNC)
|
||||||
{
|
{
|
||||||
if (tv->vval.v_string == NULL)
|
if (tv->vval.v_string == NULL)
|
||||||
@ -3199,12 +3203,15 @@ call_callback_retnr(
|
|||||||
* Nothing if "error" is FCERR_NONE.
|
* Nothing if "error" is FCERR_NONE.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
user_func_error(int error, char_u *name)
|
user_func_error(int error, char_u *name, funcexe_T *funcexe)
|
||||||
{
|
{
|
||||||
switch (error)
|
switch (error)
|
||||||
{
|
{
|
||||||
case FCERR_UNKNOWN:
|
case FCERR_UNKNOWN:
|
||||||
emsg_funcname(e_unknownfunc, name);
|
if (funcexe->fe_found_var)
|
||||||
|
semsg(_(e_not_callable_type_str), name);
|
||||||
|
else
|
||||||
|
emsg_funcname(e_unknownfunc, name);
|
||||||
break;
|
break;
|
||||||
case FCERR_NOTMETHOD:
|
case FCERR_NOTMETHOD:
|
||||||
emsg_funcname(
|
emsg_funcname(
|
||||||
@ -3448,7 +3455,7 @@ theend:
|
|||||||
*/
|
*/
|
||||||
if (!aborting())
|
if (!aborting())
|
||||||
{
|
{
|
||||||
user_func_error(error, (name != NULL) ? name : funcname);
|
user_func_error(error, (name != NULL) ? name : funcname, funcexe);
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the copies made from the partial
|
// clear the copies made from the partial
|
||||||
@ -3677,7 +3684,7 @@ trans_function_name(
|
|||||||
{
|
{
|
||||||
len = (int)STRLEN(lv.ll_exp_name);
|
len = (int)STRLEN(lv.ll_exp_name);
|
||||||
name = deref_func_name(lv.ll_exp_name, &len, partial, type,
|
name = deref_func_name(lv.ll_exp_name, &len, partial, type,
|
||||||
flags & TFN_NO_AUTOLOAD);
|
flags & TFN_NO_AUTOLOAD, NULL);
|
||||||
if (name == lv.ll_exp_name)
|
if (name == lv.ll_exp_name)
|
||||||
name = NULL;
|
name = NULL;
|
||||||
}
|
}
|
||||||
@ -3685,7 +3692,7 @@ trans_function_name(
|
|||||||
{
|
{
|
||||||
len = (int)(end - *pp);
|
len = (int)(end - *pp);
|
||||||
name = deref_func_name(*pp, &len, partial, type,
|
name = deref_func_name(*pp, &len, partial, type,
|
||||||
flags & TFN_NO_AUTOLOAD);
|
flags & TFN_NO_AUTOLOAD, NULL);
|
||||||
if (name == *pp)
|
if (name == *pp)
|
||||||
name = NULL;
|
name = NULL;
|
||||||
}
|
}
|
||||||
@ -5004,6 +5011,7 @@ ex_call(exarg_T *eap)
|
|||||||
partial_T *partial = NULL;
|
partial_T *partial = NULL;
|
||||||
evalarg_T evalarg;
|
evalarg_T evalarg;
|
||||||
type_T *type = NULL;
|
type_T *type = NULL;
|
||||||
|
int found_var = FALSE;
|
||||||
|
|
||||||
fill_evalarg_from_eap(&evalarg, eap, eap->skip);
|
fill_evalarg_from_eap(&evalarg, eap, eap->skip);
|
||||||
if (eap->skip)
|
if (eap->skip)
|
||||||
@ -5040,7 +5048,7 @@ ex_call(exarg_T *eap)
|
|||||||
// from trans_function_name().
|
// from trans_function_name().
|
||||||
len = (int)STRLEN(tofree);
|
len = (int)STRLEN(tofree);
|
||||||
name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial,
|
name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial,
|
||||||
in_vim9script() && type == NULL ? &type : NULL, FALSE);
|
in_vim9script() && type == NULL ? &type : NULL, FALSE, &found_var);
|
||||||
|
|
||||||
// Skip white space to allow ":call func ()". Not good, but required for
|
// Skip white space to allow ":call func ()". Not good, but required for
|
||||||
// backward compatibility.
|
// backward compatibility.
|
||||||
@ -5096,6 +5104,7 @@ ex_call(exarg_T *eap)
|
|||||||
funcexe.partial = partial;
|
funcexe.partial = partial;
|
||||||
funcexe.selfdict = fudi.fd_dict;
|
funcexe.selfdict = fudi.fd_dict;
|
||||||
funcexe.check_type = type;
|
funcexe.check_type = type;
|
||||||
|
funcexe.fe_found_var = found_var;
|
||||||
rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this
|
rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this
|
||||||
if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL)
|
if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL)
|
||||||
{
|
{
|
||||||
|
@ -753,6 +753,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3783,
|
||||||
/**/
|
/**/
|
||||||
3782,
|
3782,
|
||||||
/**/
|
/**/
|
||||||
|
@ -890,7 +890,7 @@ call_ufunc(
|
|||||||
|
|
||||||
if (error != FCERR_NONE)
|
if (error != FCERR_NONE)
|
||||||
{
|
{
|
||||||
user_func_error(error, ufunc->uf_name);
|
user_func_error(error, ufunc->uf_name, &funcexe);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
if (did_emsg > did_emsg_before)
|
if (did_emsg > did_emsg_before)
|
||||||
@ -2343,7 +2343,8 @@ exec_instructions(ectx_T *ectx)
|
|||||||
long n = 0;
|
long n = 0;
|
||||||
char_u *s = NULL;
|
char_u *s = NULL;
|
||||||
char *msg;
|
char *msg;
|
||||||
callback_T cb = {NULL, NULL, 0};
|
char_u numbuf[NUMBUFLEN];
|
||||||
|
char_u *tofree = NULL;
|
||||||
|
|
||||||
--ectx->ec_stack.ga_len;
|
--ectx->ec_stack.ga_len;
|
||||||
tv = STACK_TV_BOT(0);
|
tv = STACK_TV_BOT(0);
|
||||||
@ -2356,28 +2357,29 @@ exec_instructions(ectx_T *ectx)
|
|||||||
else if (iptr->isn_type == ISN_STOREFUNCOPT)
|
else if (iptr->isn_type == ISN_STOREFUNCOPT)
|
||||||
{
|
{
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
cb = get_callback(tv);
|
// If the option can be set to a function reference or
|
||||||
if (cb.cb_name == NULL || *cb.cb_name == NUL)
|
// 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);
|
clear_tv(tv);
|
||||||
free_callback(&cb);
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
s = cb.cb_name;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// must be VAR_NUMBER, CHECKTYPE makes sure
|
// must be VAR_NUMBER, CHECKTYPE makes sure
|
||||||
n = tv->vval.v_number;
|
n = tv->vval.v_number;
|
||||||
msg = set_option_value(opt_name, n, s, opt_flags);
|
msg = set_option_value(opt_name, n, s, opt_flags);
|
||||||
clear_tv(tv);
|
clear_tv(tv);
|
||||||
|
vim_free(tofree);
|
||||||
if (msg != NULL)
|
if (msg != NULL)
|
||||||
{
|
{
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
emsg(_(msg));
|
emsg(_(msg));
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
if (cb.cb_name != NULL)
|
|
||||||
free_callback(&cb);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user