forked from aniani/vim
patch 9.0.2164: Vim9: can use type a func arg/return value
Problem: Vim9: can use type a func arg/return value Solution: Check if using type as function argument or return value closes: #13675 Signed-off-by: Ernie Rael <errael@raelity.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
9a775b4a2a
commit
b077b58809
@ -7,7 +7,7 @@ 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, int new_function, int *found_var);
|
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, type_T **type, int no_autoload, int new_function, int *found_var);
|
||||||
void emsg_funcname(char *ermsg, char_u *name);
|
void emsg_funcname(char *ermsg, char_u *name);
|
||||||
int get_func_arguments(char_u **arg, evalarg_T *evalarg, int partial_argc, typval_T *argvars, int *argcount);
|
int get_func_arguments(char_u **arg, evalarg_T *evalarg, int partial_argc, typval_T *argvars, int *argcount, int is_builtin);
|
||||||
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, funcerror_T *error);
|
char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, funcerror_T *error);
|
||||||
void func_name_with_sid(char_u *name, int sid, char_u *buffer);
|
void func_name_with_sid(char_u *name, int sid, char_u *buffer);
|
||||||
|
@ -3197,7 +3197,7 @@ def Test_func_argtype_check()
|
|||||||
assert_fails('IntArg(j)', 'E1013: Argument 1: type mismatch, expected number but got job')
|
assert_fails('IntArg(j)', 'E1013: Argument 1: type mismatch, expected number but got job')
|
||||||
assert_fails('IntArg(ch)', 'E1013: Argument 1: type mismatch, expected number but got channel')
|
assert_fails('IntArg(ch)', 'E1013: Argument 1: type mismatch, expected number but got channel')
|
||||||
endif
|
endif
|
||||||
assert_fails('IntArg(A)', 'E1013: Argument 1: type mismatch, expected number but got class<A>')
|
assert_fails('IntArg(A)', 'E1405: Class "A" cannot be used as a value')
|
||||||
assert_fails('IntArg(o)', 'E1013: Argument 1: type mismatch, expected number but got object<A>')
|
assert_fails('IntArg(o)', 'E1013: Argument 1: type mismatch, expected number but got object<A>')
|
||||||
|
|
||||||
# Passing a number to functions accepting different argument types
|
# Passing a number to functions accepting different argument types
|
||||||
@ -3262,7 +3262,7 @@ def Test_func_argtype_check()
|
|||||||
v9.CheckSourceFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got channel', 2)
|
v9.CheckSourceFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got channel', 2)
|
||||||
endif
|
endif
|
||||||
lines = pre_lines + ['IntArg(A)'] + post_lines
|
lines = pre_lines + ['IntArg(A)'] + post_lines
|
||||||
v9.CheckSourceFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got class<A>', 1)
|
v9.CheckSourceFailure(lines, 'E1405: Class "A" cannot be used as a value', 1)
|
||||||
lines = pre_lines + ['var o: A = A.new()', 'IntArg(o)'] + post_lines
|
lines = pre_lines + ['var o: A = A.new()', 'IntArg(o)'] + post_lines
|
||||||
v9.CheckSourceFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got object<A>', 2)
|
v9.CheckSourceFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got object<A>', 2)
|
||||||
enddef
|
enddef
|
||||||
|
@ -4149,7 +4149,7 @@ def Test_lockvar_argument()
|
|||||||
|
|
||||||
Lock2(C)
|
Lock2(C)
|
||||||
END
|
END
|
||||||
v9.CheckSourceSuccess(lines)
|
v9.CheckSourceFailure(lines, 'E1405: Class "C" cannot be used as a value')
|
||||||
|
|
||||||
# Lock an object.
|
# Lock an object.
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
|
@ -546,4 +546,238 @@ def Test_typealias_class()
|
|||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
" Test for typealias as function arg and return value
|
||||||
|
def Test_type_as_func_argument_or_return_value()
|
||||||
|
# check typealias as arg, function call in script level
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
type A = number
|
||||||
|
def Foo(arg: any)
|
||||||
|
enddef
|
||||||
|
Foo(A)
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1403: Type alias "A" cannot be used as a value', 5)
|
||||||
|
|
||||||
|
# check typealias as function return, function call in script level
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
type A = number
|
||||||
|
def Foo(): any
|
||||||
|
return A
|
||||||
|
enddef
|
||||||
|
Foo()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1)
|
||||||
|
|
||||||
|
# check typealias as arg, function call in :def
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
type A = number
|
||||||
|
def Foo(arg: any)
|
||||||
|
enddef
|
||||||
|
def F()
|
||||||
|
Foo(A)
|
||||||
|
enddef
|
||||||
|
F()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1)
|
||||||
|
|
||||||
|
# check typealias as function return, function call in :def
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
type A = number
|
||||||
|
def Foo(): any
|
||||||
|
return A
|
||||||
|
enddef
|
||||||
|
def F()
|
||||||
|
Foo()
|
||||||
|
enddef
|
||||||
|
F()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1)
|
||||||
|
|
||||||
|
# check funcref using typealias as arg at script level
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
type A = number
|
||||||
|
def F(arg: any)
|
||||||
|
echo typename(arg)
|
||||||
|
enddef
|
||||||
|
var Fref: func(any)
|
||||||
|
Fref = F
|
||||||
|
|
||||||
|
Fref(A)
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1403: Type alias "A" cannot be used as a value', 9)
|
||||||
|
|
||||||
|
# check funcref using typealias as arg in :def
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
type A = number
|
||||||
|
def F(arg: any)
|
||||||
|
echo typename(arg)
|
||||||
|
enddef
|
||||||
|
var Fref: func(any)
|
||||||
|
Fref = F
|
||||||
|
|
||||||
|
def G()
|
||||||
|
Fref(A)
|
||||||
|
enddef
|
||||||
|
G()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1)
|
||||||
|
|
||||||
|
# check funcref using typealias as return
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
type A = number
|
||||||
|
def F(): any
|
||||||
|
return A
|
||||||
|
enddef
|
||||||
|
var Fref: func(): any
|
||||||
|
Fref = F
|
||||||
|
|
||||||
|
Fref()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1)
|
||||||
|
|
||||||
|
# check defered function using typealias as arg
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
type A = number
|
||||||
|
def F(arg: any)
|
||||||
|
enddef
|
||||||
|
def G()
|
||||||
|
defer F(A)
|
||||||
|
enddef
|
||||||
|
G()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1407: Cannot use a Typealias as a variable or value', 1)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
" Test for class typealias as function arg and return value
|
||||||
|
def Test_class_as_func_argument_or_return_value()
|
||||||
|
# check class typealias as arg, function call in script level
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class C
|
||||||
|
endclass
|
||||||
|
type A = C
|
||||||
|
def Foo(arg: any)
|
||||||
|
enddef
|
||||||
|
Foo(A)
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 7)
|
||||||
|
|
||||||
|
# check class typealias as function return, function call in script level
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class C
|
||||||
|
endclass
|
||||||
|
type A = C
|
||||||
|
def Foo(): any
|
||||||
|
return A
|
||||||
|
enddef
|
||||||
|
Foo()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 1)
|
||||||
|
|
||||||
|
# check class typealias as arg, function call in :def
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class C
|
||||||
|
endclass
|
||||||
|
type A = C
|
||||||
|
def Foo(arg: any)
|
||||||
|
enddef
|
||||||
|
def F()
|
||||||
|
Foo(A)
|
||||||
|
enddef
|
||||||
|
F()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 1)
|
||||||
|
|
||||||
|
# check class typealias as function return, function call in :def
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class C
|
||||||
|
endclass
|
||||||
|
type A = C
|
||||||
|
def Foo(): any
|
||||||
|
return A
|
||||||
|
enddef
|
||||||
|
def F()
|
||||||
|
Foo()
|
||||||
|
enddef
|
||||||
|
F()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 1)
|
||||||
|
|
||||||
|
# check funcref using class typealias as arg at script level
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class C
|
||||||
|
endclass
|
||||||
|
type A = C
|
||||||
|
def F(arg: any)
|
||||||
|
echo typename(arg)
|
||||||
|
enddef
|
||||||
|
var Fref: func(any)
|
||||||
|
Fref = F
|
||||||
|
|
||||||
|
Fref(A)
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 11)
|
||||||
|
|
||||||
|
# check funcref using class typealias as arg in :def
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class C
|
||||||
|
endclass
|
||||||
|
type A = C
|
||||||
|
def F(arg: any)
|
||||||
|
echo typename(arg)
|
||||||
|
enddef
|
||||||
|
var Fref: func(any)
|
||||||
|
Fref = F
|
||||||
|
|
||||||
|
def G()
|
||||||
|
Fref(A)
|
||||||
|
enddef
|
||||||
|
G()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 1)
|
||||||
|
|
||||||
|
# check funcref using class typealias as return
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class C
|
||||||
|
endclass
|
||||||
|
type A = C
|
||||||
|
def F(): any
|
||||||
|
return A
|
||||||
|
enddef
|
||||||
|
var Fref: func(): any
|
||||||
|
Fref = F
|
||||||
|
|
||||||
|
Fref()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 1)
|
||||||
|
|
||||||
|
# check defered function using class typealias as arg
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class C
|
||||||
|
endclass
|
||||||
|
type A = C
|
||||||
|
def F(arg: any)
|
||||||
|
enddef
|
||||||
|
def G()
|
||||||
|
defer F(A)
|
||||||
|
enddef
|
||||||
|
G()
|
||||||
|
END
|
||||||
|
v9.CheckScriptFailure(lines, 'E1405: Class "C" cannot be used as a value', 1)
|
||||||
|
enddef
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@ -1905,7 +1905,8 @@ get_func_arguments(
|
|||||||
evalarg_T *evalarg,
|
evalarg_T *evalarg,
|
||||||
int partial_argc,
|
int partial_argc,
|
||||||
typval_T *argvars,
|
typval_T *argvars,
|
||||||
int *argcount)
|
int *argcount,
|
||||||
|
int is_builtin)
|
||||||
{
|
{
|
||||||
char_u *argp = *arg;
|
char_u *argp = *arg;
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
@ -1920,12 +1921,20 @@ get_func_arguments(
|
|||||||
|
|
||||||
if (*argp == ')' || *argp == ',' || *argp == NUL)
|
if (*argp == ')' || *argp == ',' || *argp == NUL)
|
||||||
break;
|
break;
|
||||||
if (eval1(&argp, &argvars[*argcount], evalarg) == FAIL)
|
|
||||||
|
int arg_idx = *argcount;
|
||||||
|
if (eval1(&argp, &argvars[arg_idx], evalarg) == FAIL)
|
||||||
{
|
{
|
||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++*argcount;
|
++*argcount;
|
||||||
|
if (!is_builtin && check_typval_is_value(&argvars[arg_idx]) == FAIL)
|
||||||
|
{
|
||||||
|
ret = FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// The comma should come right after the argument, but this wasn't
|
// The comma should come right after the argument, but this wasn't
|
||||||
// checked previously, thus only enforce it in Vim9 script.
|
// checked previously, thus only enforce it in Vim9 script.
|
||||||
if (vim9script)
|
if (vim9script)
|
||||||
@ -1985,7 +1994,7 @@ get_func_tv(
|
|||||||
argp = *arg;
|
argp = *arg;
|
||||||
ret = get_func_arguments(&argp, evalarg,
|
ret = get_func_arguments(&argp, evalarg,
|
||||||
(funcexe->fe_partial == NULL ? 0 : funcexe->fe_partial->pt_argc),
|
(funcexe->fe_partial == NULL ? 0 : funcexe->fe_partial->pt_argc),
|
||||||
argvars, &argcount);
|
argvars, &argcount, builtin_function(name, -1));
|
||||||
|
|
||||||
if (ret == OK)
|
if (ret == OK)
|
||||||
{
|
{
|
||||||
@ -6125,8 +6134,9 @@ ex_defer_inner(
|
|||||||
copy_tv(&partial->pt_argv[i], &argvars[i]);
|
copy_tv(&partial->pt_argv[i], &argvars[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int is_builtin = builtin_function(name, -1);
|
||||||
r = get_func_arguments(arg, evalarg, FALSE,
|
r = get_func_arguments(arg, evalarg, FALSE,
|
||||||
argvars + partial_argc, &argcount);
|
argvars + partial_argc, &argcount, is_builtin);
|
||||||
argcount += partial_argc;
|
argcount += partial_argc;
|
||||||
|
|
||||||
if (r == OK)
|
if (r == OK)
|
||||||
@ -6136,7 +6146,7 @@ ex_defer_inner(
|
|||||||
// Check that the arguments are OK for the types of the funcref.
|
// Check that the arguments are OK for the types of the funcref.
|
||||||
r = check_argument_types(type, argvars, argcount, NULL, name);
|
r = check_argument_types(type, argvars, argcount, NULL, name);
|
||||||
}
|
}
|
||||||
else if (builtin_function(name, -1))
|
else if (is_builtin)
|
||||||
{
|
{
|
||||||
int idx = find_internal_func(name);
|
int idx = find_internal_func(name);
|
||||||
|
|
||||||
|
@ -704,6 +704,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 */
|
||||||
|
/**/
|
||||||
|
2164,
|
||||||
/**/
|
/**/
|
||||||
2163,
|
2163,
|
||||||
/**/
|
/**/
|
||||||
|
@ -2342,7 +2342,7 @@ call_oc_method(
|
|||||||
}
|
}
|
||||||
|
|
||||||
char_u *argp = name_end;
|
char_u *argp = name_end;
|
||||||
int ret = get_func_arguments(&argp, evalarg, 0, argvars, &argcount);
|
int ret = get_func_arguments(&argp, evalarg, 0, argvars, &argcount, FALSE);
|
||||||
if (ret == FAIL)
|
if (ret == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
|
@ -2661,6 +2661,8 @@ compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx)
|
|||||||
// for an inline function without a specified return type. Set the
|
// for an inline function without a specified return type. Set the
|
||||||
// return type here.
|
// return type here.
|
||||||
stack_type = get_type_on_stack(cctx, 0);
|
stack_type = get_type_on_stack(cctx, 0);
|
||||||
|
if (check_type_is_value(stack_type) == FAIL)
|
||||||
|
return NULL;
|
||||||
if ((check_return_type && (cctx->ctx_ufunc->uf_ret_type == NULL
|
if ((check_return_type && (cctx->ctx_ufunc->uf_ret_type == NULL
|
||||||
|| cctx->ctx_ufunc->uf_ret_type == &t_unknown))
|
|| cctx->ctx_ufunc->uf_ret_type == &t_unknown))
|
||||||
|| (!check_return_type
|
|| (!check_return_type
|
||||||
|
@ -398,6 +398,9 @@ check_ufunc_arg_types(ufunc_T *ufunc, int argcount, int off, ectx_T *ectx)
|
|||||||
if (argv[i].v_type == VAR_SPECIAL
|
if (argv[i].v_type == VAR_SPECIAL
|
||||||
&& argv[i].vval.v_number == VVAL_NONE)
|
&& argv[i].vval.v_number == VVAL_NONE)
|
||||||
continue;
|
continue;
|
||||||
|
// only pass values to user functions, never types
|
||||||
|
if (check_typval_is_value(&argv[i]) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
if (i < ufunc->uf_args.ga_len && ufunc->uf_arg_types != NULL)
|
if (i < ufunc->uf_args.ga_len && ufunc->uf_arg_types != NULL)
|
||||||
type = ufunc->uf_arg_types[i];
|
type = ufunc->uf_arg_types[i];
|
||||||
@ -4462,6 +4465,12 @@ exec_instructions(ectx_T *ectx)
|
|||||||
garray_T *trystack = &ectx->ec_trystack;
|
garray_T *trystack = &ectx->ec_trystack;
|
||||||
trycmd_T *trycmd = NULL;
|
trycmd_T *trycmd = NULL;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// TODO: If FAIL, line number in output not correct
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
if (check_typval_is_value(STACK_TV_BOT(-1)) == FAIL)
|
||||||
|
goto theend;
|
||||||
|
|
||||||
if (trystack->ga_len > 0)
|
if (trystack->ga_len > 0)
|
||||||
trycmd = ((trycmd_T *)trystack->ga_data)
|
trycmd = ((trycmd_T *)trystack->ga_data)
|
||||||
+ trystack->ga_len - 1;
|
+ trystack->ga_len - 1;
|
||||||
|
@ -1821,6 +1821,8 @@ generate_CALL(
|
|||||||
type_T *actual;
|
type_T *actual;
|
||||||
|
|
||||||
actual = get_type_on_stack(cctx, argcount - i - 1);
|
actual = get_type_on_stack(cctx, argcount - i - 1);
|
||||||
|
if (check_type_is_value(actual) == FAIL)
|
||||||
|
return FAIL;
|
||||||
if (actual->tt_type == VAR_SPECIAL
|
if (actual->tt_type == VAR_SPECIAL
|
||||||
&& i >= regular_args - ufunc->uf_def_args.ga_len)
|
&& i >= regular_args - ufunc->uf_def_args.ga_len)
|
||||||
{
|
{
|
||||||
@ -1960,6 +1962,8 @@ check_func_args_from_type(
|
|||||||
type_T *actual = get_type_on_stack(cctx, -1 - offset);
|
type_T *actual = get_type_on_stack(cctx, -1 - offset);
|
||||||
type_T *expected;
|
type_T *expected;
|
||||||
|
|
||||||
|
if (check_type_is_value(actual) == FAIL)
|
||||||
|
return FAIL;
|
||||||
if (varargs && i >= type->tt_argcount - 1)
|
if (varargs && i >= type->tt_argcount - 1)
|
||||||
{
|
{
|
||||||
expected = type->tt_args[type->tt_argcount - 1];
|
expected = type->tt_args[type->tt_argcount - 1];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user