forked from aniani/vim
patch 9.0.0623: error for modifying a const is not detected at compile time
Problem: Error for modifying a const is not detected at compile time. Solution: Add TTFLAG_CONST and check for it in add() and extend().
This commit is contained in:
@@ -3332,4 +3332,6 @@ EXTERN char e_cannot_use_length_endcol_and_endlnum_with_text[]
|
|||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
EXTERN char e_loop_nesting_too_deep[]
|
EXTERN char e_loop_nesting_too_deep[]
|
||||||
INIT(= N_("E1306: Loop nesting too deep"));
|
INIT(= N_("E1306: Loop nesting too deep"));
|
||||||
|
EXTERN char e_argument_nr_trying_to_modify_const_str[]
|
||||||
|
INIT(= N_("E1307: Argument %d: Trying to modify a const %s"));
|
||||||
#endif
|
#endif
|
||||||
|
@@ -221,6 +221,22 @@ check_arg_type(
|
|||||||
context->arg_cctx, FALSE, FALSE);
|
context->arg_cctx, FALSE, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Give an error if "type" is a constant.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
arg_type_modifiable(type_T *type, int arg_idx)
|
||||||
|
{
|
||||||
|
char *tofree;
|
||||||
|
|
||||||
|
if ((type->tt_flags & TTFLAG_CONST) == 0)
|
||||||
|
return OK;
|
||||||
|
semsg(_(e_argument_nr_trying_to_modify_const_str),
|
||||||
|
arg_idx, type_name(type, &tofree));
|
||||||
|
vim_free(tofree);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check "type" is a float or a number.
|
* Check "type" is a float or a number.
|
||||||
*/
|
*/
|
||||||
@@ -323,6 +339,20 @@ arg_list_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check "type" is a modifiable list of 'any' or a blob.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
arg_list_or_blob_mod(
|
||||||
|
type_T *type,
|
||||||
|
type_T *decl_type,
|
||||||
|
argcontext_T *context)
|
||||||
|
{
|
||||||
|
if (arg_list_or_blob(type, decl_type, context) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
return arg_type_modifiable(type, context->arg_idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check "type" is a string or a number
|
* Check "type" is a string or a number
|
||||||
*/
|
*/
|
||||||
@@ -467,6 +497,20 @@ arg_list_or_dict(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check "type" is a list of 'any' or a dict of 'any'. And modifiable.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
arg_list_or_dict_mod(
|
||||||
|
type_T *type,
|
||||||
|
type_T *decl_type,
|
||||||
|
argcontext_T *context)
|
||||||
|
{
|
||||||
|
if (arg_list_or_dict(type, decl_type, context) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
return arg_type_modifiable(type, context->arg_idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check "type" is a list of 'any' or a dict of 'any' or a blob.
|
* Check "type" is a list of 'any' or a dict of 'any' or a blob.
|
||||||
*/
|
*/
|
||||||
@@ -979,7 +1023,7 @@ static argcheck_T arg2_list_any_number[] = {arg_list_any, arg_number};
|
|||||||
static argcheck_T arg2_list_any_string[] = {arg_list_any, arg_string};
|
static argcheck_T arg2_list_any_string[] = {arg_list_any, arg_string};
|
||||||
static argcheck_T arg2_list_number[] = {arg_list_number, arg_list_number};
|
static argcheck_T arg2_list_number[] = {arg_list_number, arg_list_number};
|
||||||
static argcheck_T arg2_list_number_bool[] = {arg_list_number, arg_bool};
|
static argcheck_T arg2_list_number_bool[] = {arg_list_number, arg_bool};
|
||||||
static argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
|
static argcheck_T arg2_listblobmod_item[] = {arg_list_or_blob_mod, arg_item_of_prev};
|
||||||
static argcheck_T arg2_lnum[] = {arg_lnum, arg_lnum};
|
static argcheck_T arg2_lnum[] = {arg_lnum, arg_lnum};
|
||||||
static argcheck_T arg2_lnum_number[] = {arg_lnum, arg_number};
|
static argcheck_T arg2_lnum_number[] = {arg_lnum, arg_number};
|
||||||
static argcheck_T arg2_number[] = {arg_number, arg_number};
|
static argcheck_T arg2_number[] = {arg_number, arg_number};
|
||||||
@@ -1036,7 +1080,7 @@ static argcheck_T arg24_count[] = {arg_string_or_list_or_dict, NULL, arg_bool, a
|
|||||||
static argcheck_T arg13_cursor[] = {arg_cursor1, arg_number, arg_number};
|
static argcheck_T arg13_cursor[] = {arg_cursor1, arg_number, arg_number};
|
||||||
static argcheck_T arg12_deepcopy[] = {NULL, arg_bool};
|
static argcheck_T arg12_deepcopy[] = {NULL, arg_bool};
|
||||||
static argcheck_T arg12_execute[] = {arg_string_or_list_string, arg_string};
|
static argcheck_T arg12_execute[] = {arg_string_or_list_string, arg_string};
|
||||||
static argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
|
static argcheck_T arg23_extend[] = {arg_list_or_dict_mod, arg_same_as_prev, arg_extend3};
|
||||||
static argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3};
|
static argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3};
|
||||||
static argcheck_T arg23_get[] = {arg_get1, arg_string_or_nr, NULL};
|
static argcheck_T arg23_get[] = {arg_get1, arg_string_or_nr, NULL};
|
||||||
static argcheck_T arg14_glob[] = {arg_string, arg_bool, arg_bool, arg_bool};
|
static argcheck_T arg14_glob[] = {arg_string, arg_bool, arg_bool, arg_bool};
|
||||||
@@ -1554,7 +1598,7 @@ static funcentry_T global_functions[] =
|
|||||||
ret_any, f_abs},
|
ret_any, f_abs},
|
||||||
{"acos", 1, 1, FEARG_1, arg1_float_or_nr,
|
{"acos", 1, 1, FEARG_1, arg1_float_or_nr,
|
||||||
ret_float, f_acos},
|
ret_float, f_acos},
|
||||||
{"add", 2, 2, FEARG_1, arg2_listblob_item,
|
{"add", 2, 2, FEARG_1, arg2_listblobmod_item,
|
||||||
ret_first_arg, f_add},
|
ret_first_arg, f_add},
|
||||||
{"and", 2, 2, FEARG_1, arg2_number,
|
{"and", 2, 2, FEARG_1, arg2_number,
|
||||||
ret_number, f_and},
|
ret_number, f_and},
|
||||||
|
330
src/globals.h
330
src/globals.h
@@ -396,65 +396,301 @@ EXTERN int want_garbage_collect INIT(= FALSE);
|
|||||||
EXTERN int garbage_collect_at_exit INIT(= FALSE);
|
EXTERN int garbage_collect_at_exit INIT(= FALSE);
|
||||||
|
|
||||||
|
|
||||||
// Commonly used types.
|
// Array with predefined commonly used types.
|
||||||
// "unknown" is used for when the type is really unknown, e.g. global
|
//
|
||||||
// variables. Also for when a function may or may not return something.
|
// For each entry of a regular type the next one has the "const" version.
|
||||||
EXTERN type_T t_unknown INIT6(VAR_UNKNOWN, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
// E.g. "&t_const_bool == &t_bool + 1"
|
||||||
|
|
||||||
// "any" is used for when the type is mixed. Excludes "void".
|
// t_unknown - used for when the type is really unknown, e.g. global variables.
|
||||||
EXTERN type_T t_any INIT6(VAR_ANY, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
// Also for when a function may or may not return something.
|
||||||
|
#define t_unknown (static_types[0])
|
||||||
|
#define t_const_unknown (static_types[1])
|
||||||
|
|
||||||
// "void" is used for a function not returning anything.
|
// t_any - used for when the type can be anything, but excludes "void".
|
||||||
EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
#define t_any (static_types[2])
|
||||||
|
#define t_const_any (static_types[3])
|
||||||
|
|
||||||
EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
// t_void - used for a function not returning anything.
|
||||||
EXTERN type_T t_null INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
#define t_void (static_types[4])
|
||||||
EXTERN type_T t_none INIT6(VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
#define t_const_void (static_types[5])
|
||||||
EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
|
||||||
EXTERN type_T t_number_bool INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC|TTFLAG_BOOL_OK, NULL, NULL);
|
|
||||||
EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
|
||||||
EXTERN type_T t_string INIT6(VAR_STRING, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
|
||||||
EXTERN type_T t_blob INIT6(VAR_BLOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
|
||||||
EXTERN type_T t_blob_null INIT6(VAR_BLOB, 0, 0, TTFLAG_STATIC, &t_void, NULL);
|
|
||||||
EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
|
||||||
EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
|
||||||
|
|
||||||
// Special value used for @#.
|
#define t_bool (static_types[6])
|
||||||
EXTERN type_T t_number_or_string INIT6(VAR_STRING, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
#define t_const_bool (static_types[7])
|
||||||
|
|
||||||
EXTERN type_T t_func_unknown INIT6(VAR_FUNC, -1, -1, TTFLAG_STATIC, &t_unknown, NULL);
|
#define t_null (static_types[8])
|
||||||
EXTERN type_T t_func_void INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_void, NULL);
|
#define t_const_null (static_types[9])
|
||||||
EXTERN type_T t_func_any INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_any, NULL);
|
|
||||||
EXTERN type_T t_func_number INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_number, NULL);
|
|
||||||
EXTERN type_T t_func_string INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_string, NULL);
|
|
||||||
EXTERN type_T t_func_bool INIT6(VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_bool, NULL);
|
|
||||||
EXTERN type_T t_func_0_void INIT6(VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_void, NULL);
|
|
||||||
EXTERN type_T t_func_0_any INIT6(VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_any, NULL);
|
|
||||||
EXTERN type_T t_func_0_number INIT6(VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_number, NULL);
|
|
||||||
EXTERN type_T t_func_0_string INIT6(VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_string, NULL);
|
|
||||||
|
|
||||||
EXTERN type_T t_list_any INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_any, NULL);
|
#define t_none (static_types[10])
|
||||||
EXTERN type_T t_dict_any INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_any, NULL);
|
#define t_const_none (static_types[11])
|
||||||
EXTERN type_T t_list_empty INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_unknown, NULL);
|
|
||||||
EXTERN type_T t_dict_empty INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_unknown, NULL);
|
|
||||||
|
|
||||||
EXTERN type_T t_list_bool INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_bool, NULL);
|
#define t_number (static_types[12])
|
||||||
EXTERN type_T t_list_number INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_number, NULL);
|
#define t_const_number (static_types[13])
|
||||||
EXTERN type_T t_list_string INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_string, NULL);
|
|
||||||
EXTERN type_T t_list_job INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_job, NULL);
|
|
||||||
EXTERN type_T t_list_dict_any INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_dict_any, NULL);
|
|
||||||
EXTERN type_T t_list_list_any INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_list_any, NULL);
|
|
||||||
EXTERN type_T t_list_list_string INIT6(VAR_LIST, 0, 0, TTFLAG_STATIC, &t_list_string, NULL);
|
|
||||||
|
|
||||||
EXTERN type_T t_dict_bool INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_bool, NULL);
|
// t_number_bool - number that can be used as a bool
|
||||||
EXTERN type_T t_dict_number INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_number, NULL);
|
#define t_number_bool (static_types[14])
|
||||||
EXTERN type_T t_dict_string INIT6(VAR_DICT, 0, 0, TTFLAG_STATIC, &t_string, NULL);
|
#define t_const_number_bool (static_types[15])
|
||||||
|
|
||||||
|
#define t_float (static_types[16])
|
||||||
|
#define t_const_float (static_types[17])
|
||||||
|
|
||||||
|
#define t_string (static_types[18])
|
||||||
|
#define t_const_string (static_types[19])
|
||||||
|
|
||||||
|
#define t_blob (static_types[20])
|
||||||
|
#define t_const_blob (static_types[21])
|
||||||
|
|
||||||
|
#define t_blob_null (static_types[22])
|
||||||
|
#define t_const_blob_null (static_types[23])
|
||||||
|
|
||||||
|
#define t_job (static_types[24])
|
||||||
|
#define t_const_job (static_types[25])
|
||||||
|
|
||||||
|
#define t_channel (static_types[26])
|
||||||
|
#define t_const_channel (static_types[27])
|
||||||
|
|
||||||
|
// t_number_or_string - Special value used for @#.
|
||||||
|
#define t_number_or_string (static_types[28])
|
||||||
|
#define t_const_number_or_string (static_types[29])
|
||||||
|
|
||||||
|
// t_func_unknown - function with any arguments and no or unknown return value
|
||||||
|
#define t_func_unknown (static_types[30])
|
||||||
|
#define t_const_func_unknown (static_types[31])
|
||||||
|
|
||||||
|
// t_func_void - function with any arguments and no return value
|
||||||
|
#define t_func_void (static_types[32])
|
||||||
|
#define t_const_func_void (static_types[33])
|
||||||
|
|
||||||
|
#define t_func_any (static_types[34])
|
||||||
|
#define t_const_func_any (static_types[35])
|
||||||
|
|
||||||
|
#define t_func_number (static_types[36])
|
||||||
|
#define t_const_func_number (static_types[37])
|
||||||
|
|
||||||
|
#define t_func_string (static_types[38])
|
||||||
|
#define t_const_func_string (static_types[39])
|
||||||
|
|
||||||
|
#define t_func_bool (static_types[40])
|
||||||
|
#define t_const_func_bool (static_types[41])
|
||||||
|
|
||||||
|
// t_func_0_void - function without arguments and nor return value
|
||||||
|
#define t_func_0_void (static_types[42])
|
||||||
|
#define t_const_func_0_void (static_types[43])
|
||||||
|
|
||||||
|
#define t_func_0_any (static_types[44])
|
||||||
|
#define t_const_func_0_any (static_types[45])
|
||||||
|
|
||||||
|
#define t_func_0_number (static_types[46])
|
||||||
|
#define t_const_func_0_number (static_types[47])
|
||||||
|
|
||||||
|
#define t_func_0_string (static_types[48])
|
||||||
|
#define t_const_func_0_string (static_types[49])
|
||||||
|
|
||||||
|
#define t_list_any (static_types[50])
|
||||||
|
#define t_const_list_any (static_types[51])
|
||||||
|
|
||||||
|
#define t_dict_any (static_types[52])
|
||||||
|
#define t_const_dict_any (static_types[53])
|
||||||
|
|
||||||
|
#define t_list_empty (static_types[54])
|
||||||
|
#define t_const_list_empty (static_types[55])
|
||||||
|
|
||||||
|
#define t_dict_empty (static_types[56])
|
||||||
|
#define t_const_dict_empty (static_types[57])
|
||||||
|
|
||||||
|
#define t_list_bool (static_types[58])
|
||||||
|
#define t_const_list_bool (static_types[59])
|
||||||
|
|
||||||
|
#define t_list_number (static_types[60])
|
||||||
|
#define t_const_list_number (static_types[61])
|
||||||
|
|
||||||
|
#define t_list_string (static_types[62])
|
||||||
|
#define t_const_list_string (static_types[63])
|
||||||
|
|
||||||
|
#define t_list_job (static_types[64])
|
||||||
|
#define t_const_list_job (static_types[65])
|
||||||
|
|
||||||
|
#define t_list_dict_any (static_types[66])
|
||||||
|
#define t_const_list_dict_any (static_types[67])
|
||||||
|
|
||||||
|
#define t_list_list_any (static_types[68])
|
||||||
|
#define t_const_list_list_any (static_types[69])
|
||||||
|
|
||||||
|
#define t_list_list_string (static_types[70])
|
||||||
|
#define t_const_list_list_string (static_types[71])
|
||||||
|
|
||||||
|
#define t_dict_bool (static_types[72])
|
||||||
|
#define t_const_dict_bool (static_types[73])
|
||||||
|
|
||||||
|
#define t_dict_number (static_types[74])
|
||||||
|
#define t_const_dict_number (static_types[75])
|
||||||
|
|
||||||
|
#define t_dict_string (static_types[76])
|
||||||
|
#define t_const_dict_string (static_types[77])
|
||||||
|
|
||||||
|
EXTERN type_T static_types[78]
|
||||||
|
#ifdef DO_INIT
|
||||||
|
= {
|
||||||
|
// 0: t_unknown
|
||||||
|
{VAR_UNKNOWN, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_UNKNOWN, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 2: t_any
|
||||||
|
{VAR_ANY, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_ANY, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 4: t_void
|
||||||
|
{VAR_VOID, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_VOID, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 6: t_bool
|
||||||
|
{VAR_BOOL, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_BOOL, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 8: t_null
|
||||||
|
{VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_SPECIAL, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 10: t_none
|
||||||
|
{VAR_SPECIAL, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_SPECIAL, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 12: t_number
|
||||||
|
{VAR_NUMBER, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_NUMBER, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 14: t_number_bool
|
||||||
|
{VAR_NUMBER, 0, 0, TTFLAG_STATIC|TTFLAG_BOOL_OK, NULL, NULL},
|
||||||
|
{VAR_NUMBER, 0, 0, TTFLAG_STATIC|TTFLAG_BOOL_OK|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 16: t_float
|
||||||
|
{VAR_FLOAT, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_FLOAT, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 18: t_string
|
||||||
|
{VAR_STRING, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_STRING, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 20: t_blob
|
||||||
|
{VAR_BLOB, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_BLOB, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 22: t_blob_null
|
||||||
|
{VAR_BLOB, 0, 0, TTFLAG_STATIC, &t_void, NULL},
|
||||||
|
{VAR_BLOB, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_void, NULL},
|
||||||
|
|
||||||
|
// 24: t_job
|
||||||
|
{VAR_JOB, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_JOB, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 26: t_channel
|
||||||
|
{VAR_CHANNEL, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_CHANNEL, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 28: t_number_or_string
|
||||||
|
{VAR_STRING, 0, 0, TTFLAG_STATIC, NULL, NULL},
|
||||||
|
{VAR_STRING, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, NULL, NULL},
|
||||||
|
|
||||||
|
// 30: t_func_unknown
|
||||||
|
{VAR_FUNC, -1, -1, TTFLAG_STATIC, &t_unknown, NULL},
|
||||||
|
{VAR_FUNC, -1, -1, TTFLAG_STATIC|TTFLAG_CONST, &t_unknown, NULL},
|
||||||
|
|
||||||
|
// 32: t_func_void
|
||||||
|
{VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_void, NULL},
|
||||||
|
{VAR_FUNC, -1, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_void, NULL},
|
||||||
|
|
||||||
|
// 34: t_func_any
|
||||||
|
{VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_any, NULL},
|
||||||
|
{VAR_FUNC, -1, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_any, NULL},
|
||||||
|
|
||||||
|
// 36: t_func_number
|
||||||
|
{VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_number, NULL},
|
||||||
|
{VAR_FUNC, -1, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_number, NULL},
|
||||||
|
|
||||||
|
// 38: t_func_string
|
||||||
|
{VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_string, NULL},
|
||||||
|
{VAR_FUNC, -1, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_string, NULL},
|
||||||
|
|
||||||
|
// 40: t_func_bool
|
||||||
|
{VAR_FUNC, -1, 0, TTFLAG_STATIC, &t_bool, NULL},
|
||||||
|
{VAR_FUNC, -1, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_bool, NULL},
|
||||||
|
|
||||||
|
// 42: t_func_0_void
|
||||||
|
{VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_void, NULL},
|
||||||
|
{VAR_FUNC, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_void, NULL},
|
||||||
|
|
||||||
|
// 44: t_func_0_any
|
||||||
|
{VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_any, NULL},
|
||||||
|
{VAR_FUNC, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_any, NULL},
|
||||||
|
|
||||||
|
// 46: t_func_0_number
|
||||||
|
{VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_number, NULL},
|
||||||
|
{VAR_FUNC, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_number, NULL},
|
||||||
|
|
||||||
|
// 48: t_func_0_string
|
||||||
|
{VAR_FUNC, 0, 0, TTFLAG_STATIC, &t_string, NULL},
|
||||||
|
{VAR_FUNC, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_string, NULL},
|
||||||
|
|
||||||
|
// 50: t_list_any
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC, &t_any, NULL},
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_any, NULL},
|
||||||
|
|
||||||
|
// 52: t_dict_any
|
||||||
|
{VAR_DICT, 0, 0, TTFLAG_STATIC, &t_any, NULL},
|
||||||
|
{VAR_DICT, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_any, NULL},
|
||||||
|
|
||||||
|
// 54: t_list_empty
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC, &t_unknown, NULL},
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_unknown, NULL},
|
||||||
|
|
||||||
|
// 56: t_dict_empty
|
||||||
|
{VAR_DICT, 0, 0, TTFLAG_STATIC, &t_unknown, NULL},
|
||||||
|
{VAR_DICT, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_unknown, NULL},
|
||||||
|
|
||||||
|
// 58: t_list_bool
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC, &t_bool, NULL},
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_bool, NULL},
|
||||||
|
|
||||||
|
// 60: t_list_number
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC, &t_number, NULL},
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_number, NULL},
|
||||||
|
|
||||||
|
// 62: t_list_string
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC, &t_string, NULL},
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_string, NULL},
|
||||||
|
|
||||||
|
// 64: t_list_job
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC, &t_job, NULL},
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_job, NULL},
|
||||||
|
|
||||||
|
// 66: t_list_dict_any
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC, &t_dict_any, NULL},
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_dict_any, NULL},
|
||||||
|
|
||||||
|
// 68: t_list_list_any
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC, &t_list_any, NULL},
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_list_any, NULL},
|
||||||
|
|
||||||
|
// 70: t_list_list_string
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC, &t_list_string, NULL},
|
||||||
|
{VAR_LIST, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_list_string, NULL},
|
||||||
|
|
||||||
|
// 72: t_dict_bool
|
||||||
|
{VAR_DICT, 0, 0, TTFLAG_STATIC, &t_bool, NULL},
|
||||||
|
{VAR_DICT, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_bool, NULL},
|
||||||
|
|
||||||
|
// 74: t_dict_number
|
||||||
|
{VAR_DICT, 0, 0, TTFLAG_STATIC, &t_number, NULL},
|
||||||
|
{VAR_DICT, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_number, NULL},
|
||||||
|
|
||||||
|
// 76: t_dict_string
|
||||||
|
{VAR_DICT, 0, 0, TTFLAG_STATIC, &t_string, NULL},
|
||||||
|
{VAR_DICT, 0, 0, TTFLAG_STATIC|TTFLAG_CONST, &t_string, NULL},
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
#ifdef FEAT_EVAL
|
|
||||||
EXTERN int did_source_packages INIT(= FALSE);
|
EXTERN int did_source_packages INIT(= FALSE);
|
||||||
#endif
|
#endif // FEAT_EVAL
|
||||||
|
|
||||||
// Magic number used for hashitem "hi_key" value indicating a deleted item.
|
// Magic number used for hashitem "hi_key" value indicating a deleted item.
|
||||||
// Only the address is used.
|
// Only the address is used.
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
/* evalfunc.c */
|
/* evalfunc.c */
|
||||||
|
int arg_type_modifiable(type_T *type, int arg_idx);
|
||||||
char_u *get_function_name(expand_T *xp, int idx);
|
char_u *get_function_name(expand_T *xp, int idx);
|
||||||
char_u *get_expr_name(expand_T *xp, int idx);
|
char_u *get_expr_name(expand_T *xp, int idx);
|
||||||
int find_internal_func(char_u *name);
|
int find_internal_func(char_u *name);
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
/* vim9type.c */
|
/* vim9type.c */
|
||||||
|
type_T *copy_type(type_T *type, garray_T *type_gap);
|
||||||
void clear_type_list(garray_T *gap);
|
void clear_type_list(garray_T *gap);
|
||||||
type_T *alloc_type(type_T *type);
|
type_T *alloc_type(type_T *type);
|
||||||
void free_type(type_T *type);
|
void free_type(type_T *type);
|
||||||
|
@@ -1445,10 +1445,10 @@ typedef struct {
|
|||||||
type_T *type_decl; // declared type or equal to type_current
|
type_T *type_decl; // declared type or equal to type_current
|
||||||
} type2_T;
|
} type2_T;
|
||||||
|
|
||||||
#define TTFLAG_VARARGS 1 // func args ends with "..."
|
#define TTFLAG_VARARGS 0x01 // func args ends with "..."
|
||||||
#define TTFLAG_OPTARG 2 // func arg type with "?"
|
#define TTFLAG_BOOL_OK 0x02 // can be converted to bool
|
||||||
#define TTFLAG_BOOL_OK 4 // can be converted to bool
|
#define TTFLAG_STATIC 0x04 // one of the static types, e.g. t_any
|
||||||
#define TTFLAG_STATIC 8 // one of the static types, e.g. t_any
|
#define TTFLAG_CONST 0x08 // cannot be changed
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure to hold an internal variable without a name.
|
* Structure to hold an internal variable without a name.
|
||||||
|
@@ -184,6 +184,21 @@ def Test_add_list()
|
|||||||
v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number', 3)
|
v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number', 3)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_add_const()
|
||||||
|
var lines =<< trim END
|
||||||
|
const l = [1, 2]
|
||||||
|
add(l, 3)
|
||||||
|
END
|
||||||
|
v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const list<number>')
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
const b = 0z0102
|
||||||
|
add(b, 0z03)
|
||||||
|
END
|
||||||
|
v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const blob')
|
||||||
|
enddef
|
||||||
|
|
||||||
|
|
||||||
def Test_and()
|
def Test_and()
|
||||||
v9.CheckDefAndScriptFailure(['and("x", 0x2)'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
|
v9.CheckDefAndScriptFailure(['and("x", 0x2)'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
|
||||||
v9.CheckDefAndScriptFailure(['and(0x1, "x")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2'])
|
v9.CheckDefAndScriptFailure(['and(0x1, "x")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2'])
|
||||||
@@ -1181,6 +1196,29 @@ def Test_extend_with_error_function()
|
|||||||
v9.CheckScriptFailure(lines, 'E1001: Variable not found: m')
|
v9.CheckScriptFailure(lines, 'E1001: Variable not found: m')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_extend_const()
|
||||||
|
var lines =<< trim END
|
||||||
|
const l = [1, 2]
|
||||||
|
extend(l, [3])
|
||||||
|
END
|
||||||
|
v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const list<number>')
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
const d = {a: 1, b: 2}
|
||||||
|
extend(d, {c: 3})
|
||||||
|
END
|
||||||
|
v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const dict<number>')
|
||||||
|
|
||||||
|
# item in a for loop is const
|
||||||
|
lines =<< trim END
|
||||||
|
var l: list<dict<any>> = [{n: 1}]
|
||||||
|
for item in l
|
||||||
|
item->extend({x: 2})
|
||||||
|
endfor
|
||||||
|
END
|
||||||
|
v9.CheckDefFailure(lines, 'E1307: Argument 1: Trying to modify a const dict<any>')
|
||||||
|
enddef
|
||||||
|
|
||||||
def Test_extendnew()
|
def Test_extendnew()
|
||||||
assert_equal([1, 2, 'a'], extendnew([1, 2], ['a']))
|
assert_equal([1, 2, 'a'], extendnew([1, 2], ['a']))
|
||||||
assert_equal({one: 1, two: 'a'}, extendnew({one: 1}, {two: 'a'}))
|
assert_equal({one: 1, two: 'a'}, extendnew({one: 1}, {two: 'a'}))
|
||||||
|
@@ -2471,10 +2471,11 @@ def Test_for_loop_fails()
|
|||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
var l: list<dict<any>> = [{n: 1}]
|
var l: list<dict<any>> = [{n: 1}]
|
||||||
for item: dict<number> in l
|
for item: dict<number> in l
|
||||||
item->extend({s: ''})
|
var d = {s: ''}
|
||||||
|
d->extend(item)
|
||||||
endfor
|
endfor
|
||||||
END
|
END
|
||||||
v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>')
|
v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<string> but got dict<number>')
|
||||||
|
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
for a in range(3)
|
for a in range(3)
|
||||||
|
@@ -699,6 +699,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 */
|
||||||
|
/**/
|
||||||
|
623,
|
||||||
/**/
|
/**/
|
||||||
622,
|
622,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -462,6 +462,29 @@ need_type(
|
|||||||
cctx, silent, actual_is_const);
|
cctx, silent, actual_is_const);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set type of variable "lvar" to "type". If the variable is a constant then
|
||||||
|
* the type gets TTFLAG_CONST.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
set_var_type(lvar_T *lvar, type_T *type_arg, cctx_T *cctx)
|
||||||
|
{
|
||||||
|
type_T *type = type_arg;
|
||||||
|
|
||||||
|
if (lvar->lv_const && (type->tt_flags & TTFLAG_CONST) == 0)
|
||||||
|
{
|
||||||
|
if (type->tt_flags & TTFLAG_STATIC)
|
||||||
|
// entry in static_types[] is followed by const type
|
||||||
|
type = type + 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = copy_type(type, cctx->ctx_type_list);
|
||||||
|
type->tt_flags |= TTFLAG_CONST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lvar->lv_type = type;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reserve space for a local variable.
|
* Reserve space for a local variable.
|
||||||
* Return the variable or NULL if it failed.
|
* Return the variable or NULL if it failed.
|
||||||
@@ -497,7 +520,12 @@ reserve_local(
|
|||||||
|
|
||||||
lvar->lv_name = vim_strnsave(name, len == 0 ? STRLEN(name) : len);
|
lvar->lv_name = vim_strnsave(name, len == 0 ? STRLEN(name) : len);
|
||||||
lvar->lv_const = isConst;
|
lvar->lv_const = isConst;
|
||||||
|
if (type == &t_unknown || type == &t_any)
|
||||||
|
// type not known yet, may be inferred from RHS
|
||||||
lvar->lv_type = type;
|
lvar->lv_type = type;
|
||||||
|
else
|
||||||
|
// may use TTFLAG_CONST
|
||||||
|
set_var_type(lvar, type, cctx);
|
||||||
|
|
||||||
// Remember the name for debugging.
|
// Remember the name for debugging.
|
||||||
if (GA_GROW_FAILS(&dfunc->df_var_names, 1))
|
if (GA_GROW_FAILS(&dfunc->df_var_names, 1))
|
||||||
@@ -2304,19 +2332,22 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
type_T *type;
|
||||||
|
|
||||||
// An empty list or dict has a &t_unknown member,
|
// An empty list or dict has a &t_unknown member,
|
||||||
// for a variable that implies &t_any.
|
// for a variable that implies &t_any.
|
||||||
if (rhs_type == &t_list_empty)
|
if (rhs_type == &t_list_empty)
|
||||||
lhs.lhs_lvar->lv_type = &t_list_any;
|
type = &t_list_any;
|
||||||
else if (rhs_type == &t_dict_empty)
|
else if (rhs_type == &t_dict_empty)
|
||||||
lhs.lhs_lvar->lv_type = &t_dict_any;
|
type = &t_dict_any;
|
||||||
else if (rhs_type == &t_unknown)
|
else if (rhs_type == &t_unknown)
|
||||||
lhs.lhs_lvar->lv_type = &t_any;
|
type = &t_any;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lhs.lhs_lvar->lv_type = rhs_type;
|
type = rhs_type;
|
||||||
inferred_type = rhs_type;
|
inferred_type = rhs_type;
|
||||||
}
|
}
|
||||||
|
set_var_type(lhs.lhs_lvar, type, cctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (*op == '=')
|
else if (*op == '=')
|
||||||
|
@@ -1533,6 +1533,8 @@ generate_LISTAPPEND(cctx_T *cctx)
|
|||||||
// For checking the item type we use the declared type of the list and the
|
// For checking the item type we use the declared type of the list and the
|
||||||
// current type of the added item, adding a string to [1, 2] is OK.
|
// current type of the added item, adding a string to [1, 2] is OK.
|
||||||
list_type = get_decl_type_on_stack(cctx, 1);
|
list_type = get_decl_type_on_stack(cctx, 1);
|
||||||
|
if (arg_type_modifiable(list_type, 1) == FAIL)
|
||||||
|
return FAIL;
|
||||||
item_type = get_type_on_stack(cctx, 0);
|
item_type = get_type_on_stack(cctx, 0);
|
||||||
expected = list_type->tt_member;
|
expected = list_type->tt_member;
|
||||||
if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||||
@@ -1554,7 +1556,9 @@ generate_BLOBAPPEND(cctx_T *cctx)
|
|||||||
{
|
{
|
||||||
type_T *item_type;
|
type_T *item_type;
|
||||||
|
|
||||||
// Caller already checked that blob_type is a blob.
|
// Caller already checked that blob_type is a blob, check it is modifiable.
|
||||||
|
if (arg_type_modifiable(get_decl_type_on_stack(cctx, 1), 1) == FAIL)
|
||||||
|
return FAIL;
|
||||||
item_type = get_type_on_stack(cctx, 0);
|
item_type = get_type_on_stack(cctx, 0);
|
||||||
if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
@@ -45,6 +45,30 @@ get_type_ptr(garray_T *type_gap)
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make a shallow copy of "type".
|
||||||
|
* When allocation fails returns "type".
|
||||||
|
*/
|
||||||
|
type_T *
|
||||||
|
copy_type(type_T *type, garray_T *type_gap)
|
||||||
|
{
|
||||||
|
type_T *copy = get_type_ptr(type_gap);
|
||||||
|
|
||||||
|
if (copy == NULL)
|
||||||
|
return type;
|
||||||
|
*copy = *type;
|
||||||
|
|
||||||
|
if (type->tt_args != NULL)
|
||||||
|
{
|
||||||
|
copy->tt_args = ALLOC_MULT(type_T *, type->tt_argcount);
|
||||||
|
if (copy->tt_args != NULL)
|
||||||
|
for (int i = 0; i < type->tt_argcount; ++i)
|
||||||
|
copy->tt_args[i] = type->tt_args[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
clear_type_list(garray_T *gap)
|
clear_type_list(garray_T *gap)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user