]> granicus.if.org Git - vim/commitdiff
patch 8.2.3996: Vim9: type checking lacks information about declared type v8.2.3996
authorBram Moolenaar <Bram@vim.org>
Tue, 4 Jan 2022 15:17:03 +0000 (15:17 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 4 Jan 2022 15:17:03 +0000 (15:17 +0000)
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.

17 files changed:
src/dict.c
src/evalbuffer.c
src/evalfunc.c
src/list.c
src/proto/evalbuffer.pro
src/proto/evalfunc.pro
src/proto/vim9instr.pro
src/proto/vim9type.pro
src/structs.h
src/testdir/test_vim9_assign.vim
src/testdir/test_vim9_builtin.vim
src/version.c
src/vim9cmds.c
src/vim9compile.c
src/vim9expr.c
src/vim9instr.c
src/vim9type.c

index b3cdfd9b9e6e4cda05845c10b53db27805f16c78..27cde11a3fbad815332e30eb8e41e7bcb581c2e5 100644 (file)
@@ -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;
index 37febe4059e068b3cf34590e88ecc81ce2cfdf84..58834785aa7eff6649cb264859e1a132d0542c46 100644 (file)
@@ -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
  */
index e469520730ee94e46037c3f773cae62eebee03bd..8cb2d755d594f098a2468231ceed93b1346805e4 100644 (file)
@@ -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);
 }
index aadc7233d0359c0bf908298edcb65c55bea16ef9..6ad3e9211ef7c5b08ab75b197d1848722d521221 100644 (file)
@@ -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
index 57c84ceb76c234ec6928a55d538a2f09d9cecd53..b59c5f5e9b1d1dfc3561e6e41bce67a58d1a5a2a 100644 (file)
@@ -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);
index eb89e6452d073c4d8904d36e3f2b254485db86d7..e5086049837a6cf070157315a4b506ed0546cacc 100644 (file)
@@ -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);
index 0083334d91f335d423f24396b2dc68ae2516940e..b20dcf7d1b153a3f6da4ace558d93ae234ff8047 100644 (file)
@@ -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);
index 0bdc2277454955cb45c49ec503dfd79a7bec0fe5..015531c1ed3c1844220290037b90c203ccc3c9f6 100644 (file)
@@ -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);
index 4e770f1187da2e038dc2e29db77aad799e422f3b..7d040eb6f480836cbb0bffb1c452e7951316541e 100644 (file)
@@ -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
index 223a6e401dd8273a3c6ba52c1809e3d082d35c95..c91cd6547379c0fc263602eb83d84c9966aa3a77 100644 (file)
@@ -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<number>
+      g:myList = l
+      g:myList->extend([1])
+      g:myList->extend(['x'])
+  END
+  CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 4)
+  unlet g:myList
 enddef
 
 def Test_extend_dict()
@@ -963,6 +980,23 @@ def Test_assignment_dict()
   var anyDict: dict<any> = {a: 0}
   assert_equal({a: 0, b: 'x'}, extend(anyDict, {b: 'x'}))
 
+  # using global var, which has no declared type
+  g:myDict = {}
+  g:myDict->extend({a: 1})
+  g:myDict->extend({b: 'x'})
+  assert_equal({a: 1, b: 'x'}, g:myDict)
+  unlet g:myDict
+
+  # using list with declared type gives an error
+  lines =<< trim END
+      var d: dict<number>
+      g:myDict = d
+      g:myDict->extend({a: 1})
+      g:myDict->extend({b: 'x'})
+  END
+  CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>', 4)
+  unlet g:myDict
+
   # assignment to script-local dict
   lines =<< trim END
     vim9script
index 7b835100c2c9a665b29b93d96a0cba850f54a1fb..d957c1502daa13cdefac0dab64c2b5138f39d79b 100644 (file)
@@ -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<any> but got string', 'E712: Argument of extend() must be a List or Dictionary'])
-  CheckDefAndScriptFailure(['extend([1, 2], 3)'], ['E1013: Argument 2: type mismatch, expected list<number> but got number', 'E712: Argument of extend() must be a List or Dictionary'])
+  CheckDefAndScriptFailure(['extend([1, 2], 3)'], ['E1013: Argument 2: type mismatch, expected list<any> but got number', 'E712: Argument of extend() must be a List or Dictionary'])
   CheckDefAndScriptFailure(['var ll = [1, 2]', 'extend(ll, ["x"])'], ['E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>'])
   CheckDefFailure(['extend([1, 2], [3], "x")'], 'E1013: Argument 3: type mismatch, expected number but got string')
 
-  CheckDefFailure(['extend({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict<number> but got number')
-  CheckDefFailure(['extend({a: 1}, {b: "x"})'], 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>')
+  CheckDefFailure(['extend({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict<any> but got number')
   CheckDefFailure(['extend({a: 1}, {b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number')
 
-  CheckDefFailure(['extend([1], ["b"])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>')
-  CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<any>')
-
   CheckScriptFailure(['vim9script', 'var l = [1]', 'extend(l, ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<any> in extend()')
 enddef
 
index b905932326b9eacabfd6e3b26fa0df4da15b92db..4d15dbf662839ceaf528c2bc78688fa75e12c98e 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3996,
 /**/
     3995,
 /**/
index e11825dde9db3e7a8864e4ebc6b6f3b7b4ac6bd0..2802ac37de6bc717bed90a6c6e810046afd609f7 100644 (file)
@@ -769,7 +769,6 @@ compile_for(char_u *arg_start, cctx_T *cctx)
     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 *cctx)
     {
        // 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 *cctx)
            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 cmdidx, cctx_T *cctx)
     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 cmdidx, cctx_T *cctx)
        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, cctx_T *cctx)
 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_return_type, int legacy, cctx_T *cctx)
            // "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))
index 026b18f39b2f159c40b900e5cb0246f4e6ab9713..a243e6435313e0c1ae7d60c1e2feb478a2901e15 100644 (file)
@@ -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 *eap, cmdidx_T cmdidx, cctx_T *cctx)
     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 *eap, cmdidx_T cmdidx, cctx_T *cctx)
            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 *eap, cmdidx_T cmdidx, cctx_T *cctx)
                        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 *eap, cmdidx_T cmdidx, cctx_T *cctx)
            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)
            {
index 0c3f3e503090da7c6f3484003e6ed96a7f87b861..76edddb1eaef3e12048673b1753c9b4c20831d8e 100644 (file)
@@ -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 *keeping_dict, cctx_T *cctx)
     // 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 *keeping_dict, cctx_T *cctx)
            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 *keeping_dict, cctx_T *cctx)
            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 *keeping_dict, cctx_T *cctx)
     }
     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 *keeping_dict, cctx_T *cctx)
     {
        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 *keeping_dict, cctx_T *cctx)
        }
        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 *cctx)
     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_only, char_u *start, char_u **end)
        {
            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, ppconst_T *ppconst)
 
     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, ppconst_T *ppconst)
            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, ppconst_T *ppconst)
            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_T *ppconst)
            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
index 49936c37bba2e0b451757a1b1e953adaacff2d0f..4961695f07992caf6ee4cdbc3aab2a90cdce39d7 100644 (file)
@@ -57,33 +57,45 @@ generate_instr(cctx_T *cctx, isntype_T isn_type)
     isn_T *
 generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop)
 {
-    garray_T   *stack = &cctx->ctx_type_stack;
-
     RETURN_NULL_IF_SKIP(cctx);
-    stack->ga_len -= drop;
+    cctx->ctx_type_stack.ga_len -= drop;
     return generate_instr(cctx, isn_type);
 }
 
 /*
- * Generate instruction "isn_type" and put "type" on the type stack.
+ * Generate instruction "isn_type" and put "type" on the type stack,
+ * use "decl_type" for the declared type.
  */
     isn_T *
-generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type)
+generate_instr_type2(
+       cctx_T      *cctx,
+       isntype_T   isn_type,
+       type_T      *type,
+       type_T      *decl_type)
 {
     isn_T      *isn;
-    garray_T   *stack = &cctx->ctx_type_stack;
 
     if ((isn = generate_instr(cctx, isn_type)) == NULL)
        return NULL;
 
-    if (GA_GROW_FAILS(stack, 1))
+    if (push_type_stack2(cctx, type == NULL ? &t_any : type,
+                              decl_type == NULL ? &t_any : decl_type) == FAIL)
        return NULL;
-    ((type_T **)stack->ga_data)[stack->ga_len] = type == NULL ? &t_any : type;
-    ++stack->ga_len;
 
     return isn;
 }
 
+/*
+ * Generate instruction "isn_type" and put "type" on the type stack.
+ * Uses "any" for the declared type, which works for constants.  For declared
+ * variables use generate_instr_type2().
+ */
+    isn_T *
+generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type)
+{
+    return generate_instr_type2(cctx, isn_type, type, &t_any);
+}
+
 /*
  * Generate an ISN_DEBUG instruction.
  */
@@ -111,12 +123,11 @@ may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
 {
     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 tolerant, cctx_T *cctx)
        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 *type2)
     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_T exprtype, int ic)
     // 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_T exprtype, int ic)
     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_T exprtype, int ic)
 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, int offset)
     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, int offset)
 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 *tv)
 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_T number)
 
     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 *name, type_T *type)
 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, int with_op)
     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 *ufunc)
     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, int arg_off)
 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_idx, int argcount, int method_call)
     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_idx, int argcount, int method_call)
     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_idx, int argcount, int method_call)
 
     // 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_idx, int argcount, int method_call)
     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 *ufunc, int pushed_argcount)
            type_T *expected;
            type_T *actual;
 
-           actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
+           actual = get_type_on_stack(cctx, argcount - i - 1);
            if (actual == &t_special
                              && i >= regular_args - ufunc->uf_def_args.ga_len)
            {
@@ -1479,14 +1458,11 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
        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 *ufunc, int pushed_argcount)
 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 *name, int argcount)
     isn->isn_arg.ufunc.cuf_name = vim_strsave(name);
     isn->isn_arg.ufunc.cuf_argcount = argcount;
 
-    stack->ga_len -= argcount; // drop the arguments
-    if (GA_GROW_FAILS(stack, 1))
-       return FAIL;
-    // add return value
-    ((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
-    ++stack->ga_len;
+    // drop the argument types
+    cctx->ctx_type_stack.ga_len -= argcount;
 
-    return OK;
+    // add return value
+    return push_type_stack(cctx, &t_any);
 }
 
 /*
@@ -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_u *name, size_t len)
     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_u *name, size_t len)
     // 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 isntype, char_u *str)
 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 count)
 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
index d07c6e6a08f70e541b70fd51b1440754ed7767e1..f2ed15b48c13917202e9ca60185f2e53c1b82960 100644 (file)
@@ -1192,38 +1192,110 @@ common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap)
 }
 
 /*
- * 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;
 }