summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-01-04 15:17:03 +0000
committerBram Moolenaar <Bram@vim.org>2022-01-04 15:17:03 +0000
commit078a46161e8b1b30bf306d6c1f4f0af7c616a989 (patch)
tree334c2fa968e1641524028ac18afedf5980446e64
parent9acf2d8be93f3b50607279e7f3484b019675d0a7 (diff)
patch 8.2.3996: Vim9: type checking lacks information about declared typev8.2.3996
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.
-rw-r--r--src/dict.c5
-rw-r--r--src/evalbuffer.c6
-rw-r--r--src/evalfunc.c217
-rw-r--r--src/list.c4
-rw-r--r--src/proto/evalbuffer.pro1
-rw-r--r--src/proto/evalfunc.pro4
-rw-r--r--src/proto/vim9instr.pro1
-rw-r--r--src/proto/vim9type.pro8
-rw-r--r--src/structs.h11
-rw-r--r--src/testdir/test_vim9_assign.vim34
-rw-r--r--src/testdir/test_vim9_builtin.vim14
-rw-r--r--src/version.c2
-rw-r--r--src/vim9cmds.c30
-rw-r--r--src/vim9compile.c27
-rw-r--r--src/vim9expr.c111
-rw-r--r--src/vim9instr.c262
-rw-r--r--src/vim9type.c92
17 files changed, 464 insertions, 365 deletions
diff --git a/src/dict.c b/src/dict.c
index b3cdfd9b9e..27cde11a3f 100644
--- 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
index 37febe4059..58834785aa 100644
--- a/src/evalbuffer.c
+++ b/src/evalbuffer.c
@@ -807,12 +807,6 @@ f_getbufline(typval_T *argvars, typval_T *rettv)
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
index e469520730..8cb2d755d5 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -195,7 +195,7 @@ static void f_xor(typval_T *argvars, typval_T *rettv);
// 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_T *context)
* 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 *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);
}
@@ -258,7 +258,7 @@ arg_dict_any(type_T *type, argcontext_T *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);
}
@@ -267,7 +267,7 @@ arg_list_any(type_T *type, argcontext_T *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);
}
@@ -276,7 +276,7 @@ arg_list_number(type_T *type, argcontext_T *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);
}
@@ -285,7 +285,7 @@ arg_list_string(type_T *type, argcontext_T *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);
}
@@ -294,7 +294,7 @@ arg_string(type_T *type, argcontext_T *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);
}
@@ -303,7 +303,7 @@ arg_blob(type_T *type, argcontext_T *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);
}
@@ -312,7 +312,7 @@ arg_bool(type_T *type, argcontext_T *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
@@ -327,7 +327,7 @@ arg_list_or_blob(type_T *type, argcontext_T *context)
* 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, argcontext_T *context)
* 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 *context)
* 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, argcontext_T *context)
* 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 *context)
* 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, argcontext_T *context)
* 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, argcontext_T *context)
* 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, argcontext_T *context)
* 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, argcontext_T *context)
* 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, argcontext_T *context)
* 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_T *type, argcontext_T *context)
* 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_T *context)
* 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 *context)
{
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 *context)
* 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, argcontext_T *context)
* 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, argcontext_T *context)
* 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 *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
@@ -594,13 +594,13 @@ arg_chan_or_job(type_T *type, argcontext_T *context)
}
/*
- * 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);
}
@@ -611,11 +611,11 @@ arg_same_as_prev(type_T *type, argcontext_T *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;
}
@@ -625,9 +625,9 @@ arg_same_struct_as_prev(type_T *type, argcontext_T *context)
* 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)
@@ -645,7 +645,7 @@ arg_item_of_prev(type_T *type, argcontext_T *context)
* 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, argcontext_T *context)
* 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, argcontext_T *context)
* 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;
}
@@ -693,7 +693,7 @@ arg_extend3(type_T *type, argcontext_T *context)
* 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 *context)
* 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 *context)
* 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;
}
@@ -749,7 +749,7 @@ arg_remove2(type_T *type, argcontext_T *context)
* 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 *context)
* 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 *context)
* 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 *context)
* 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[] = {arg_string_or_list_any, arg_string, arg_
* 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 **argtypes UNUSED)
* 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 **argtypes UNUSED)
* 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 **argtypes UNUSED)
}
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 UNUSED)
}
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 **argtypes UNUSED)
}
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, int *min_argcount)
* "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
index aadc7233d0..6ad3e9211e 100644
--- 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_T *rettv, int make_copy)
// 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 copyID)
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
index 57c84ceb76..b59c5f5e9b 100644
--- a/src/proto/evalbuffer.pro
+++ b/src/proto/evalbuffer.pro
@@ -16,7 +16,6 @@ void f_bufwinnr(typval_T *argvars, typval_T *rettv);
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
index eb89e6452d..e508604983 100644
--- a/src/proto/evalfunc.pro
+++ b/src/proto/evalfunc.pro
@@ -5,9 +5,9 @@ char_u *get_expr_name(expand_T *xp, int idx);
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
index 0083334d91..b20dcf7d1b 100644
--- 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
index 0bdc227745..015531c1ed 100644
--- a/src/proto/vim9type.pro
+++ b/src/proto/vim9type.pro
@@ -8,7 +8,7 @@ type_T *alloc_func_type(type_T *ret_type, int argcount, garray_T *type_gap);
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 optional);
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
index 4e770f1187..7d040eb6f4 100644
--- a/src/structs.h
+++ b/src/structs.h