patch 9.0.0615: using reduce() on a list from range() is a bit slow

Problem:    Using reduce() on a list from range() is a bit slow.
Solution:   Avoid materializing the list.
diff --git a/src/list.c b/src/list.c
index a7b2189..fab86fd 100644
--- a/src/list.c
+++ b/src/list.c
@@ -2377,9 +2377,8 @@
 	rettv->v_type = VAR_LIST;
 	rettv->vval.v_list = NULL;
     }
-    if (l == NULL
-	    || (filtermap == FILTERMAP_FILTER
-		&& value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
+    if (l == NULL || (filtermap == FILTERMAP_FILTER
+			    && value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
 	return;
 
     prev_lock = l->lv_lock;
@@ -3011,28 +3010,44 @@
 {
     list_T	*l = argvars[0].vval.v_list;
     listitem_T  *li = NULL;
+    int		range_list;
+    int		range_idx = 0;
+    varnumber_T	range_val = 0;
     typval_T	initial;
     typval_T	argv[3];
     int		r;
     int		called_emsg_start = called_emsg;
     int		prev_locked;
 
-    if (l != NULL)
-	CHECK_LIST_MATERIALIZE(l);
+    // Using reduce on a range() uses "range_idx" and "range_val".
+    range_list = l != NULL && l->lv_first == &range_list_item;
+    if (range_list)
+	range_val = l->lv_u.nonmat.lv_start;
+
     if (argvars[2].v_type == VAR_UNKNOWN)
     {
-	if (l == NULL || l->lv_first == NULL)
+	if (l == NULL || l->lv_len == 0)
 	{
 	    semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "List");
 	    return;
 	}
-	initial = l->lv_first->li_tv;
-	li = l->lv_first->li_next;
+	if (range_list)
+	{
+	    initial.v_type = VAR_NUMBER;
+	    initial.vval.v_number = range_val;
+	    range_val += l->lv_u.nonmat.lv_stride;
+	    range_idx = 1;
+	}
+	else
+	{
+	    initial = l->lv_first->li_tv;
+	    li = l->lv_first->li_next;
+	}
     }
     else
     {
 	initial = argvars[2];
-	if (l != NULL)
+	if (l != NULL && !range_list)
 	    li = l->lv_first;
     }
     copy_tv(&initial, rettv);
@@ -3041,20 +3056,36 @@
 	return;
 
     prev_locked = l->lv_lock;
-
     l->lv_lock = VAR_FIXED;  // disallow the list changing here
-    for ( ; li != NULL; li = li->li_next)
+
+    while (range_list ? range_idx < l->lv_len : li != NULL)
     {
 	argv[0] = *rettv;
-	argv[1] = li->li_tv;
 	rettv->v_type = VAR_UNKNOWN;
 
+	if (range_list)
+	{
+	    argv[1].v_type = VAR_NUMBER;
+	    argv[1].vval.v_number = range_val;
+	}
+	else
+	    argv[1] = li->li_tv;
+
 	r = eval_expr_typval(expr, argv, 2, rettv);
 
 	clear_tv(&argv[0]);
 	if (r == FAIL || called_emsg != called_emsg_start)
 	    break;
+
+	if (range_list)
+	{
+	    range_val += l->lv_u.nonmat.lv_stride;
+	    ++range_idx;
+	}
+	else
+	    li = li->li_next;
     }
+
     l->lv_lock = prev_locked;
 }