patch 8.2.4231: Vim9: map() gives type error when type was not declared

Problem:    Vim9: map() gives type error when type was not declared.
Solution:   Only check the type when it was declared, like extend() does.
            (closes #9635)
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 627ebb0..411d332 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -530,21 +530,30 @@
 
     if (type->tt_type == VAR_FUNC)
     {
-	if (type->tt_member != &t_any
-	    && type->tt_member != &t_unknown)
+	if (type->tt_member != &t_any && type->tt_member != &t_unknown)
 	{
 	    type_T *expected = NULL;
 
 	    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;
+	    {
+		// Use the declared type, so that an error is given if a
+		// declared list changes type, but not if a constant list
+		// changes type.
+		if (context->arg_types[0].type_decl->tt_type == VAR_LIST
+			|| context->arg_types[0].type_decl->tt_type == VAR_DICT)
+		    expected = context->arg_types[0].type_decl->tt_member;
+		else
+		    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].type_curr->tt_type == VAR_BLOB)
 		expected = &t_number;
 	    if (expected != NULL)
 	    {
-		type_T t_func_exp = {VAR_FUNC, -1, 0, TTFLAG_STATIC, NULL, NULL};
+		type_T t_func_exp = {VAR_FUNC, -1, 0, TTFLAG_STATIC,
+								   NULL, NULL};
 
 		t_func_exp.tt_member = expected;
 		return check_arg_type(&t_func_exp, type, context);
diff --git a/src/list.c b/src/list.c
index dca5ff0..a8b2207 100644
--- a/src/list.c
+++ b/src/list.c
@@ -580,15 +580,14 @@
     {
 	// empty list
 	l->lv_first = item;
-	l->lv_u.mat.lv_last = item;
 	item->li_prev = NULL;
     }
     else
     {
 	l->lv_u.mat.lv_last->li_next = item;
 	item->li_prev = l->lv_u.mat.lv_last;
-	l->lv_u.mat.lv_last = item;
     }
+    l->lv_u.mat.lv_last = item;
     ++l->lv_len;
     item->li_next = NULL;
 }
@@ -2362,8 +2361,7 @@
 	    tv.v_lock = 0;
 	    tv.vval.v_number = val;
 	    set_vim_var_nr(VV_KEY, idx);
-	    if (filter_map_one(&tv, expr, filtermap, &newtv, &rem)
-		    == FAIL)
+	    if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL)
 		break;
 	    if (did_emsg)
 	    {
@@ -2461,7 +2459,6 @@
 						    : N_("filter() argument"));
     int		save_did_emsg;
     type_T	*type = NULL;
-    garray_T	type_list;
 
     // map() and filter() return the first argument, also on failure.
     if (filtermap != FILTERMAP_MAPNEW && argvars[0].v_type != VAR_STRING)
@@ -2474,9 +2471,13 @@
 
     if (filtermap == FILTERMAP_MAP && in_vim9script())
     {
-	// Check that map() does not change the type of the dict.
-	ga_init2(&type_list, sizeof(type_T *), 10);
-	type = typval2type(argvars, get_copyID(), &type_list, TVTT_DO_MEMBER);
+	// Check that map() does not change the declared type of the list or
+	// dict.
+	if (argvars[0].v_type == VAR_DICT && argvars[0].vval.v_dict != NULL)
+	    type = argvars[0].vval.v_dict->dv_type;
+	else if (argvars[0].v_type == VAR_LIST
+					     && argvars[0].vval.v_list != NULL)
+	    type = argvars[0].vval.v_list->lv_type;
     }
 
     if (argvars[0].v_type != VAR_BLOB
@@ -2489,10 +2490,10 @@
 	goto theend;
     }
 
-    expr = &argvars[1];
     // On type errors, the preceding call has already displayed an error
     // message.  Avoid a misleading error message for an empty string that
     // was not passed as argument.
+    expr = &argvars[1];
     if (expr->v_type != VAR_UNKNOWN)
     {
 	typval_T	save_val;
@@ -2525,8 +2526,6 @@
     }
 
 theend:
-    if (type != NULL)
-	clear_type_list(&type_list);
 }
 
 /*
diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim
index 7f4d87a..0af1d5b 100644
--- a/src/testdir/test_vim9_assign.vim
+++ b/src/testdir/test_vim9_assign.vim
@@ -1963,7 +1963,7 @@
       var ll: list<number>
       ll = [1, 2, 3]->map('"one"')
   END
-  CheckDefExecFailure(lines, 'E1012: Type mismatch; expected number but got string')
+  CheckDefExecFailure(lines, 'E1012: Type mismatch; expected list<number> but got list<string>')
 enddef
 
 def Test_cannot_use_let()
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index 45d212c..32467b4 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -2230,13 +2230,18 @@
   END
   CheckDefExecAndScriptFailure(lines, 'E1190: 2 arguments too few')
 
+  # declared list cannot change type
   lines =<< trim END
     def Map(i: number, v: number): string
       return 'bad'
     enddef
-    echo map([1, 2, 3], Map)
+    var ll: list<number> = [1, 2, 3]
+    echo map(ll, Map)
   END
   CheckDefAndScriptFailure(lines, ['E1013: Argument 2: type mismatch, expected func(...): number but got func(number, number): string', 'E1012: Type mismatch; expected number but got string in map()'])
+
+  # not declared list can change type
+  echo [1, 2, 3]->map((..._) => 'x')
 enddef
 
 def Test_map_item_type()
diff --git a/src/version.c b/src/version.c
index cbc938a..7341fcc 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4231,
+/**/
     4230,
 /**/
     4229,
diff --git a/src/vim9instr.c b/src/vim9instr.c
index d000c4a..e869d9e 100644
--- a/src/vim9instr.c
+++ b/src/vim9instr.c
@@ -1331,10 +1331,10 @@
     if (push_type_stack(cctx, type) == FAIL)
 	return FAIL;
 
-    if (maptype != NULL && maptype[0].type_curr->tt_member != NULL
-				  && maptype[0].type_curr->tt_member != &t_any)
+    if (maptype != NULL && maptype[0].type_decl->tt_member != NULL
+				  && maptype[0].type_decl->tt_member != &t_any)
 	// Check that map() didn't change the item types.
-	generate_TYPECHECK(cctx, maptype[0].type_curr, -1, 1);
+	generate_TYPECHECK(cctx, maptype[0].type_decl, -1, 1);
 
     return OK;
 }