Skip to content

Commit 351ead0

Browse files
committed
patch 8.2.2362: Vim9: check of builtin function argument type is incomplete
Problem: Vim9: check of builtin function argument type is incomplete. Solution: Use need_type() instead of check_arg_type().
1 parent 7c886db commit 351ead0

8 files changed

Lines changed: 63 additions & 44 deletions

File tree

src/evalfunc.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,13 +275,30 @@ typedef struct {
275275
int arg_count; // actual argument count
276276
type_T **arg_types; // list of argument types
277277
int arg_idx; // current argument index (first arg is zero)
278+
cctx_T *arg_cctx;
278279
} argcontext_T;
279280

280281
// A function to check one argument type. The first argument is the type to
281282
// check. If needed, other argument types can be obtained with the context.
282283
// E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
283284
typedef int (*argcheck_T)(type_T *, argcontext_T *);
284285

286+
/*
287+
* Call need_type() to check an argument type.
288+
*/
289+
static int
290+
check_arg_type(
291+
type_T *expected,
292+
type_T *actual,
293+
argcontext_T *context)
294+
{
295+
// TODO: would be useful to know if "actual" is a constant and pass it to
296+
// need_type() to get a compile time error if possible.
297+
return need_type(actual, expected,
298+
context->arg_idx - context->arg_count, context->arg_idx + 1,
299+
context->arg_cctx, FALSE, FALSE);
300+
}
301+
285302
/*
286303
* Check "type" is a float or a number.
287304
*/
@@ -301,7 +318,7 @@ arg_float_or_nr(type_T *type, argcontext_T *context)
301318
static int
302319
arg_number(type_T *type, argcontext_T *context)
303320
{
304-
return check_arg_type(&t_number, type, context->arg_idx + 1);
321+
return check_arg_type(&t_number, type, context);
305322
}
306323

307324
/*
@@ -310,7 +327,7 @@ arg_number(type_T *type, argcontext_T *context)
310327
static int
311328
arg_string(type_T *type, argcontext_T *context)
312329
{
313-
return check_arg_type(&t_string, type, context->arg_idx + 1);
330+
return check_arg_type(&t_string, type, context);
314331
}
315332

316333
/*
@@ -348,7 +365,7 @@ arg_same_as_prev(type_T *type, argcontext_T *context)
348365
{
349366
type_T *prev_type = context->arg_types[context->arg_idx - 1];
350367

351-
return check_arg_type(prev_type, type, context->arg_idx + 1);
368+
return check_arg_type(prev_type, type, context);
352369
}
353370

354371
/*
@@ -362,7 +379,7 @@ arg_same_struct_as_prev(type_T *type, argcontext_T *context)
362379
type_T *prev_type = context->arg_types[context->arg_idx - 1];
363380

364381
if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type)
365-
return check_arg_type(prev_type, type, context->arg_idx + 1);
382+
return check_arg_type(prev_type, type, context);
366383
return OK;
367384
}
368385

@@ -384,7 +401,7 @@ arg_item_of_prev(type_T *type, argcontext_T *context)
384401
// probably VAR_ANY, can't check
385402
return OK;
386403

387-
return check_arg_type(expected, type, context->arg_idx + 1);
404+
return check_arg_type(expected, type, context);
388405
}
389406

390407
/*
@@ -1931,7 +1948,11 @@ internal_func_name(int idx)
19311948
* Return FAIL and gives an error message when a type is wrong.
19321949
*/
19331950
int
1934-
internal_func_check_arg_types(type_T **types, int idx, int argcount)
1951+
internal_func_check_arg_types(
1952+
type_T **types,
1953+
int idx,
1954+
int argcount,
1955+
cctx_T *cctx)
19351956
{
19361957
argcheck_T *argchecks = global_functions[idx].f_argcheck;
19371958
int i;
@@ -1942,6 +1963,7 @@ internal_func_check_arg_types(type_T **types, int idx, int argcount)
19421963

19431964
context.arg_count = argcount;
19441965
context.arg_types = types;
1966+
context.arg_cctx = cctx;
19451967
for (i = 0; i < argcount; ++i)
19461968
if (argchecks[i] != NULL)
19471969
{

src/proto/evalfunc.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ char_u *get_expr_name(expand_T *xp, int idx);
44
int find_internal_func(char_u *name);
55
int has_internal_func(char_u *name);
66
char *internal_func_name(int idx);
7-
int internal_func_check_arg_types(type_T **types, int idx, int argcount);
7+
int internal_func_check_arg_types(type_T **types, int idx, int argcount, cctx_T *cctx);
88
type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes);
99
int internal_func_is_map(int idx);
1010
int check_internal_func(int idx, int argcount);

src/proto/vim9compile.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
int check_defined(char_u *p, size_t len, cctx_T *cctx);
33
int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2);
44
int use_typecheck(type_T *actual, type_T *expected);
5+
int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, cctx_T *cctx, int silent, int actual_is_const);
56
int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx);
67
imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
78
imported_T *find_imported_in_script(char_u *name, size_t len, int sid);

src/proto/vim9type.pro

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ int check_typval_type(type_T *expected, typval_T *actual_tv, int argidx);
1515
void type_mismatch(type_T *expected, type_T *actual);
1616
void arg_type_mismatch(type_T *expected, type_T *actual, int argidx);
1717
int check_type(type_T *expected, type_T *actual, int give_msg, int argidx);
18-
int check_arg_type(type_T *expected, type_T *actual, int argidx);
1918
int check_argument_types(type_T *type, typval_T *argvars, int argcount, char_u *name);
2019
char_u *skip_type(char_u *start, int optional);
2120
type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error);

src/testdir/test_vim9_builtin.vim

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ def Test_extend_arg_types()
241241
CheckDefFailure(['extend({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict<number> but got number')
242242
CheckDefFailure(['extend({a: 1}, {b: "x"})'], 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>')
243243
CheckDefFailure(['extend({a: 1}, {b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number')
244+
245+
CheckDefFailure(['extend([1], ["b"])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>')
246+
CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1012: Type mismatch; expected list<number> but got list<any>')
244247
enddef
245248

246249
def Test_extendnew()

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2362,
753755
/**/
754756
2361,
755757
/**/

src/vim9compile.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -878,11 +878,12 @@ use_typecheck(type_T *actual, type_T *expected)
878878
* If "actual_is_const" is TRUE then the type won't change at runtime, do not
879879
* generate a TYPECHECK.
880880
*/
881-
static int
881+
int
882882
need_type(
883883
type_T *actual,
884884
type_T *expected,
885885
int offset,
886+
int arg_idx,
886887
cctx_T *cctx,
887888
int silent,
888889
int actual_is_const)
@@ -896,7 +897,7 @@ need_type(
896897
return OK;
897898
}
898899

899-
if (check_type(expected, actual, FALSE, 0) == OK)
900+
if (check_type(expected, actual, FALSE, arg_idx) == OK)
900901
return OK;
901902

902903
// If the actual type can be the expected type add a runtime check.
@@ -908,7 +909,7 @@ need_type(
908909
}
909910

910911
if (!silent)
911-
type_mismatch(expected, actual);
912+
arg_type_mismatch(expected, actual, arg_idx);
912913
return FAIL;
913914
}
914915

@@ -931,7 +932,7 @@ bool_on_stack(cctx_T *cctx)
931932
// This requires a runtime type check.
932933
return generate_COND2BOOL(cctx);
933934

934-
return need_type(type, &t_bool, -1, cctx, FALSE, FALSE);
935+
return need_type(type, &t_bool, -1, 0, cctx, FALSE, FALSE);
935936
}
936937

937938
/*
@@ -1613,7 +1614,8 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
16131614
{
16141615
// Check the types of the arguments.
16151616
argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
1616-
if (internal_func_check_arg_types(argtypes, func_idx, argcount) == FAIL)
1617+
if (internal_func_check_arg_types(argtypes, func_idx, argcount,
1618+
cctx) == FAIL)
16171619
return FAIL;
16181620
if (internal_func_is_map(func_idx))
16191621
maptype = *argtypes;
@@ -1656,7 +1658,7 @@ generate_LISTAPPEND(cctx_T *cctx)
16561658
list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
16571659
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
16581660
expected = list_type->tt_member;
1659-
if (need_type(item_type, expected, -1, cctx, FALSE, FALSE) == FAIL)
1661+
if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL)
16601662
return FAIL;
16611663

16621664
if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
@@ -1678,7 +1680,7 @@ generate_BLOBAPPEND(cctx_T *cctx)
16781680

16791681
// Caller already checked that blob_type is a blob.
16801682
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
1681-
if (need_type(item_type, &t_number, -1, cctx, FALSE, FALSE) == FAIL)
1683+
if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
16821684
return FAIL;
16831685

16841686
if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
@@ -1733,7 +1735,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
17331735
else
17341736
expected = ufunc->uf_va_type->tt_member;
17351737
actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
1736-
if (need_type(actual, expected, -argcount + i, cctx,
1738+
if (need_type(actual, expected, -argcount + i, 0, cctx,
17371739
TRUE, FALSE) == FAIL)
17381740
{
17391741
arg_type_mismatch(expected, actual, i + 1);
@@ -1850,7 +1852,7 @@ generate_PCALL(
18501852
type->tt_argcount - 1]->tt_member;
18511853
else
18521854
expected = type->tt_args[i];
1853-
if (need_type(actual, expected, offset,
1855+
if (need_type(actual, expected, offset, 0,
18541856
cctx, TRUE, FALSE) == FAIL)
18551857
{
18561858
arg_type_mismatch(expected, actual, i + 1);
@@ -3135,7 +3137,7 @@ compile_dict(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
31353137
{
31363138
type_T *keytype = ((type_T **)stack->ga_data)
31373139
[stack->ga_len - 1];
3138-
if (need_type(keytype, &t_string, -1, cctx,
3140+
if (need_type(keytype, &t_string, -1, 0, cctx,
31393141
FALSE, FALSE) == FAIL)
31403142
return FAIL;
31413143
}
@@ -3808,13 +3810,13 @@ compile_subscript(
38083810
vtype = VAR_DICT;
38093811
if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
38103812
{
3811-
if (need_type(valtype, &t_number, -1, cctx,
3813+
if (need_type(valtype, &t_number, -1, 0, cctx,
38123814
FALSE, FALSE) == FAIL)
38133815
return FAIL;
38143816
if (is_slice)
38153817
{
38163818
valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
3817-
if (need_type(valtype, &t_number, -2, cctx,
3819+
if (need_type(valtype, &t_number, -2, 0, cctx,
38183820
FALSE, FALSE) == FAIL)
38193821
return FAIL;
38203822
}
@@ -3836,7 +3838,7 @@ compile_subscript(
38363838
}
38373839
else
38383840
{
3839-
if (need_type(*typep, &t_dict_any, -2, cctx,
3841+
if (need_type(*typep, &t_dict_any, -2, 0, cctx,
38403842
FALSE, FALSE) == FAIL)
38413843
return FAIL;
38423844
*typep = &t_any;
@@ -4235,7 +4237,7 @@ compile_expr7t(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
42354237
actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
42364238
if (check_type(want_type, actual, FALSE, 0) == FAIL)
42374239
{
4238-
if (need_type(actual, want_type, -1, cctx, FALSE, FALSE) == FAIL)
4240+
if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE) == FAIL)
42394241
return FAIL;
42404242
}
42414243
}
@@ -4917,7 +4919,7 @@ compile_return(char_u *arg, int check_return_type, cctx_T *cctx)
49174919
return NULL;
49184920
}
49194921
if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, -1,
4920-
cctx, FALSE, FALSE) == FAIL)
4922+
0, cctx, FALSE, FALSE) == FAIL)
49214923
return NULL;
49224924
}
49234925
}
@@ -5831,7 +5833,7 @@ compile_assign_unlet(
58315833
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
58325834
// now we can properly check the type
58335835
if (lhs->lhs_type->tt_member != NULL && rhs_type != &t_void
5834-
&& need_type(rhs_type, lhs->lhs_type->tt_member, -2, cctx,
5836+
&& need_type(rhs_type, lhs->lhs_type->tt_member, -2, 0, cctx,
58355837
FALSE, FALSE) == FAIL)
58365838
return FAIL;
58375839
}
@@ -5976,7 +5978,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
59765978
emsg(_(e_cannot_use_void_value));
59775979
goto theend;
59785980
}
5979-
if (need_type(stacktype, &t_list_any, -1, cctx,
5981+
if (need_type(stacktype, &t_list_any, -1, 0, cctx,
59805982
FALSE, FALSE) == FAIL)
59815983
goto theend;
59825984
// TODO: check the length of a constant list here
@@ -6123,13 +6125,13 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
61236125
// without operator check type here, otherwise below
61246126
if (lhs.lhs_has_index)
61256127
use_type = lhs.lhs_member_type;
6126-
if (need_type(rhs_type, use_type, -1, cctx,
6128+
if (need_type(rhs_type, use_type, -1, 0, cctx,
61276129
FALSE, is_const) == FAIL)
61286130
goto theend;
61296131
}
61306132
}
61316133
else if (*p != '=' && need_type(rhs_type, lhs.lhs_member_type,
6132-
-1, cctx, FALSE, FALSE) == FAIL)
6134+
-1, 0, cctx, FALSE, FALSE) == FAIL)
61336135
goto theend;
61346136
}
61356137
else if (cmdidx == CMD_final)
@@ -6216,7 +6218,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
62166218
// If variable is float operation with number is OK.
62176219
!(expected == &t_float && stacktype == &t_number) &&
62186220
#endif
6219-
need_type(stacktype, expected, -1, cctx,
6221+
need_type(stacktype, expected, -1, 0, cctx,
62206222
FALSE, FALSE) == FAIL)
62216223
goto theend;
62226224

@@ -6925,7 +6927,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
69256927
// Now that we know the type of "var", check that it is a list, now or at
69266928
// runtime.
69276929
vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
6928-
if (need_type(vartype, &t_list_any, -1, cctx, FALSE, FALSE) == FAIL)
6930+
if (need_type(vartype, &t_list_any, -1, 0, cctx, FALSE, FALSE) == FAIL)
69296931
{
69306932
drop_scope(cctx);
69316933
return NULL;

src/vim9type.c

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -513,26 +513,16 @@ check_type(type_T *expected, type_T *actual, int give_msg, int argidx)
513513
return ret;
514514
}
515515

516-
/*
517-
* Like check_type() but also allow for a runtime type check. E.g. "any" can be
518-
* used for "number".
519-
*/
520-
int
521-
check_arg_type(type_T *expected, type_T *actual, int argidx)
522-
{
523-
if (check_type(expected, actual, FALSE, 0) == OK
524-
|| use_typecheck(actual, expected))
525-
return OK;
526-
// TODO: should generate a TYPECHECK instruction.
527-
return check_type(expected, actual, TRUE, argidx);
528-
}
529-
530516
/*
531517
* Check that the arguments of "type" match "argvars[argcount]".
532518
* Return OK/FAIL.
533519
*/
534520
int
535-
check_argument_types(type_T *type, typval_T *argvars, int argcount, char_u *name)
521+
check_argument_types(
522+
type_T *type,
523+
typval_T *argvars,
524+
int argcount,
525+
char_u *name)
536526
{
537527
int varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0;
538528
int i;

0 commit comments

Comments
 (0)