hashtab_free_contents(&d->dv_hashtab);
free_type(d->dv_type);
d->dv_type = NULL;
+ free_type(d->dv_decl_type);
+ d->dv_decl_type = NULL;
}
/*
if (filtermap == FILTERMAP_MAP)
{
if (argtype != NULL && check_typval_arg_type(
- argtype->tt_member, &newtv,
- func_name, 0) == FAIL)
+ argtype->tt_member, &newtv, func_name, 0) == FAIL)
{
clear_tv(&newtv);
break;
get_buffer_lines(buf, lnum, end, TRUE, rettv);
}
- type_T *
-ret_f_getline(int argcount, type_T **argtypes UNUSED)
-{
- return argcount == 1 ? &t_string : &t_list_string;
-}
-
/*
* "getline(lnum, [end])" function
*/
// Context passed to an arg_ function.
typedef struct {
int arg_count; // actual argument count
- type_T **arg_types; // list of argument types
+ type2_T *arg_types; // list of argument types
int arg_idx; // current argument index (first arg is zero)
cctx_T *arg_cctx;
} argcontext_T;
// A function to check one argument type. The first argument is the type to
// check. If needed, other argument types can be obtained with the context.
// E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
-typedef int (*argcheck_T)(type_T *, argcontext_T *);
+typedef int (*argcheck_T)(type_T *, type_T *, argcontext_T *);
/*
* Call need_type() to check an argument type.
* Check "type" is a float or a number.
*/
static int
-arg_float_or_nr(type_T *type, argcontext_T *context)
+arg_float_or_nr(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a number.
*/
static int
-arg_number(type_T *type, argcontext_T *context)
+arg_number(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
return check_arg_type(&t_number, type, context);
}
* Check "type" is a dict of 'any'.
*/
static int
-arg_dict_any(type_T *type, argcontext_T *context)
+arg_dict_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
return check_arg_type(&t_dict_any, type, context);
}
* Check "type" is a list of 'any'.
*/
static int
-arg_list_any(type_T *type, argcontext_T *context)
+arg_list_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
return check_arg_type(&t_list_any, type, context);
}
* Check "type" is a list of numbers.
*/
static int
-arg_list_number(type_T *type, argcontext_T *context)
+arg_list_number(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
return check_arg_type(&t_list_number, type, context);
}
* Check "type" is a list of strings.
*/
static int
-arg_list_string(type_T *type, argcontext_T *context)
+arg_list_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
return check_arg_type(&t_list_string, type, context);
}
* Check "type" is a string.
*/
static int
-arg_string(type_T *type, argcontext_T *context)
+arg_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
return check_arg_type(&t_string, type, context);
}
* Check "type" is a blob
*/
static int
-arg_blob(type_T *type, argcontext_T *context)
+arg_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
return check_arg_type(&t_blob, type, context);
}
* Check "type" is a bool or number 0 or 1.
*/
static int
-arg_bool(type_T *type, argcontext_T *context)
+arg_bool(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
return check_arg_type(&t_bool, type, context);
}
* Check "type" is a list of 'any' or a blob.
*/
static int
-arg_list_or_blob(type_T *type, argcontext_T *context)
+arg_list_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a string or a number
*/
static int
-arg_string_or_nr(type_T *type, argcontext_T *context)
+arg_string_or_nr(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a buffer (string or a number)
*/
static int
-arg_buffer(type_T *type, argcontext_T *context)
+arg_buffer(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a buffer or a dict of any
*/
static int
-arg_buffer_or_dict_any(type_T *type, argcontext_T *context)
+arg_buffer_or_dict_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a line (string or a number)
*/
static int
-arg_lnum(type_T *type, argcontext_T *context)
+arg_lnum(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a string or a list of strings.
*/
static int
-arg_string_or_list_string(type_T *type, argcontext_T *context)
+arg_string_or_list_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a string or a list of 'any'
*/
static int
-arg_string_or_list_any(type_T *type, argcontext_T *context)
+arg_string_or_list_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a string or a blob
*/
static int
-arg_string_or_blob(type_T *type, argcontext_T *context)
+arg_string_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a list of 'any' or a dict of 'any'.
*/
static int
-arg_list_or_dict(type_T *type, argcontext_T *context)
+arg_list_or_dict(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a list of 'any' or a dict of 'any' or a blob.
*/
static int
-arg_list_or_dict_or_blob(type_T *type, argcontext_T *context)
+arg_list_or_dict_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a list of 'any' or a dict of 'any' or a blob or a string.
*/
static int
-arg_list_or_dict_or_blob_or_string(type_T *type, argcontext_T *context)
+arg_list_or_dict_or_blob_or_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check second argument of filter(): func must return a bool.
*/
static int
-arg_filter_func(type_T *type, argcontext_T *context)
+arg_filter_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_FUNC
&& !(type->tt_member->tt_type == VAR_BOOL
* Check second argument of map().
*/
static int
-arg_map_func(type_T *type, argcontext_T *context)
+arg_map_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_FUNC
&& type->tt_member != &t_any
{
type_T *expected = NULL;
- if (context->arg_types[0]->tt_type == VAR_LIST
- || context->arg_types[0]->tt_type == VAR_DICT)
- expected = context->arg_types[0]->tt_member;
- else if (context->arg_types[0]->tt_type == VAR_STRING)
+ if (context->arg_types[0].type_curr->tt_type == VAR_LIST
+ || context->arg_types[0].type_curr->tt_type == VAR_DICT)
+ expected = context->arg_types[0].type_curr->tt_member;
+ else if (context->arg_types[0].type_curr->tt_type == VAR_STRING)
expected = &t_string;
- else if (context->arg_types[0]->tt_type == VAR_BLOB)
+ else if (context->arg_types[0].type_curr->tt_type == VAR_BLOB)
expected = &t_number;
if (expected != NULL)
{
* Also accept a number, one and zero are accepted.
*/
static int
-arg_string_or_func(type_T *type, argcontext_T *context)
+arg_string_or_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a list of 'any' or a blob or a string.
*/
static int
-arg_string_list_or_blob(type_T *type, argcontext_T *context)
+arg_string_list_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a job.
*/
static int
-arg_job(type_T *type, argcontext_T *context)
+arg_job(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
return check_arg_type(&t_job, type, context);
}
* Check "type" is a channel or a job.
*/
static int
-arg_chan_or_job(type_T *type, argcontext_T *context)
+arg_chan_or_job(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
}
/*
- * Check "type" is the same type as the previous argument.
+ * Check "type" can be used as the type_decl of the previous argument.
* Must not be used for the first argcheck_T entry.
*/
static int
-arg_same_as_prev(type_T *type, argcontext_T *context)
+arg_same_as_prev(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
- type_T *prev_type = context->arg_types[context->arg_idx - 1];
+ type_T *prev_type = context->arg_types[context->arg_idx - 1].type_decl;
return check_arg_type(prev_type, type, context);
}
* Must not be used for the first argcheck_T entry.
*/
static int
-arg_same_struct_as_prev(type_T *type, argcontext_T *context)
+arg_same_struct_as_prev(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
- type_T *prev_type = context->arg_types[context->arg_idx - 1];
+ type_T *prev_type = context->arg_types[context->arg_idx - 1].type_curr;
- if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type)
+ if (prev_type->tt_type != context->arg_types[context->arg_idx].type_curr->tt_type)
return check_arg_type(prev_type, type, context);
return OK;
}
* Must not be used for the first argcheck_T entry.
*/
static int
-arg_item_of_prev(type_T *type, argcontext_T *context)
+arg_item_of_prev(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
- type_T *prev_type = context->arg_types[context->arg_idx - 1];
+ type_T *prev_type = context->arg_types[context->arg_idx - 1].type_curr;
type_T *expected;
if (prev_type->tt_type == VAR_LIST)
* Check "type" is a string or a number or a list
*/
static int
-arg_str_or_nr_or_list(type_T *type, argcontext_T *context)
+arg_str_or_nr_or_list(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Check "type" is a dict of 'any' or a string
*/
static int
-arg_dict_any_or_string(type_T *type, argcontext_T *context)
+arg_dict_any_or_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* any)
*/
static int
-arg_extend3(type_T *type, argcontext_T *context)
+arg_extend3(type_T *type, type_T *decl_type, argcontext_T *context)
{
- type_T *first_type = context->arg_types[context->arg_idx - 2];
+ type_T *first_type = context->arg_types[context->arg_idx - 2].type_curr;
if (first_type->tt_type == VAR_LIST)
- return arg_number(type, context);
+ return arg_number(type, decl_type, context);
if (first_type->tt_type == VAR_DICT)
- return arg_string(type, context);
+ return arg_string(type, decl_type, context);
return OK;
}
* funcref)
*/
static int
-arg_get1(type_T *type, argcontext_T *context)
+arg_get1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* blob or list or dict)
*/
static int
-arg_len1(type_T *type, argcontext_T *context)
+arg_len1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* any)
*/
static int
-arg_remove2(type_T *type, argcontext_T *context)
+arg_remove2(type_T *type, type_T *decl_type, argcontext_T *context)
{
- type_T *first_type = context->arg_types[context->arg_idx - 1];
+ type_T *first_type = context->arg_types[context->arg_idx - 1].type_curr;
if (first_type->tt_type == VAR_LIST || first_type->tt_type == VAR_BLOB)
- return arg_number(type, context);
+ return arg_number(type, decl_type, context);
if (first_type->tt_type == VAR_DICT)
- return arg_string_or_nr(type, context);
+ return arg_string_or_nr(type, decl_type, context);
return OK;
}
* list or any)
*/
static int
-arg_repeat1(type_T *type, argcontext_T *context)
+arg_repeat1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* or any)
*/
static int
-arg_slice1(type_T *type, argcontext_T *context)
+arg_slice1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* or any)
*/
static int
-arg_count1(type_T *type, argcontext_T *context)
+arg_count1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* list or any)
*/
static int
-arg_cursor1(type_T *type, argcontext_T *context)
+arg_cursor1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
{
if (type->tt_type == VAR_ANY
|| type->tt_type == VAR_UNKNOWN
* Note that "argtypes" is NULL if "argcount" is zero.
*/
static type_T *
-ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_void(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_void;
}
static type_T *
-ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_any(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_any;
}
static type_T *
-ret_bool(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_bool(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_bool;
}
static type_T *
-ret_number_bool(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_number_bool(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_number_bool;
}
static type_T *
-ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_number(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_number;
}
static type_T *
-ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_float(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_float;
}
static type_T *
-ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_string(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_string;
}
static type_T *
-ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_list_any(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_list_any;
}
static type_T *
-ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_list_number(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_list_number;
}
static type_T *
-ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_list_string(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_list_string;
}
static type_T *
-ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_list_dict_any(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_list_dict_any;
}
static type_T *
-ret_list_items(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_list_items(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_list_list_any;
}
static type_T *
-ret_list_string_items(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_list_string_items(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_list_list_string;
}
static type_T *
-ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_dict_any(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_dict_any;
}
static type_T *
-ret_job_info(int argcount, type_T **argtypes UNUSED)
+ret_job_info(int argcount, type2_T *argtypes UNUSED)
{
if (argcount == 0)
return &t_list_job;
return &t_dict_any;
}
static type_T *
-ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_dict_number(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_dict_number;
}
static type_T *
-ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_dict_string(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_dict_string;
}
static type_T *
-ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_blob(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_blob;
}
static type_T *
-ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_func_any(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_func_any;
}
static type_T *
-ret_func_unknown(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_func_unknown(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_func_unknown;
}
static type_T *
-ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_channel(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_channel;
}
static type_T *
-ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
+ret_job(int argcount UNUSED, type2_T *argtypes UNUSED)
{
return &t_job;
}
static type_T *
-ret_first_arg(int argcount, type_T **argtypes)
+ret_first_arg(int argcount, type2_T *argtypes)
{
if (argcount > 0)
- return argtypes[0];
+ return argtypes[0].type_curr;
return &t_void;
}
static type_T *
-ret_repeat(int argcount, type_T **argtypes)
+ret_repeat(int argcount, type2_T *argtypes)
{
if (argcount == 0)
return &t_any;
- if (argtypes[0] == &t_number)
+ if (argtypes[0].type_curr == &t_number)
return &t_string;
- return argtypes[0];
+ return argtypes[0].type_curr;
}
// for map(): returns first argument but item type may differ
static type_T *
-ret_first_cont(int argcount, type_T **argtypes)
+ret_first_cont(int argcount, type2_T *argtypes)
{
if (argcount > 0)
{
- if (argtypes[0]->tt_type == VAR_LIST)
+ if (argtypes[0].type_curr->tt_type == VAR_LIST)
return &t_list_any;
- if (argtypes[0]->tt_type == VAR_DICT)
+ if (argtypes[0].type_curr->tt_type == VAR_DICT)
return &t_dict_any;
- if (argtypes[0]->tt_type == VAR_BLOB)
- return argtypes[0];
+ if (argtypes[0].type_curr->tt_type == VAR_BLOB)
+ return argtypes[0].type_curr;
}
return &t_any;
}
+// for getline()
+ static type_T *
+ret_getline(int argcount, type2_T *argtypes UNUSED)
+{
+ return argcount == 1 ? &t_string : &t_list_string;
+}
// for finddir()
static type_T *
-ret_finddir(int argcount, type_T **argtypes UNUSED)
+ret_finddir(int argcount, type2_T *argtypes UNUSED)
{
if (argcount < 3)
return &t_string;
* one.
*/
static type_T *
-ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED)
+ret_list_or_dict_0(int argcount, type2_T *argtypes UNUSED)
{
if (argcount > 0)
return &t_dict_any;
* are two.
*/
static type_T *
-ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED)
+ret_list_or_dict_1(int argcount, type2_T *argtypes UNUSED)
{
if (argcount > 1)
return &t_dict_any;
}
static type_T *
-ret_argv(int argcount, type_T **argtypes UNUSED)
+ret_argv(int argcount, type2_T *argtypes UNUSED)
{
// argv() returns list of strings
if (argcount == 0)
}
static type_T *
-ret_remove(int argcount, type_T **argtypes)
+ret_remove(int argcount, type2_T *argtypes)
{
if (argcount > 0)
{
- if (argtypes[0]->tt_type == VAR_LIST
- || argtypes[0]->tt_type == VAR_DICT)
- return argtypes[0]->tt_member;
- if (argtypes[0]->tt_type == VAR_BLOB)
+ if (argtypes[0].type_curr->tt_type == VAR_LIST
+ || argtypes[0].type_curr->tt_type == VAR_DICT)
+ return argtypes[0].type_curr->tt_member;
+ if (argtypes[0].type_curr->tt_type == VAR_BLOB)
return &t_number;
}
return &t_any;
}
static type_T *
-ret_getreg(int argcount, type_T **argtypes UNUSED)
+ret_getreg(int argcount, type2_T *argtypes UNUSED)
{
// Assume that if the third argument is passed it's non-zero
if (argcount == 3)
}
static type_T *
-ret_maparg(int argcount, type_T **argtypes UNUSED)
+ret_maparg(int argcount, type2_T *argtypes UNUSED)
{
// Assume that if the fourth argument is passed it's non-zero
if (argcount == 4)
char f_max_argc; // maximal number of arguments
char f_argtype; // for method: FEARG_ values
argcheck_T *f_argcheck; // list of functions to check argument types
- type_T *(*f_retfunc)(int argcount, type_T **argtypes);
+ type_T *(*f_retfunc)(int argcount, type2_T *argtypes);
// return type function
void (*f_func)(typval_T *args, typval_T *rvar);
// implementation of function
{"getjumplist", 0, 2, FEARG_1, arg2_number,
ret_list_any, f_getjumplist},
{"getline", 1, 2, FEARG_1, arg2_lnum,
- ret_f_getline, f_getline},
+ ret_getline, f_getline},
{"getloclist", 1, 2, 0, arg2_number_dict_any,
ret_list_or_dict_1, f_getloclist},
{"getmarklist", 0, 1, FEARG_1, arg1_buffer,
*/
int
internal_func_check_arg_types(
- type_T **types,
+ type2_T *types,
int idx,
int argcount,
cctx_T *cctx)
if (argchecks[i] != NULL)
{
context.arg_idx = i;
- if (argchecks[i](types[i], &context) == FAIL)
+ if (argchecks[i](types[i].type_curr, types[i].type_decl,
+ &context) == FAIL)
return FAIL;
}
}
* "argcount" may be less than the actual count when only getting the type.
*/
type_T *
-internal_func_ret_type(int idx, int argcount, type_T **argtypes)
+internal_func_ret_type(int idx, int argcount, type2_T *argtypes)
{
return global_functions[idx].f_retfunc(argcount, argtypes);
}
l->lv_used_next->lv_used_prev = l->lv_used_prev;
free_type(l->lv_type);
+ free_type(l->lv_decl_type);
vim_free(l);
}
// The type will change.
free_type(l->lv_type);
l->lv_type = NULL;
+ free_type(l->lv_decl_type);
+ l->lv_decl_type = NULL;
}
else
{
if (copy != NULL)
{
copy->lv_type = alloc_type(orig->lv_type);
+ copy->lv_decl_type = alloc_type(orig->lv_decl_type);
if (copyID != 0)
{
// Do this before adding the items, because one of the items may
void f_deletebufline(typval_T *argvars, typval_T *rettv);
void f_getbufinfo(typval_T *argvars, typval_T *rettv);
void f_getbufline(typval_T *argvars, typval_T *rettv);
-type_T *ret_f_getline(int argcount, type_T **argtypes);
void f_getline(typval_T *argvars, typval_T *rettv);
void f_setbufline(typval_T *argvars, typval_T *rettv);
void f_setline(typval_T *argvars, typval_T *rettv);
int find_internal_func(char_u *name);
int has_internal_func(char_u *name);
char *internal_func_name(int idx);
-int internal_func_check_arg_types(type_T **types, int idx, int argcount, cctx_T *cctx);
+int internal_func_check_arg_types(type2_T *types, int idx, int argcount, cctx_T *cctx);
void internal_func_get_argcount(int idx, int *argcount, int *min_argcount);
-type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes);
+type_T *internal_func_ret_type(int idx, int argcount, type2_T *argtypes);
int internal_func_is_map(int idx);
int check_internal_func(int idx, int argcount);
int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv);
/* vim9instr.c */
isn_T *generate_instr(cctx_T *cctx, isntype_T isn_type);
isn_T *generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop);
+isn_T *generate_instr_type2(cctx_T *cctx, isntype_T isn_type, type_T *type, type_T *decl_type);
isn_T *generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type);
isn_T *generate_instr_debug(cctx_T *cctx);
int may_generate_2STRING(int offset, int tolerant, cctx_T *cctx);
type_T *get_func_type(type_T *ret_type, int argcount, garray_T *type_gap);
int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap);
int need_convert_to_bool(type_T *type, typval_T *tv);
-type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int do_member);
+type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags);
type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap);
int check_typval_arg_type(type_T *expected, typval_T *actual_tv, char *func_name, int arg_idx);
int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where);
type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error);
int equal_type(type_T *type1, type_T *type2, int flags);
void common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap);
-type_T *get_member_type_from_stack(type_T **stack_top, int count, int skip, garray_T *type_gap);
+int push_type_stack(cctx_T *cctx, type_T *type);
+int push_type_stack2(cctx_T *cctx, type_T *type, type_T *decl_type);
+void set_type_on_stack(cctx_T *cctx, type_T *type, int offset);
+type_T *get_type_on_stack(cctx_T *cctx, int offset);
+type_T *get_member_type_from_stack(int count, int skip, type_T **decl_type, cctx_T *cctx);
char *vartype_name(vartype_T type);
char *type_name(type_T *type, char **tofree);
void f_typename(typval_T *argvars, typval_T *rettv);
type_T **tt_args; // func argument types, allocated
};
+typedef struct {
+ type_T *type_curr; // current type, value type
+ type_T *type_decl; // declared type or equal to type_current
+} type2_T;
+
#define TTFLAG_VARARGS 1 // func args ends with "..."
#define TTFLAG_OPTARG 2 // func arg type with "?"
#define TTFLAG_BOOL_OK 4 // can be converted to bool
int lv_idx; // cached index of an item
} mat;
} lv_u;
- type_T *lv_type; // allocated by alloc_type()
+ type_T *lv_type; // current type, allocated by alloc_type()
+ type_T *lv_decl_type; // declared type, allocated by alloc_type()
list_T *lv_copylist; // copied list used by deepcopy()
list_T *lv_used_next; // next list in used lists list
list_T *lv_used_prev; // previous list in used lists list
int dv_refcount; // reference count
int dv_copyID; // ID used by deepcopy()
hashtab_T dv_hashtab; // hashtab that refers to the items
- type_T *dv_type; // allocated by alloc_type()
+ type_T *dv_type; // current type, allocated by alloc_type()
+ type_T *dv_decl_type; // declared type, allocated by alloc_type()
dict_T *dv_copydict; // copied dict used by deepcopy()
dict_T *dv_used_next; // next dict in used dicts list
dict_T *dv_used_prev; // previous dict in used dicts list
extend(test_null_list(), ['x'])
END
CheckScriptFailure(lines, 'E1134:', 2)
+
+ # using global var has no declared type
+ g:myList = []
+ g:myList->extend([1])
+ g:myList->extend(['x'])
+ assert_equal([1, 'x'], g:myList)
+ unlet g:myList
+
+ # using declared list gives an error
+ lines =<< trim END
+ var l: list<number>
+ g:myList = l
+ g:myList->extend([1])
+ g:myList->extend(['x'])
+ END
+ CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 4)
+ unlet g:myList
enddef
def Test_extend_dict()
var anyDict: dict<any> = {a: 0}
assert_equal({a: 0, b: 'x'}, extend(anyDict, {b: 'x'}))
+ # using global var, which has no declared type
+ g:myDict = {}
+ g:myDict->extend({a: 1})
+ g:myDict->extend({b: 'x'})
+ assert_equal({a: 1, b: 'x'}, g:myDict)
+ unlet g:myDict
+
+ # using list with declared type gives an error
+ lines =<< trim END
+ var d: dict<number>
+ g:myDict = d
+ g:myDict->extend({a: 1})
+ g:myDict->extend({b: 'x'})
+ END
+ CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>', 4)
+ unlet g:myDict
+
# assignment to script-local dict
lines =<< trim END
vim9script
END
CheckDefAndScriptSuccess(lines)
- # FIXME: this should not fail when compiled
lines =<< trim END
- vim9script
assert_equal([1, 2, "x"], extend([1, 2], ["x"]))
assert_equal([1, "b", 1], extend([1], ["b", 1]))
+
+ assert_equal({a: 1, b: "x"}, extend({a: 1}, {b: "x"}))
END
- CheckScriptSuccess(lines)
+ CheckDefAndScriptSuccess(lines)
CheckDefAndScriptFailure(['extend("a", 1)'], ['E1013: Argument 1: type mismatch, expected list<any> but got string', 'E712: Argument of extend() must be a List or Dictionary'])
- CheckDefAndScriptFailure(['extend([1, 2], 3)'], ['E1013: Argument 2: type mismatch, expected list<number> but got number', 'E712: Argument of extend() must be a List or Dictionary'])
+ CheckDefAndScriptFailure(['extend([1, 2], 3)'], ['E1013: Argument 2: type mismatch, expected list<any> but got number', 'E712: Argument of extend() must be a List or Dictionary'])
CheckDefAndScriptFailure(['var ll = [1, 2]', 'extend(ll, ["x"])'], ['E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>'])
CheckDefFailure(['extend([1, 2], [3], "x")'], 'E1013: Argument 3: type mismatch, expected number but got string')
- CheckDefFailure(['extend({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict<number> but got number')
- CheckDefFailure(['extend({a: 1}, {b: "x"})'], 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>')
+ CheckDefFailure(['extend({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict<any> but got number')
CheckDefFailure(['extend({a: 1}, {b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number')
- CheckDefFailure(['extend([1], ["b"])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>')
- CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<any>')
-
CheckScriptFailure(['vim9script', 'var l = [1]', 'extend(l, ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<any> in extend()')
enddef
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 3996,
/**/
3995,
/**/
int var_list = FALSE;
int semicolon = FALSE;
size_t varlen;
- garray_T *stack = &cctx->ctx_type_stack;
garray_T *instr = &cctx->ctx_instr;
scope_T *scope;
lvar_T *loop_lvar; // loop iteration variable
{
// If we know the type of "var" and it is not a supported type we can
// give an error now.
- vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ vartype = get_type_on_stack(cctx, 0);
if (vartype->tt_type != VAR_LIST
&& vartype->tt_type != VAR_STRING
&& vartype->tt_type != VAR_BLOB
generate_UNPACK(cctx, var_count, semicolon);
arg = skipwhite(arg + 1); // skip white after '['
- // the list item is replaced by a number of items
- if (GA_GROW_FAILS(stack, var_count - 1))
- {
- drop_scope(cctx);
- return NULL;
- }
- --stack->ga_len;
+ // drop the list item
+ --cctx->ctx_type_stack.ga_len;
+
+ // add type of the items
for (idx = 0; idx < var_count; ++idx)
{
- ((type_T **)stack->ga_data)[stack->ga_len] =
- (semicolon && idx == 0) ? vartype : item_type;
- ++stack->ga_len;
+ type_T *type = (semicolon && idx == 0) ? vartype : item_type;
+
+ if (push_type_stack(cctx, type) == FAIL)
+ {
+ drop_scope(cctx);
+ return NULL;
+ }
}
}
char_u *expr_start;
int count = 0;
int start_ctx_lnum = cctx->ctx_lnum;
- garray_T *stack = &cctx->ctx_type_stack;
type_T *type;
for (;;)
if (cctx->ctx_skip != SKIP_YES)
{
// check for non-void type
- type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ type = get_type_on_stack(cctx, 0);
if (type->tt_type == VAR_VOID)
{
semsg(_(e_expression_does_not_result_in_value_str), expr_start);
compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx)
{
char_u *p = arg;
- garray_T *stack = &cctx->ctx_type_stack;
type_T *stack_type;
if (*p != NUL && *p != '|' && *p != '\n')
// "check_return_type" with uf_ret_type set to &t_unknown is used
// for an inline function without a specified return type. Set the
// return type here.
- stack_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ stack_type = get_type_on_stack(cctx, 0);
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_any))
int c = var_start[varlen];
int lines_len = cctx->ctx_ufunc->uf_lines.ga_len;
char_u *p = var_start;
- garray_T *stack = &cctx->ctx_type_stack;
int res;
// Evaluate "ll[expr]" of "ll[expr][idx]". End the line with a NUL and
return FAIL;
}
- lhs->lhs_type = stack->ga_len == 0 ? &t_void
- : ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ lhs->lhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void
+ : get_type_on_stack(cctx, 0);
// now we can properly check the type
if (rhs_type != NULL && lhs->lhs_type->tt_member != NULL
&& rhs_type != &t_void
cctx_T *cctx)
{
vartype_T dest_type;
- garray_T *stack = &cctx->ctx_type_stack;
int range = FALSE;
if (compile_assign_index(var_start, lhs, &range, cctx) == FAIL)
if (range)
{
- type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
+ type = get_type_on_stack(cctx, 1);
if (need_type(type, &t_number,
-1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
}
- type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ type = get_type_on_stack(cctx, 0);
if ((dest_type != VAR_BLOB && type != &t_special)
&& need_type(type, &t_number,
-1, 0, cctx, FALSE, FALSE) == FAIL)
int semicolon = 0;
int did_generate_slice = FALSE;
garray_T *instr = &cctx->ctx_instr;
- garray_T *stack = &cctx->ctx_type_stack;
char_u *op;
int oplen = 0;
int heredoc = FALSE;
int needed_list_len;
int did_check = FALSE;
- stacktype = stack->ga_len == 0 ? &t_void
- : ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ stacktype = cctx->ctx_type_stack.ga_len == 0 ? &t_void
+ : get_type_on_stack(cctx, 0);
if (stacktype->tt_type == VAR_VOID)
{
emsg(_(e_cannot_use_void_value));
goto theend;
}
- rhs_type = stack->ga_len == 0 ? &t_void
- : ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ rhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void
+ : get_type_on_stack(cctx, 0);
if (lhs.lhs_lvar != NULL && (is_decl || !lhs.lhs_has_type))
{
if ((rhs_type->tt_type == VAR_FUNC
else
{
expected = lhs.lhs_member_type;
- stacktype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ stacktype = get_type_on_stack(cctx, 0);
if (
#ifdef FEAT_FLOAT
// If variable is float operation with number is OK.
cctx.ctx_lnum = -1;
cctx.ctx_outer = outer_cctx;
ga_init2(&cctx.ctx_locals, sizeof(lvar_T), 10);
- ga_init2(&cctx.ctx_type_stack, sizeof(type_T *), 50);
+ // Each entry on the type stack consists of two type pointers.
+ ga_init2(&cctx.ctx_type_stack, sizeof(type2_T), 50);
ga_init2(&cctx.ctx_imports, sizeof(imported_T), 10);
cctx.ctx_type_list = &ufunc->uf_type_list;
ga_init2(&cctx.ctx_instr, sizeof(isn_T), 50);
SOURCING_LNUM = 0; // line number unknown
for (i = 0; i < count; ++i)
{
- garray_T *stack = &cctx.ctx_type_stack;
type_T *val_type;
int arg_idx = first_def_arg + i;
where_T where = WHERE_INIT;
// If no type specified use the type of the default value.
// Otherwise check that the default value type matches the
// specified type.
- val_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ val_type = get_type_on_stack(&cctx, 0);
where.wt_index = arg_idx + 1;
if (ufunc->uf_arg_types[arg_idx] == &t_unknown)
{
int
compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
{
- type_T **typep;
+ type2_T *typep;
garray_T *stack = &cctx->ctx_type_stack;
vartype_T vartype;
type_T *idxtype;
// We can index a list, dict and blob. If we don't know the type
// we can use the index value type. If we still don't know use an "ANY"
// instruction.
- typep = ((type_T **)stack->ga_data) + stack->ga_len
- - (is_slice ? 3 : 2);
- vartype = (*typep)->tt_type;
- idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ // TODO: what about the decl type?
+ typep = (((type2_T *)stack->ga_data) + stack->ga_len - (is_slice ? 3 : 2));
+ vartype = typep->type_curr->tt_type;
+ idxtype = (((type2_T *)stack->ga_data) + stack->ga_len - 1)->type_curr;
// If the index is a string, the variable must be a Dict.
- if ((*typep == &t_any || *typep == &t_unknown) && idxtype == &t_string)
+ if ((typep->type_curr == &t_any || typep->type_curr == &t_unknown)
+ && idxtype == &t_string)
vartype = VAR_DICT;
if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB)
{
return FAIL;
if (is_slice)
{
- idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
+ idxtype = get_type_on_stack(cctx, 1);
if (need_type(idxtype, &t_number, -2, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
emsg(_(e_cannot_slice_dictionary));
return FAIL;
}
- if ((*typep)->tt_type == VAR_DICT)
+ if (typep->type_curr->tt_type == VAR_DICT)
{
- *typep = (*typep)->tt_member;
- if (*typep == &t_unknown)
+ typep->type_curr = typep->type_curr->tt_member;
+ if (typep->type_curr == &t_unknown)
// empty dict was used
- *typep = &t_any;
+ typep->type_curr = &t_any;
+ if (typep->type_decl->tt_type == VAR_DICT)
+ {
+ typep->type_decl = typep->type_decl->tt_member;
+ if (typep->type_decl == &t_unknown)
+ // empty dict was used
+ typep->type_decl = &t_any;
+ }
+ else
+ typep->type_decl = typep->type_curr;
}
else
{
- if (need_type(*typep, &t_dict_any, -2, 0, cctx,
+ if (need_type(typep->type_curr, &t_dict_any, -2, 0, cctx,
FALSE, FALSE) == FAIL)
return FAIL;
- *typep = &t_any;
+ typep->type_curr = &t_any;
+ typep->type_decl = &t_any;
}
if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
return FAIL;
}
else if (vartype == VAR_STRING)
{
- *typep = &t_string;
+ typep->type_curr = &t_string;
+ typep->type_decl = &t_string;
if ((is_slice
? generate_instr_drop(cctx, ISN_STRSLICE, 2)
: generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL)
{
if (is_slice)
{
- *typep = &t_blob;
+ typep->type_curr = &t_blob;
+ typep->type_decl = &t_blob;
if (generate_instr_drop(cctx, ISN_BLOBSLICE, 2) == FAIL)
return FAIL;
}
else
{
- *typep = &t_number;
+ typep->type_curr = &t_number;
+ typep->type_decl = &t_number;
if (generate_instr_drop(cctx, ISN_BLOBINDEX, 1) == FAIL)
return FAIL;
}
}
- else if (vartype == VAR_LIST || *typep == &t_any || *typep == &t_unknown)
+ else if (vartype == VAR_LIST || typep->type_curr == &t_any
+ || typep->type_curr == &t_unknown)
{
if (is_slice)
{
}
else
{
- if ((*typep)->tt_type == VAR_LIST)
+ if (typep->type_curr->tt_type == VAR_LIST)
{
- *typep = (*typep)->tt_member;
- if (*typep == &t_unknown)
+ typep->type_curr = typep->type_curr->tt_member;
+ if (typep->type_curr == &t_unknown)
// empty list was used
- *typep = &t_any;
+ typep->type_curr = &t_any;
+ if (typep->type_decl->tt_type == VAR_LIST)
+ {
+ typep->type_decl = typep->type_decl->tt_member;
+ if (typep->type_decl == &t_unknown)
+ // empty list was used
+ typep->type_decl = &t_any;
+ }
+ else
+ typep->type_decl = typep->type_curr;
}
if (generate_instr_drop(cctx,
vartype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX, 1)
if (STRCMP(name, "add") == 0 && argcount == 2)
{
- garray_T *stack = &cctx->ctx_type_stack;
- type_T *type = ((type_T **)stack->ga_data)[
- stack->ga_len - 2];
+ type_T *type = get_type_on_stack(cctx, 1);
// add() can be compiled to instructions if we know the type
if (type->tt_type == VAR_LIST)
if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload
&& compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK)
{
- garray_T *stack = &cctx->ctx_type_stack;
- type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ type_T *type = get_type_on_stack(cctx, 0);
res = generate_PCALL(cctx, argcount, namebuf, type, FALSE);
goto theend;
int
bool_on_stack(cctx_T *cctx)
{
- garray_T *stack = &cctx->ctx_type_stack;
type_T *type;
- type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ type = get_type_on_stack(cctx, 0);
if (type == &t_bool)
return OK;
{
int negate = *p == '-';
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
type_T *type;
- type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ type = get_type_on_stack(cctx, 0);
if (type != &t_float && need_type(type, &t_number,
-1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
// is not a function call.
if (**arg == '(')
{
- garray_T *stack = &cctx->ctx_type_stack;
type_T *type;
int argcount = 0;
ppconst->pp_is_const = FALSE;
// funcref(arg)
- type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ type = get_type_on_stack(cctx, 0);
*arg = skipwhite(p + 1);
if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
// instructions of the expression and move the type of the
// expression after the argument types. This is what ISN_PCALL
// expects.
- stack = &cctx->ctx_type_stack;
arg_isn_count = cctx->ctx_instr.ga_len - expr_isn_end;
if (arg_isn_count > 0)
{
int expr_isn_count = expr_isn_end - expr_isn_start;
isn_T *isn = ALLOC_MULT(isn_T, expr_isn_count);
+ type_T *decl_type;
+ type2_T *typep;
if (isn == NULL)
return FAIL;
isn, sizeof(isn_T) * expr_isn_count);
vim_free(isn);
- type = ((type_T **)stack->ga_data)[type_idx_start];
- mch_memmove(((type_T **)stack->ga_data) + type_idx_start,
- ((type_T **)stack->ga_data) + type_idx_start + 1,
- sizeof(type_T *)
+ typep = ((type2_T *)stack->ga_data) + type_idx_start;
+ type = typep->type_curr;
+ decl_type = typep->type_decl;
+ mch_memmove(((type2_T *)stack->ga_data) + type_idx_start,
+ ((type2_T *)stack->ga_data) + type_idx_start + 1,
+ sizeof(type2_T)
* (stack->ga_len - type_idx_start - 1));
- ((type_T **)stack->ga_data)[stack->ga_len - 1] = type;
+ typep = ((type2_T *)stack->ga_data) + stack->ga_len - 1;
+ typep->type_curr = type;
+ typep->type_decl = decl_type;
}
- type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ type = get_type_on_stack(cctx, 0);
if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL)
return FAIL;
}
if (want_type != NULL)
{
- garray_T *stack = &cctx->ctx_type_stack;
type_T *actual;
where_T where = WHERE_INIT;
generate_ppconst(cctx, ppconst);
- actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ actual = get_type_on_stack(cctx, 0);
if (check_type_maybe(want_type, actual, FALSE, where) != OK)
{
if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE)
generate_JUMP(cctx, op_falsy
? JUMP_AND_KEEP_IF_TRUE : JUMP_IF_FALSE, 0);
if (op_falsy)
- type1 = ((type_T **)stack->ga_data)[stack->ga_len];
+ type1 = get_type_on_stack(cctx, -1);
}
// evaluate the second expression; any type is accepted
if (!op_falsy)
{
// remember the type and drop it
+ type1 = get_type_on_stack(cctx, 0);
--stack->ga_len;
- type1 = ((type_T **)stack->ga_data)[stack->ga_len];
end_idx = instr->ga_len;
generate_JUMP(cctx, JUMP_ALWAYS, 0);
ppconst->pp_is_const = FALSE;
// If the types differ, the result has a more generic type.
- typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
+ typep = &((((type2_T *)stack->ga_data)
+ + stack->ga_len - 1)->type_curr);
common_type(type1, *typep, typep, cctx->ctx_type_list);
// jump here from JUMP_ALWAYS or JUMP_AND_KEEP_IF_TRUE
isn_T *
generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop)
{
- garray_T *stack = &cctx->ctx_type_stack;
-
RETURN_NULL_IF_SKIP(cctx);
- stack->ga_len -= drop;
+ cctx->ctx_type_stack.ga_len -= drop;
return generate_instr(cctx, isn_type);
}
/*
- * Generate instruction "isn_type" and put "type" on the type stack.
+ * Generate instruction "isn_type" and put "type" on the type stack,
+ * use "decl_type" for the declared type.
*/
isn_T *
-generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type)
+generate_instr_type2(
+ cctx_T *cctx,
+ isntype_T isn_type,
+ type_T *type,
+ type_T *decl_type)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
if ((isn = generate_instr(cctx, isn_type)) == NULL)
return NULL;
- if (GA_GROW_FAILS(stack, 1))
+ if (push_type_stack2(cctx, type == NULL ? &t_any : type,
+ decl_type == NULL ? &t_any : decl_type) == FAIL)
return NULL;
- ((type_T **)stack->ga_data)[stack->ga_len] = type == NULL ? &t_any : type;
- ++stack->ga_len;
return isn;
}
+/*
+ * Generate instruction "isn_type" and put "type" on the type stack.
+ * Uses "any" for the declared type, which works for constants. For declared
+ * variables use generate_instr_type2().
+ */
+ isn_T *
+generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type)
+{
+ return generate_instr_type2(cctx, isn_type, type, &t_any);
+}
+
/*
* Generate an ISN_DEBUG instruction.
*/
{
isn_T *isn;
isntype_T isntype = ISN_2STRING;
- garray_T *stack = &cctx->ctx_type_stack;
- type_T **type;
+ type_T *type;
RETURN_OK_IF_SKIP(cctx);
- type = ((type_T **)stack->ga_data) + stack->ga_len + offset;
- switch ((*type)->tt_type)
+ type = get_type_on_stack(cctx, -1 - offset);
+ switch (type->tt_type)
{
// nothing to be done
case VAR_STRING: return OK;
case VAR_JOB:
case VAR_CHANNEL:
case VAR_INSTR:
- to_string_error((*type)->tt_type);
+ to_string_error(type->tt_type);
return FAIL;
}
- *type = &t_string;
+ set_type_on_stack(cctx, &t_string, -1 - offset);
if ((isn = generate_instr(cctx, isntype)) == NULL)
return FAIL;
isn->isn_arg.tostring.offset = offset;
type_T *type2,
exprtype_T expr_type)
{
- garray_T *stack = &cctx->ctx_type_stack;
isn_T *isn = generate_instr_drop(cctx,
vartype == VAR_NUMBER ? ISN_OPNR
: vartype == VAR_LIST ? ISN_ADDLIST
if (vartype == VAR_LIST
&& type1->tt_type == VAR_LIST && type2->tt_type == VAR_LIST
&& type1->tt_member != type2->tt_member)
- (((type_T **)stack->ga_data)[stack->ga_len - 1]) = &t_list_any;
+ set_type_on_stack(cctx, &t_list_any, 0);
return isn == NULL ? FAIL : OK;
}
int
generate_two_op(cctx_T *cctx, char_u *op)
{
- garray_T *stack = &cctx->ctx_type_stack;
type_T *type1;
type_T *type2;
vartype_T vartype;
RETURN_OK_IF_SKIP(cctx);
// Get the known type of the two items on the stack.
- type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2];
- type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ type1 = get_type_on_stack(cctx, 1);
+ type2 = get_type_on_stack(cctx, 0);
vartype = operator_type(type1, type2);
switch (*op)
&& (type2->tt_type == VAR_NUMBER || type2->tt_type == VAR_FLOAT))
type = &t_float;
#endif
- ((type_T **)stack->ga_data)[stack->ga_len - 1] = type;
+ set_type_on_stack(cctx, type, 0);
}
return OK;
// Get the known type of the two items on the stack. If they are matching
// use a type-specific instruction. Otherwise fall back to runtime type
// checking.
- type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2]->tt_type;
- type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type;
+ type1 = get_type_on_stack(cctx, 1)->tt_type;
+ type2 = get_type_on_stack(cctx, 0)->tt_type;
isntype = get_compare_isn(exprtype, type1, type2);
if (isntype == ISN_DROP)
return FAIL;
if (stack->ga_len >= 2)
{
--stack->ga_len;
- ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool;
+ set_type_on_stack(cctx, &t_bool, 0);
}
return OK;
generate_2BOOL(cctx_T *cctx, int invert, int offset)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_2BOOL)) == NULL)
isn->isn_arg.tobool.offset = offset;
// type becomes bool
- ((type_T **)stack->ga_data)[stack->ga_len + offset] = &t_bool;
+ set_type_on_stack(cctx, &t_bool, -1 - offset);
return OK;
}
generate_COND2BOOL(cctx_T *cctx)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_COND2BOOL)) == NULL)
return FAIL;
// type becomes bool
- ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool;
+ set_type_on_stack(cctx, &t_bool, 0);
return OK;
}
int argidx)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL)
isn->isn_arg.type.ct_arg_idx = (int8_T)argidx;
// type becomes expected
- ((type_T **)stack->ga_data)[stack->ga_len + offset] = expected;
+ set_type_on_stack(cctx, expected, -1 - offset);
return OK;
}
generate_PUSHNR(cctx_T *cctx, varnumber_T number)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr_type(cctx, ISN_PUSHNR, &t_number)) == NULL)
if (number == 0 || number == 1)
// A 0 or 1 number can also be used as a bool.
- ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_number_bool;
+ set_type_on_stack(cctx, &t_number_bool, 0);
return OK;
}
generate_GETITEM(cctx_T *cctx, int index, int with_op)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
- type_T *type = ((type_T **)stack->ga_data)[stack->ga_len
- - (with_op ? 2 : 1)];
+ type_T *type = get_type_on_stack(cctx, with_op ? 1 : 0);
type_T *item_type = &t_any;
RETURN_OK_IF_SKIP(cctx);
isn->isn_arg.getitem.gi_with_op = with_op;
// add the item type to the type stack
- if (GA_GROW_FAILS(stack, 1))
- return FAIL;
- ((type_T **)stack->ga_data)[stack->ga_len] = item_type;
- ++stack->ga_len;
- return OK;
+ return push_type_stack(cctx, item_type);
}
/*
isn_T *isn;
RETURN_OK_IF_SKIP(cctx);
- if ((isn = generate_instr_type(cctx, isn_type, type)) == NULL)
+ if ((isn = generate_instr_type2(cctx, isn_type, type, type)) == NULL)
return FAIL;
if (name != NULL)
isn->isn_arg.string = vim_strsave(name);
isn_T *isn;
RETURN_OK_IF_SKIP(cctx);
- if ((isn = generate_instr_type(cctx, ISN_LOADOUTER, type)) == NULL)
+ if ((isn = generate_instr_type2(cctx, ISN_LOADOUTER, type, type)) == NULL)
return FAIL;
isn->isn_arg.outer.outer_idx = idx;
isn->isn_arg.outer.outer_depth = nesting;
generate_NEWLIST(cctx_T *cctx, int count)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
+ type_T *member_type;
+ type_T *decl_member_type;
type_T *type;
- type_T *member;
+ type_T *decl_type;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_NEWLIST)) == NULL)
return FAIL;
isn->isn_arg.number = count;
- // get the member type from all the items on the stack.
- if (count == 0)
- member = &t_unknown;
- else
- member = get_member_type_from_stack(
- ((type_T **)stack->ga_data) + stack->ga_len, count, 1,
- cctx->ctx_type_list);
- type = get_list_type(member, cctx->ctx_type_list);
+ // Get the member type and the declared member type from all the items on
+ // the stack.
+ member_type = get_member_type_from_stack(count, 1, &decl_member_type, cctx);
+ type = get_list_type(member_type, cctx->ctx_type_list);
+ decl_type = get_list_type(decl_member_type, cctx->ctx_type_list);
// drop the value types
- stack->ga_len -= count;
+ cctx->ctx_type_stack.ga_len -= count;
// add the list type to the type stack
- if (GA_GROW_FAILS(stack, 1))
- return FAIL;
- ((type_T **)stack->ga_data)[stack->ga_len] = type;
- ++stack->ga_len;
-
- return OK;
+ return push_type_stack2(cctx, type, decl_type);
}
/*
generate_NEWDICT(cctx_T *cctx, int count)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
+ type_T *member_type;
+ type_T *decl_member_type;
type_T *type;
- type_T *member;
+ type_T *decl_type;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_NEWDICT)) == NULL)
return FAIL;
isn->isn_arg.number = count;
- if (count == 0)
- member = &t_void;
- else
- member = get_member_type_from_stack(
- ((type_T **)stack->ga_data) + stack->ga_len, count, 2,
- cctx->ctx_type_list);
- type = get_dict_type(member, cctx->ctx_type_list);
+ member_type = get_member_type_from_stack(count, 2,
+ &decl_member_type, cctx);
+ type = get_dict_type(member_type, cctx->ctx_type_list);
+ decl_type = get_dict_type(decl_member_type, cctx->ctx_type_list);
// drop the key and value types
- stack->ga_len -= 2 * count;
+ cctx->ctx_type_stack.ga_len -= 2 * count;
// add the dict type to the type stack
- if (GA_GROW_FAILS(stack, 1))
- return FAIL;
- ((type_T **)stack->ga_data)[stack->ga_len] = type;
- ++stack->ga_len;
-
- return OK;
+ return push_type_stack2(cctx, type, decl_type);
}
/*
generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
+ type_T *type;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
if (ufunc->uf_flags & FC_CLOSURE)
cctx->ctx_ufunc->uf_flags |= FC_CLOSURE;
- if (GA_GROW_FAILS(stack, 1))
- return FAIL;
- ((type_T **)stack->ga_data)[stack->ga_len] =
- ufunc->uf_func_type == NULL ? &t_func_any : ufunc->uf_func_type;
- ++stack->ga_len;
-
- return OK;
+ type = ufunc->uf_func_type == NULL ? &t_func_any : ufunc->uf_func_type;
+ return push_type_stack(cctx, type);
}
/*
generate_FOR(cctx_T *cctx, int loop_idx)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_FOR)) == NULL)
return FAIL;
isn->isn_arg.forloop.for_idx = loop_idx;
- if (GA_GROW_FAILS(stack, 1))
- return FAIL;
// type doesn't matter, will be stored next
- ((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
- ++stack->ga_len;
-
- return OK;
+ return push_type_stack(cctx, &t_any);
}
/*
* Generate an ISN_TRYCONT instruction.
isn_T *isn;
garray_T *stack = &cctx->ctx_type_stack;
int argoff;
- type_T **argtypes = NULL;
- type_T *shuffled_argtypes[MAX_FUNC_ARGS];
- type_T *maptype = NULL;
+ type2_T *typep;
+ type2_T *argtypes = NULL;
+ type2_T shuffled_argtypes[MAX_FUNC_ARGS];
+ type2_T *maptype = NULL;
+ type_T *type;
RETURN_OK_IF_SKIP(cctx);
argoff = check_internal_func(func_idx, argcount);
if (argcount > 0)
{
// Check the types of the arguments.
- argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
+ typep = ((type2_T *)stack->ga_data) + stack->ga_len - argcount;
if (method_call && argoff > 1)
{
int i;
for (i = 0; i < argcount; ++i)
shuffled_argtypes[i] = (i < argoff - 1)
- ? argtypes[i + 1]
- : (i == argoff - 1) ? argtypes[0] : argtypes[i];
+ ? typep[i + 1]
+ : (i == argoff - 1) ? typep[0] : typep[i];
+ argtypes = shuffled_argtypes;
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < argcount; ++i)
+ shuffled_argtypes[i] = typep[i];
argtypes = shuffled_argtypes;
}
if (internal_func_check_arg_types(argtypes, func_idx, argcount,
cctx) == FAIL)
return FAIL;
if (internal_func_is_map(func_idx))
- maptype = *argtypes;
+ maptype = argtypes;
}
if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
// Drop the argument types and push the return type.
stack->ga_len -= argcount;
- if (GA_GROW_FAILS(stack, 1))
+ type = internal_func_ret_type(func_idx, argcount, argtypes);
+ if (push_type_stack(cctx, type) == FAIL)
return FAIL;
- ((type_T **)stack->ga_data)[stack->ga_len] =
- internal_func_ret_type(func_idx, argcount, argtypes);
- ++stack->ga_len;
- if (maptype != NULL && maptype->tt_member != NULL
- && maptype->tt_member != &t_any)
+ if (maptype != NULL && maptype[0].type_curr->tt_member != NULL
+ && maptype[0].type_curr->tt_member != &t_any)
// Check that map() didn't change the item types.
- generate_TYPECHECK(cctx, maptype, -1, 1);
+ generate_TYPECHECK(cctx, maptype[0].type_curr, -1, 1);
return OK;
}
int
generate_LISTAPPEND(cctx_T *cctx)
{
- garray_T *stack = &cctx->ctx_type_stack;
type_T *list_type;
type_T *item_type;
type_T *expected;
// Caller already checked that list_type is a list.
- list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
- item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ list_type = get_type_on_stack(cctx, 1);
+ item_type = get_type_on_stack(cctx, 0);
expected = list_type->tt_member;
if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
return FAIL;
- --stack->ga_len; // drop the argument
+ --cctx->ctx_type_stack.ga_len; // drop the argument
return OK;
}
int
generate_BLOBAPPEND(cctx_T *cctx)
{
- garray_T *stack = &cctx->ctx_type_stack;
type_T *item_type;
// Caller already checked that blob_type is a blob.
- item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ item_type = get_type_on_stack(cctx, 0);
if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
return FAIL;
if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
return FAIL;
- --stack->ga_len; // drop the argument
+ --cctx->ctx_type_stack.ga_len; // drop the argument
return OK;
}
generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
int regular_args = ufunc->uf_args.ga_len;
int argcount = pushed_argcount;
type_T *expected;
type_T *actual;
- actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
+ actual = get_type_on_stack(cctx, argcount - i - 1);
if (actual == &t_special
&& i >= regular_args - ufunc->uf_def_args.ga_len)
{
isn->isn_arg.ufunc.cuf_argcount = argcount;
}
- stack->ga_len -= argcount; // drop the arguments
- if (GA_GROW_FAILS(stack, 1))
- return FAIL;
- // add return value
- ((type_T **)stack->ga_data)[stack->ga_len] = ufunc->uf_ret_type;
- ++stack->ga_len;
+ // drop the argument types
+ cctx->ctx_type_stack.ga_len -= argcount;
- return OK;
+ // add return type
+ return push_type_stack(cctx, ufunc->uf_ret_type);
}
/*
generate_UCALL(cctx_T *cctx, char_u *name, int argcount)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_UCALL)) == NULL)
isn->isn_arg.ufunc.cuf_name = vim_strsave(name);
isn->isn_arg.ufunc.cuf_argcount = argcount;
- stack->ga_len -= argcount; // drop the arguments
- if (GA_GROW_FAILS(stack, 1))
- return FAIL;
- // add return value
- ((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
- ++stack->ga_len;
+ // drop the argument types
+ cctx->ctx_type_stack.ga_len -= argcount;
- return OK;
+ // add return value
+ return push_type_stack(cctx, &t_any);
}
/*
int at_top)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
type_T *ret_type;
RETURN_OK_IF_SKIP(cctx);
for (i = 0; i < argcount; ++i)
{
int offset = -argcount + i - (at_top ? 0 : 1);
- type_T *actual = ((type_T **)stack->ga_data)[
- stack->ga_len + offset];
+ type_T *actual = get_type_on_stack(cctx, -1 - offset);
type_T *expected;
if (varargs && i >= type->tt_argcount - 1)
isn->isn_arg.pfunc.cpf_top = at_top;
isn->isn_arg.pfunc.cpf_argcount = argcount;
- stack->ga_len -= argcount; // drop the arguments
+ // drop the arguments and the funcref/partial
+ cctx->ctx_type_stack.ga_len -= argcount + 1;
- // drop the funcref/partial, get back the return value
- ((type_T **)stack->ga_data)[stack->ga_len - 1] = ret_type;
+ // push the return value
+ push_type_stack(cctx, ret_type);
// If partial is above the arguments it must be cleared and replaced with
// the return value.
generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
type_T *type;
RETURN_OK_IF_SKIP(cctx);
isn->isn_arg.string = vim_strnsave(name, len);
// check for dict type
- type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ type = get_type_on_stack(cctx, 0);
if (type->tt_type != VAR_DICT && type != &t_any && type != &t_unknown)
{
char *tofree;
// change dict type to dict member type
if (type->tt_type == VAR_DICT)
{
- ((type_T **)stack->ga_data)[stack->ga_len - 1] =
- type->tt_member == &t_unknown ? &t_any : type->tt_member;
+ type_T *ntype = type->tt_member == &t_unknown
+ ? &t_any : type->tt_member;
+ set_type_on_stack(cctx, ntype, 0);
}
return OK;
generate_LEGACY_EVAL(cctx_T *cctx, char_u *line)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
RETURN_OK_IF_SKIP(cctx);
if ((isn = generate_instr(cctx, ISN_LEGACY_EVAL)) == NULL)
return FAIL;
isn->isn_arg.string = vim_strsave(line);
- if (GA_GROW_FAILS(stack, 1))
- return FAIL;
- ((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
- ++stack->ga_len;
-
- return OK;
+ return push_type_stack(cctx, &t_any);
}
int
generate_RANGE(cctx_T *cctx, char_u *range)
{
isn_T *isn;
- garray_T *stack = &cctx->ctx_type_stack;
if ((isn = generate_instr(cctx, ISN_RANGE)) == NULL)
return FAIL;
isn->isn_arg.string = range;
- if (GA_GROW_FAILS(stack, 1))
- return FAIL;
- ((type_T **)stack->ga_data)[stack->ga_len] = &t_number;
- ++stack->ga_len;
- return OK;
+ return push_type_stack(cctx, &t_number);
}
int
}
/*
- * Get the member type of a dict or list from the items on the stack.
- * "stack_top" points just after the last type on the type stack.
+ * Push an entry onto the type stack. "type" used both for the current type
+ * and the declared type.
+ * Returns FAIL when out of memory.
+ */
+ int
+push_type_stack(cctx_T *cctx, type_T *type)
+{
+ return push_type_stack2(cctx, type, type);
+}
+
+/*
+ * Push an entry onto the type stack. "type" is the current type, "decl_type"
+ * is the declared type.
+ * Returns FAIL when out of memory.
+ */
+ int
+push_type_stack2(cctx_T *cctx, type_T *type, type_T *decl_type)
+{
+ garray_T *stack = &cctx->ctx_type_stack;
+ type2_T *typep;
+
+ if (GA_GROW_FAILS(stack, 1))
+ return FAIL;
+ typep = ((type2_T *)stack->ga_data) + stack->ga_len;
+ typep->type_curr = type;
+ typep->type_decl = decl_type;
+ ++stack->ga_len;
+ return OK;
+}
+
+/*
+ * Set the type of the top of the stack to "type".
+ */
+ void
+set_type_on_stack(cctx_T *cctx, type_T *type, int offset)
+{
+ garray_T *stack = &cctx->ctx_type_stack;
+ type2_T *typep = ((type2_T *)stack->ga_data)
+ + stack->ga_len - 1 - offset;
+
+ typep->type_curr = type;
+ typep->type_decl = &t_any;
+}
+
+/*
+ * Get the type from the type stack. If "offset" is zero the one at the top,
+ * if "offset" is one the type above that, etc.
+ * Returns &t_unknown if there is no such stack entry.
+ */
+ type_T *
+get_type_on_stack(cctx_T *cctx, int offset)
+{
+ garray_T *stack = &cctx->ctx_type_stack;
+
+ if (offset + 1 > stack->ga_len)
+ return &t_unknown;
+ return (((type2_T *)stack->ga_data) + stack->ga_len - offset - 1)
+ ->type_curr;
+}
+
+/*
+ * Get the member type of a dict or list from the items on the stack of "cctx".
+ * The declared type is stored in "decl_type".
* For a list "skip" is 1, for a dict "skip" is 2, keys are skipped.
* Returns &t_void for an empty list or dict.
* Otherwise finds the common type of all items.
*/
type_T *
get_member_type_from_stack(
- type_T **stack_top,
int count,
int skip,
- garray_T *type_gap)
+ type_T **decl_type,
+ cctx_T *cctx)
{
- int i;
- type_T *result;
- type_T *type;
+ garray_T *stack = &cctx->ctx_type_stack;
+ type2_T *typep = ((type2_T *)stack->ga_data) + stack->ga_len;
+ garray_T *type_gap = cctx->ctx_type_list;
+ int i;
+ type_T *result;
+ type_T *decl_result;
+ type_T *type;
- // Use "any" for an empty list or dict.
+ // Use "unknown" for an empty list or dict.
if (count == 0)
+ {
+ *decl_type = &t_unknown;
return &t_unknown;
+ }
// Use the first value type for the list member type, then find the common
// type from following items.
- result = *(stack_top -(count * skip) + skip - 1);
+ result = (typep -(count * skip) + skip - 1)->type_curr;
+ decl_result = (typep -(count * skip) + skip - 1)->type_decl;
for (i = 1; i < count; ++i)
{
if (result == &t_any)
break; // won't get more common
- type = *(stack_top -((count - i) * skip) + skip - 1);
+ type = (typep -((count - i) * skip) + skip - 1)->type_curr;
common_type(type, result, &result, type_gap);
+ type = (typep -((count - i) * skip) + skip - 1)->type_decl;
+ common_type(type, decl_result, &decl_result, type_gap);
}
+ *decl_type = decl_result;
return result;
}