]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1203: return type of values() is always list<any> v9.0.1203
authorBram Moolenaar <Bram@vim.org>
Sun, 15 Jan 2023 18:17:12 +0000 (18:17 +0000)
committerBram Moolenaar <Bram@vim.org>
Sun, 15 Jan 2023 18:17:12 +0000 (18:17 +0000)
Problem:    Return type of values() is always list<any>.
Solution:   Use the member type if possible. (issue #11822)

src/evalfunc.c
src/proto/evalfunc.pro
src/testdir/test_vim9_builtin.vim
src/version.c
src/vim9instr.c
src/vim9type.c

index 0184d61778d289594178c68d7e2f3d4c0e0eb238..7639af8b24e9af6e4a9ef07cbe3585a751e40c52 100644 (file)
@@ -1136,6 +1136,8 @@ static argcheck_T arg23_win_execute[] = {arg_number, arg_string_or_list_string,
 static argcheck_T arg23_writefile[] = {arg_list_or_blob, arg_string, arg_string};
 static argcheck_T arg24_match_func[] = {arg_string_or_list_any, arg_string, arg_number, arg_number};
 
+// Can be used by functions called through "f_retfunc" to create new types.
+static garray_T *current_type_gap = NULL;
 
 /*
  * Functions that return the return type of a builtin function.
@@ -1438,6 +1440,29 @@ ret_finddir(int argcount,
     // Depending on the count would be a string or a list of strings.
     return &t_any;
 }
+// for values(): list of member of first argument
+    static type_T *
+ret_list_member(int argcount,
+       type2_T *argtypes,
+       type_T  **decl_type)
+{
+    if (argcount > 0)
+    {
+       type_T *t = argtypes[0].type_decl;
+       if (current_type_gap != NULL
+               && (t->tt_type == VAR_DICT || t->tt_type == VAR_LIST))
+           t = get_list_type(t->tt_member, current_type_gap);
+       else
+           t = &t_list_any;
+       *decl_type = t;
+
+       t = argtypes[0].type_curr;
+       if (current_type_gap != NULL
+               && (t->tt_type == VAR_DICT || t->tt_type == VAR_LIST))
+           return get_list_type(t->tt_member, current_type_gap);
+    }
+    return &t_list_any;
+}
 
 /*
  * Used for getqflist(): returns list if there is no argument, dict if there is
@@ -2759,7 +2784,7 @@ static funcentry_T global_functions[] =
     {"uniq",           1, 3, FEARG_1,      arg13_sortuniq,
                        ret_first_arg,      f_uniq},
     {"values",         1, 1, FEARG_1,      arg1_dict_any,
-                       ret_list_any,       f_values},
+                       ret_list_member,    f_values},
     {"virtcol",                1, 2, FEARG_1,      arg2_string_or_list_bool,
                        ret_virtcol,        f_virtcol},
     {"virtcol2col",    3, 3, FEARG_1,      arg3_number,
@@ -2993,14 +3018,17 @@ internal_func_ret_type(
        int         idx,
        int         argcount,
        type2_T     *argtypes,
-       type_T      **decl_type)
+       type_T      **decl_type,
+       garray_T    *type_gap)
 {
     type_T *ret;
 
+    current_type_gap = type_gap;
     *decl_type = NULL;
     ret = global_functions[idx].f_retfunc(argcount, argtypes, decl_type);
     if (*decl_type == NULL)
        *decl_type = ret;
+    current_type_gap = NULL;
     return ret;
 }
 
index da1c32411954983dbf36e788ba820552a746f6f2..78998ff62d6eada49f90f65edccb576700153469 100644 (file)
@@ -7,7 +7,7 @@ int has_internal_func(char_u *name);
 char *internal_func_name(int idx);
 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, type2_T *argtypes, type_T **decl_type);
+type_T *internal_func_ret_type(int idx, int argcount, type2_T *argtypes, type_T **decl_type, garray_T *type_gap);
 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 d0f49dd35b8d8ec9cfd62b915dfe84409b1def49..1e2b37857fcb65fe9ef73d86e0a8ef8ed1224ceb 100644 (file)
@@ -4740,6 +4740,31 @@ def Test_values()
   v9.CheckDefAndScriptFailure(['values([])'], ['E1013: Argument 1: type mismatch, expected dict<any> but got list<unknown>', 'E1206: Dictionary required for argument 1'])
   assert_equal([], {}->values())
   assert_equal(['sun'], {star: 'sun'}->values())
+
+  # the return type of values() is list<member>
+  var lines =<< trim END
+      vim9script
+
+      class Foo
+        this.val: number
+        def Add()
+          echo this.val
+        enddef
+      endclass
+
+      def Process(FooDict: dict<Foo>)
+        for foo in values(FooDict)
+          foo.Add()
+        endfor
+      enddef
+
+      disas Process
+
+      var D = {'x': Foo.new(22)}
+
+      Process(D)
+  END
+  v9.CheckScriptSuccess(lines)
 enddef
 
 def Test_virtcol()
index 4c9e486f28717a73726cd152490c22e600a279b4..f36b66651a32dcfa484124c04635f462dab0c272 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1203,
 /**/
     1202,
 /**/
index 72ecbaa65ed45415fb31177367370fc798440f5b..118e8858377d00a8d03685023354ecd0cfae6997 100644 (file)
@@ -1619,7 +1619,8 @@ 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;
-    type = internal_func_ret_type(func_idx, argcount, argtypes, &decl_type);
+    type = internal_func_ret_type(func_idx, argcount, argtypes, &decl_type,
+                                                         cctx->ctx_type_list);
     if (push_type_stack2(cctx, type, decl_type) == FAIL)
        return FAIL;
 
index 9bb53e2fa2dc3dc0a990eb52adbfaf3cc7c19bc5..fb32a8628ffc98428e974d1c1e71299af645d412 100644 (file)
@@ -539,7 +539,8 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags)
                type_T *decl_type;  // unused
 
                internal_func_get_argcount(idx, &argcount, &min_argcount);
-               member_type = internal_func_ret_type(idx, 0, NULL, &decl_type);
+               member_type = internal_func_ret_type(idx, 0, NULL, &decl_type,
+                                                                    type_gap);
            }
            else
                ufunc = find_func(name, FALSE);