summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErnie Rael <errael@raelity.com>2023-12-14 20:11:44 +0100
committerChristian Brabandt <cb@256bit.org>2023-12-14 20:14:13 +0100
commitb077b58809f6bd1078f409829cc1964b8475f9fc (patch)
tree107b60d5e8ef6e8f0471de02f281dbc7e510a919
parent9a775b4a2ae658e61f9d6582de72ea7a1b241aaa (diff)
patch 9.0.2164: Vim9: can use type a func arg/return valuev9.0.2164
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>
-rw-r--r--src/proto/userfunc.pro2
-rw-r--r--src/testdir/test_vim9_assign.vim4
-rw-r--r--src/testdir/test_vim9_class.vim2
-rw-r--r--src/testdir/test_vim9_typealias.vim234
-rw-r--r--src/userfunc.c20
-rw-r--r--src/version.c2
-rw-r--r--src/vim9class.c2
-rw-r--r--src/vim9cmds.c2
-rw-r--r--src/vim9execute.c9
-rw-r--r--src/vim9instr.c4
10 files changed, 271 insertions, 10 deletions
diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro
index 7b4129b470..e393c04707 100644
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -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);
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);
-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);
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);
diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim
index 38504f1af9..d582000be1 100644
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -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(ch)', 'E1013: Argument 1: type mismatch, expected number but got channel')
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>')
# 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)
endif
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
v9.CheckSourceFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got object<A>', 2)
enddef
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 5a9b0f8884..6f9723dfae 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -4149,7 +4149,7 @@ def Test_lockvar_argument()
Lock2(C)
END
- v9.CheckSourceSuccess(lines)
+ v9.CheckSourceFailure(lines, 'E1405: Class "C" cannot be used as a value')
# Lock an object.
lines =<< trim END
diff --git a/src/testdir/test_vim9_typealias.vim b/src/testdir/test_vim9_typealias.vim
index 11aa47aa63..8843cb5d1a 100644
--- a/src/testdir/test_vim9_typealias.vim
+++ b/src/testdir/test_vim9_typealias.vim
@@ -546,4 +546,238 @@ def Test_typealias_class()
v9.CheckScriptSuccess(lines)
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
diff --git a/src/userfunc.c b/src/userfunc.c
index 410658b1ea..1580a37c7a 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -1905,7 +1905,8 @@ get_func_arguments(
evalarg_T *evalarg,
int partial_argc,
typval_T *argvars,
- int *argcount)
+ int *argcount,
+ int is_builtin)
{
char_u *argp = *arg;
int ret = OK;
@@ -1920,12 +1921,20 @@ get_func_arguments(
if (*argp == ')' || *argp == ',' || *argp == NUL)
break;
- if (eval1(&argp, &argvars[*argcount], evalarg) == FAIL)
+
+ int arg_idx = *argcount;
+ if (eval1(&argp, &argvars[arg_idx], evalarg) == FAIL)
{
ret = FAIL;
break;
}
++*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
// checked previously, thus only enforce it in Vim9 script.
if (vim9script)
@@ -1985,7 +1994,7 @@ get_func_tv(
argp = *arg;
ret = get_func_arguments(&argp, evalarg,
(funcexe->fe_partial == NULL ? 0 : funcexe->fe_partial->pt_argc),
- argvars, &argcount);
+ argvars, &argcount, builtin_function(name, -1));
if (ret == OK)
{
@@ -6125,8 +6134,9 @@ ex_defer_inner(
copy_tv(&partial->pt_argv[i], &argvars[i]);
}
}
+ int is_builtin = builtin_function(name, -1);
r = get_func_arguments(arg, evalarg, FALSE,
- argvars + partial_argc, &argcount);
+ argvars + partial_argc, &argcount, is_builtin);
argcount += partial_argc;
if (r == OK)
@@ -6136,7 +6146,7 @@ ex_defer_inner(
// Check that the arguments are OK for the types of the funcref.
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);
diff --git a/src/version.c b/src/version.c
index a4b4edfdc2..6424f7fa9e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2164,
+/**/
2163,
/**/
2162,
diff --git a/src/vim9class.c b/src/vim9class.c
index 2c5e1dffa3..b19f8c96f2 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -2342,7 +2342,7 @@ call_oc_method(
}
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)
return FAIL;
diff --git a/src/vim9cmds.c b/src/vim9cmds.c
index 92605cff32..392bab4120 100644
--- a/src/vim9cmds.c
+++ b/src/vim9cmds.c
@@ -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
// return type here.
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
|| cctx->ctx_ufunc->uf_ret_type == &t_unknown))
|| (!check_return_type
diff --git a/src/vim9execute.c b/src/vim9execute.c
index d357fc42c5..882b13c61a 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -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
&& argv[i].vval.v_number == VVAL_NONE)
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)
type = ufunc->uf_arg_types[i];
@@ -4462,6 +4465,12 @@ exec_instructions(ectx_T *ectx)
garray_T *trystack = &ectx->ec_trystack;
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)
trycmd = ((trycmd_T *)trystack->ga_data)
+ trystack->ga_len - 1;
diff --git a/src/vim9instr.c b/src/vim9instr.c
index 12c83df9b8..b7cad7656b 100644
--- a/src/vim9instr.c
+++ b/src/vim9instr.c
@@ -1821,6 +1821,8 @@ generate_CALL(
type_T *actual;
actual = get_type_on_stack(cctx, argcount - i - 1);
+ if (check_type_is_value(actual) == FAIL)
+ return FAIL;
if (actual->tt_type == VAR_SPECIAL
&& 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 *expected;
+ if (check_type_is_value(actual) == FAIL)
+ return FAIL;
if (varargs && i >= type->tt_argcount - 1)
{
expected = type->tt_args[type->tt_argcount - 1];