# HG changeset patch # User Bram Moolenaar # Date 1641310206 -3600 # Node ID ccb9be1cdd7182d0fdb70d3b020d87b3337d87ad # Parent 2d3dd8065e25e223b3cf6d8f4c4b8ffbb0b3b7ff patch 8.2.3996: Vim9: type checking lacks information about declared type Commit: https://github.com/vim/vim/commit/078a46161e8b1b30bf306d6c1f4f0af7c616a989 Author: Bram Moolenaar Date: Tue Jan 4 15:17:03 2022 +0000 patch 8.2.3996: Vim9: type checking lacks information about declared type Problem: Vim9: type checking for list and dict lacks information about declared type. Solution: Add dv_decl_type and lv_decl_type. Refactor the type stack to store two types in each entry. diff --git a/src/dict.c b/src/dict.c --- a/src/dict.c +++ b/src/dict.c @@ -109,6 +109,8 @@ dict_free_contents(dict_T *d) 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; } /* @@ -1354,8 +1356,7 @@ dict_filter_map( 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; diff --git a/src/evalbuffer.c b/src/evalbuffer.c --- a/src/evalbuffer.c +++ b/src/evalbuffer.c @@ -807,12 +807,6 @@ f_getbufline(typval_T *argvars, typval_T 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 */ diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -195,7 +195,7 @@ static void f_xor(typval_T *argvars, typ // 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; @@ -203,7 +203,7 @@ typedef struct { // 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. @@ -225,7 +225,7 @@ check_arg_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 @@ -240,7 +240,7 @@ arg_float_or_nr(type_T *type, argcontext * 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); } @@ -249,7 +249,7 @@ arg_number(type_T *type, argcontext_T *c * 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); } @@ -258,7 +258,7 @@ arg_dict_any(type_T *type, argcontext_T * 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); } @@ -267,7 +267,7 @@ arg_list_any(type_T *type, argcontext_T * 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); } @@ -276,7 +276,7 @@ arg_list_number(type_T *type, argcontext * 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); } @@ -285,7 +285,7 @@ arg_list_string(type_T *type, argcontext * 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); } @@ -294,7 +294,7 @@ arg_string(type_T *type, argcontext_T *c * 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); } @@ -303,7 +303,7 @@ arg_blob(type_T *type, argcontext_T *con * 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); } @@ -312,7 +312,7 @@ arg_bool(type_T *type, argcontext_T *con * 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 @@ -327,7 +327,7 @@ arg_list_or_blob(type_T *type, argcontex * 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 @@ -342,7 +342,7 @@ arg_string_or_nr(type_T *type, argcontex * 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 @@ -357,7 +357,7 @@ arg_buffer(type_T *type, argcontext_T *c * 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 @@ -373,7 +373,7 @@ arg_buffer_or_dict_any(type_T *type, arg * 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 @@ -388,7 +388,7 @@ arg_lnum(type_T *type, argcontext_T *con * 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 @@ -411,7 +411,7 @@ arg_string_or_list_string(type_T *type, * 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 @@ -426,7 +426,7 @@ arg_string_or_list_any(type_T *type, arg * 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 @@ -441,7 +441,7 @@ arg_string_or_blob(type_T *type, argcont * 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 @@ -456,7 +456,7 @@ arg_list_or_dict(type_T *type, argcontex * 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 @@ -472,7 +472,7 @@ arg_list_or_dict_or_blob(type_T *type, a * 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 @@ -489,7 +489,7 @@ arg_list_or_dict_or_blob_or_string(type_ * 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 @@ -507,7 +507,7 @@ arg_filter_func(type_T *type, argcontext * 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 @@ -515,12 +515,12 @@ arg_map_func(type_T *type, argcontext_T { 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) { @@ -539,7 +539,7 @@ arg_map_func(type_T *type, argcontext_T * 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 @@ -557,7 +557,7 @@ arg_string_or_func(type_T *type, argcont * 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 @@ -573,7 +573,7 @@ arg_string_list_or_blob(type_T *type, ar * 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); } @@ -582,7 +582,7 @@ arg_job(type_T *type, argcontext_T *cont * 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 @@ -594,13 +594,13 @@ arg_chan_or_job(type_T *type, argcontext } /* - * 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) -{ - type_T *prev_type = context->arg_types[context->arg_idx - 1]; +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_decl; return check_arg_type(prev_type, type, context); } @@ -611,11 +611,11 @@ arg_same_as_prev(type_T *type, argcontex * Must not be used for the first argcheck_T entry. */ static int -arg_same_struct_as_prev(type_T *type, argcontext_T *context) -{ - type_T *prev_type = context->arg_types[context->arg_idx - 1]; - - if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type) +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_curr; + + 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; } @@ -625,9 +625,9 @@ arg_same_struct_as_prev(type_T *type, ar * Must not be used for the first argcheck_T entry. */ static int -arg_item_of_prev(type_T *type, argcontext_T *context) -{ - type_T *prev_type = context->arg_types[context->arg_idx - 1]; +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_curr; type_T *expected; if (prev_type->tt_type == VAR_LIST) @@ -645,7 +645,7 @@ arg_item_of_prev(type_T *type, argcontex * 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 @@ -661,7 +661,7 @@ arg_str_or_nr_or_list(type_T *type, argc * 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 @@ -677,14 +677,14 @@ arg_dict_any_or_string(type_T *type, arg * any) */ static int -arg_extend3(type_T *type, argcontext_T *context) -{ - type_T *first_type = context->arg_types[context->arg_idx - 2]; +arg_extend3(type_T *type, type_T *decl_type, argcontext_T *context) +{ + 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; } @@ -693,7 +693,7 @@ arg_extend3(type_T *type, argcontext_T * * 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 @@ -713,7 +713,7 @@ arg_get1(type_T *type, argcontext_T *con * 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 @@ -733,14 +733,14 @@ arg_len1(type_T *type, argcontext_T *con * any) */ static int -arg_remove2(type_T *type, argcontext_T *context) -{ - type_T *first_type = context->arg_types[context->arg_idx - 1]; +arg_remove2(type_T *type, type_T *decl_type, argcontext_T *context) +{ + 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; } @@ -749,7 +749,7 @@ arg_remove2(type_T *type, argcontext_T * * 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 @@ -767,7 +767,7 @@ arg_repeat1(type_T *type, argcontext_T * * 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 @@ -785,7 +785,7 @@ arg_slice1(type_T *type, argcontext_T *c * 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 @@ -803,7 +803,7 @@ arg_count1(type_T *type, argcontext_T *c * 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 @@ -960,152 +960,158 @@ static argcheck_T arg24_match_func[] = { * 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; @@ -1118,7 +1124,7 @@ ret_finddir(int argcount, type_T **argty * 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; @@ -1130,7 +1136,7 @@ ret_list_or_dict_0(int argcount, type_T * 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; @@ -1138,7 +1144,7 @@ ret_list_or_dict_1(int argcount, type_T } 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) @@ -1149,21 +1155,21 @@ ret_argv(int argcount, type_T **argtypes } 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) @@ -1172,7 +1178,7 @@ ret_getreg(int argcount, type_T **argtyp } 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) @@ -1191,7 +1197,7 @@ typedef struct 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 @@ -1599,7 +1605,7 @@ static funcentry_T global_functions[] = {"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, @@ -2576,7 +2582,7 @@ internal_func_name(int idx) */ int internal_func_check_arg_types( - type_T **types, + type2_T *types, int idx, int argcount, cctx_T *cctx) @@ -2595,7 +2601,8 @@ internal_func_check_arg_types( 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; } } @@ -2621,7 +2628,7 @@ internal_func_get_argcount(int idx, int * "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); } diff --git a/src/list.c b/src/list.c --- a/src/list.c +++ b/src/list.c @@ -271,6 +271,7 @@ list_free_list(list_T *l) 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); } @@ -1025,6 +1026,8 @@ flatten_common(typval_T *argvars, typval // 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 { @@ -1220,6 +1223,7 @@ list_copy(list_T *orig, int deep, int co 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 diff --git a/src/proto/evalbuffer.pro b/src/proto/evalbuffer.pro --- a/src/proto/evalbuffer.pro +++ b/src/proto/evalbuffer.pro @@ -16,7 +16,6 @@ void f_bufwinnr(typval_T *argvars, typva 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); diff --git a/src/proto/evalfunc.pro b/src/proto/evalfunc.pro --- a/src/proto/evalfunc.pro +++ b/src/proto/evalfunc.pro @@ -5,9 +5,9 @@ char_u *get_expr_name(expand_T *xp, int 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); diff --git a/src/proto/vim9instr.pro b/src/proto/vim9instr.pro --- a/src/proto/vim9instr.pro +++ b/src/proto/vim9instr.pro @@ -1,6 +1,7 @@ /* 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); diff --git a/src/proto/vim9type.pro b/src/proto/vim9type.pro --- a/src/proto/vim9type.pro +++ b/src/proto/vim9type.pro @@ -8,7 +8,7 @@ type_T *alloc_func_type(type_T *ret_type 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); @@ -22,7 +22,11 @@ char_u *skip_type(char_u *start, int opt 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); diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1422,6 +1422,11 @@ struct type_S { 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 @@ -1507,7 +1512,8 @@ struct listvar_S 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 @@ -1571,7 +1577,8 @@ struct dictvar_S 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 diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -639,6 +639,23 @@ def Test_extend_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 + g:myList = l + g:myList->extend([1]) + g:myList->extend(['x']) + END + CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected list but got list', 4) + unlet g:myList enddef def Test_extend_dict() @@ -963,6 +980,23 @@ def Test_assignment_dict() var anyDict: dict = {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 + g:myDict = d + g:myDict->extend({a: 1}) + g:myDict->extend({b: 'x'}) + END + CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict but got dict', 4) + unlet g:myDict + # assignment to script-local dict lines =<< trim END vim9script diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -982,26 +982,22 @@ def Test_extend_arg_types() 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 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 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 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 but got list', 'E1013: Argument 2: type mismatch, expected list but got list']) 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 but got number') - CheckDefFailure(['extend({a: 1}, {b: "x"})'], 'E1013: Argument 2: type mismatch, expected dict but got dict') + CheckDefFailure(['extend({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict 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 but got list') - CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list but got list') - CheckScriptFailure(['vim9script', 'var l = [1]', 'extend(l, ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list but got list in extend()') enddef diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3996, +/**/ 3995, /**/ 3994, diff --git a/src/vim9cmds.c b/src/vim9cmds.c --- a/src/vim9cmds.c +++ b/src/vim9cmds.c @@ -769,7 +769,6 @@ compile_for(char_u *arg_start, cctx_T *c 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 @@ -841,7 +840,7 @@ compile_for(char_u *arg_start, cctx_T *c { // 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 @@ -898,18 +897,19 @@ compile_for(char_u *arg_start, cctx_T *c 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; + } } } @@ -1647,7 +1647,6 @@ compile_mult_expr(char_u *arg, int cmdid 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 (;;) @@ -1661,7 +1660,7 @@ compile_mult_expr(char_u *arg, int cmdid 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); @@ -2182,7 +2181,6 @@ compile_cexpr(char_u *line, exarg_T *eap 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') @@ -2211,7 +2209,7 @@ compile_return(char_u *arg, int check_re // "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)) diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1639,7 +1639,6 @@ compile_load_lhs( 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 @@ -1657,8 +1656,8 @@ compile_load_lhs( 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 @@ -1717,7 +1716,6 @@ compile_assign_unlet( 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) @@ -1753,12 +1751,12 @@ compile_assign_unlet( 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) @@ -1837,7 +1835,6 @@ compile_assignment(char_u *arg, exarg_T 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; @@ -1929,8 +1926,8 @@ compile_assignment(char_u *arg, exarg_T 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)); @@ -2073,8 +2070,8 @@ compile_assignment(char_u *arg, exarg_T 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 @@ -2230,7 +2227,7 @@ compile_assignment(char_u *arg, exarg_T 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. @@ -2527,7 +2524,8 @@ compile_def_function( 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); @@ -2564,7 +2562,6 @@ compile_def_function( 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; @@ -2588,7 +2585,7 @@ compile_def_function( // 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) { diff --git a/src/vim9expr.c b/src/vim9expr.c --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -77,7 +77,7 @@ clear_ppconst(ppconst_T *ppconst) 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; @@ -85,12 +85,13 @@ compile_member(int is_slice, int *keepin // 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) { @@ -98,7 +99,7 @@ compile_member(int is_slice, int *keepin 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; @@ -112,19 +113,29 @@ compile_member(int is_slice, int *keepin 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; @@ -135,7 +146,8 @@ compile_member(int is_slice, int *keepin } 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) @@ -145,18 +157,21 @@ compile_member(int is_slice, int *keepin { 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) { @@ -167,12 +182,21 @@ compile_member(int is_slice, int *keepin } 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) @@ -709,9 +733,7 @@ compile_call( 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) @@ -758,8 +780,7 @@ compile_call( 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; @@ -1421,10 +1442,9 @@ skip_expr_cctx(char_u **arg, cctx_T *cct 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; @@ -1470,10 +1490,9 @@ compile_leader(cctx_T *cctx, int numeric { 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; @@ -1594,7 +1613,6 @@ compile_subscript( // is not a function call. if (**arg == '(') { - garray_T *stack = &cctx->ctx_type_stack; type_T *type; int argcount = 0; @@ -1603,7 +1621,7 @@ compile_subscript( 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) @@ -1672,12 +1690,13 @@ compile_subscript( // 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; @@ -1693,15 +1712,19 @@ compile_subscript( 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; } @@ -2152,12 +2175,11 @@ compile_expr7(char_u **arg, cctx_T *cctx 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) @@ -2781,7 +2803,7 @@ compile_expr1(char_u **arg, cctx_T *cctx 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 @@ -2797,8 +2819,8 @@ compile_expr1(char_u **arg, cctx_T *cctx 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); @@ -2849,7 +2871,8 @@ compile_expr1(char_u **arg, cctx_T *cctx 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 diff --git a/src/vim9instr.c b/src/vim9instr.c --- a/src/vim9instr.c +++ b/src/vim9instr.c @@ -57,31 +57,43 @@ generate_instr(cctx_T *cctx, isntype_T i 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, + * use "decl_type" for the declared type. + */ + isn_T * +generate_instr_type2( + cctx_T *cctx, + isntype_T isn_type, + type_T *type, + type_T *decl_type) +{ + isn_T *isn; + + if ((isn = generate_instr(cctx, isn_type)) == NULL) + return NULL; + + if (push_type_stack2(cctx, type == NULL ? &t_any : type, + decl_type == NULL ? &t_any : decl_type) == FAIL) + return NULL; + + 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) { - 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)) - return NULL; - ((type_T **)stack->ga_data)[stack->ga_len] = type == NULL ? &t_any : type; - ++stack->ga_len; - - return isn; + return generate_instr_type2(cctx, isn_type, type, &t_any); } /* @@ -111,12 +123,11 @@ may_generate_2STRING(int offset, int tol { 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; @@ -152,11 +163,11 @@ may_generate_2STRING(int offset, int tol 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; @@ -193,7 +204,6 @@ generate_add_instr( 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 @@ -225,7 +235,7 @@ generate_add_instr( 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; } @@ -256,7 +266,6 @@ operator_type(type_T *type1, type_T *typ 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; @@ -265,8 +274,8 @@ generate_two_op(cctx_T *cctx, char_u *op 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) @@ -323,7 +332,7 @@ generate_two_op(cctx_T *cctx, char_u *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; @@ -415,8 +424,8 @@ generate_COMPARE(cctx_T *cctx, exprtype_ // 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; @@ -430,7 +439,7 @@ generate_COMPARE(cctx_T *cctx, exprtype_ 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; @@ -444,7 +453,6 @@ generate_COMPARE(cctx_T *cctx, exprtype_ 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) @@ -453,7 +461,7 @@ generate_2BOOL(cctx_T *cctx, int invert, 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; } @@ -465,14 +473,13 @@ generate_2BOOL(cctx_T *cctx, int invert, 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; } @@ -485,7 +492,6 @@ generate_TYPECHECK( 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) @@ -495,7 +501,7 @@ generate_TYPECHECK( 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; } @@ -567,7 +573,6 @@ generate_tv_PUSH(cctx_T *cctx, typval_T 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) @@ -576,7 +581,7 @@ generate_PUSHNR(cctx_T *cctx, varnumber_ 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; } @@ -747,9 +752,7 @@ generate_PUSHFUNC(cctx_T *cctx, char_u * 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); @@ -767,11 +770,7 @@ generate_GETITEM(cctx_T *cctx, int index 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); } /* @@ -895,7 +894,7 @@ generate_LOAD( 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); @@ -918,7 +917,7 @@ generate_LOADOUTER( 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; @@ -1050,34 +1049,27 @@ generate_VIM9SCRIPT( 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); } /* @@ -1087,33 +1079,26 @@ generate_NEWLIST(cctx_T *cctx, int count 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); } /* @@ -1123,7 +1108,7 @@ generate_NEWDICT(cctx_T *cctx, int count 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) @@ -1139,13 +1124,8 @@ generate_FUNCREF(cctx_T *cctx, ufunc_T * 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); } /* @@ -1237,20 +1217,14 @@ generate_JUMP_IF_ARG_SET(cctx_T *cctx, i 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. @@ -1281,9 +1255,11 @@ generate_BCALL(cctx_T *cctx, int func_id 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); @@ -1301,22 +1277,30 @@ generate_BCALL(cctx_T *cctx, int func_id 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) @@ -1326,16 +1310,14 @@ generate_BCALL(cctx_T *cctx, int func_id // 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; } @@ -1347,14 +1329,13 @@ generate_BCALL(cctx_T *cctx, int func_id 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; @@ -1362,7 +1343,7 @@ generate_LISTAPPEND(cctx_T *cctx) 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; } @@ -1373,18 +1354,17 @@ generate_LISTAPPEND(cctx_T *cctx) 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; } @@ -1396,7 +1376,6 @@ generate_BLOBAPPEND(cctx_T *cctx) 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; @@ -1424,7 +1403,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufu 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) { @@ -1479,14 +1458,11 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufu 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); } /* @@ -1496,7 +1472,6 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufu 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) @@ -1504,14 +1479,11 @@ generate_UCALL(cctx_T *cctx, char_u *nam 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; + // drop the argument types + cctx->ctx_type_stack.ga_len -= argcount; + // add return value - ((type_T **)stack->ga_data)[stack->ga_len] = &t_any; - ++stack->ga_len; - - return OK; + return push_type_stack(cctx, &t_any); } /* @@ -1527,7 +1499,6 @@ generate_PCALL( int at_top) { isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; type_T *ret_type; RETURN_OK_IF_SKIP(cctx); @@ -1557,8 +1528,7 @@ generate_PCALL( 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) @@ -1594,10 +1564,11 @@ generate_PCALL( 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. @@ -1614,7 +1585,6 @@ generate_PCALL( 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); @@ -1623,7 +1593,7 @@ generate_STRINGMEMBER(cctx_T *cctx, char 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; @@ -1636,8 +1606,9 @@ generate_STRINGMEMBER(cctx_T *cctx, char // 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; @@ -1734,19 +1705,13 @@ generate_EXEC(cctx_T *cctx, isntype_T is 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 @@ -1767,17 +1732,12 @@ generate_EXECCONCAT(cctx_T *cctx, int co 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 diff --git a/src/vim9type.c b/src/vim9type.c --- a/src/vim9type.c +++ b/src/vim9type.c @@ -1192,38 +1192,110 @@ common_type(type_T *type1, type_T *type2 } /* - * 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; }