patch 8.2.0149: maintaining a Vim9 branch separately is more work

Problem:    Maintaining a Vim9 branch separately is more work.
Solution:   Merge the Vim9 script changes.
diff --git a/src/list.c b/src/list.c
index 68be034..4071a7d 100644
--- a/src/list.c
+++ b/src/list.c
@@ -65,6 +65,17 @@
 	    lw->lw_item = item->li_next;
 }
 
+    static void
+list_init(list_T *l)
+{
+    // Prepend the list to the list of lists for garbage collection.
+    if (first_list != NULL)
+	first_list->lv_used_prev = l;
+    l->lv_used_prev = NULL;
+    l->lv_used_next = first_list;
+    first_list = l;
+}
+
 /*
  * Allocate an empty header for a list.
  * Caller should take care of the reference count.
@@ -76,14 +87,7 @@
 
     l = ALLOC_CLEAR_ONE(list_T);
     if (l != NULL)
-    {
-	// Prepend the list to the list of lists for garbage collection.
-	if (first_list != NULL)
-	    first_list->lv_used_prev = l;
-	l->lv_used_prev = NULL;
-	l->lv_used_next = first_list;
-	first_list = l;
-    }
+	list_init(l);
     return l;
 }
 
@@ -101,6 +105,59 @@
 }
 
 /*
+ * Allocate space for a list, plus "count" items.
+ * Next list_set_item() must be called for each item.
+ */
+    list_T *
+list_alloc_with_items(int count)
+{
+    list_T	*l;
+
+    l = (list_T *)alloc_clear(sizeof(list_T) + count * sizeof(listitem_T));
+    if (l != NULL)
+    {
+	list_init(l);
+
+	if (count > 0)
+	{
+	    listitem_T	*li = (listitem_T *)(l + 1);
+	    int		i;
+
+	    l->lv_len = count;
+	    l->lv_with_items = count;
+	    l->lv_first = li;
+	    l->lv_last = li + count - 1;
+	    for (i = 0; i < count; ++i)
+	    {
+		if (i == 0)
+		    li->li_prev = NULL;
+		else
+		    li->li_prev = li - 1;
+		if (i == count - 1)
+		    li->li_next = NULL;
+		else
+		    li->li_next = li + 1;
+		++li;
+	    }
+	}
+    }
+    return l;
+}
+
+/*
+ * Set item "idx" for a list previously allocated with list_alloc_with_items().
+ * The contents of "tv" is moved into the list item.
+ * Each item must be set exactly once.
+ */
+    void
+list_set_item(list_T *l, int idx, typval_T *tv)
+{
+    listitem_T	*li = (listitem_T *)(l + 1) + idx;
+
+    li->li_tv = *tv;
+}
+
+/*
  * Allocate an empty list for a return value, with reference count set.
  * Returns OK or FAIL.
  */
@@ -163,13 +220,14 @@
 {
     listitem_T *item;
 
-    for (item = l->lv_first; item != NULL; item = l->lv_first)
-    {
-	// Remove the item before deleting it.
-	l->lv_first = item->li_next;
-	clear_tv(&item->li_tv);
-	vim_free(item);
-    }
+    if (l->lv_first != &range_list_item)
+	for (item = l->lv_first; item != NULL; item = l->lv_first)
+	{
+	    // Remove the item before deleting it.
+	    l->lv_first = item->li_next;
+	    clear_tv(&item->li_tv);
+	    list_free_item(l, item);
+	}
 }
 
 /*
@@ -250,13 +308,26 @@
 }
 
 /*
- * Free a list item.  Also clears the value.  Does not notify watchers.
+ * Free a list item, unless it was allocated together with the list itself.
+ * Does not clear the value.  Does not notify watchers.
  */
     void
-listitem_free(listitem_T *item)
+list_free_item(list_T *l, listitem_T *item)
+{
+    if (l->lv_with_items == 0 || item < (listitem_T *)l
+			   || item >= (listitem_T *)(l + 1) + l->lv_with_items)
+	vim_free(item);
+}
+
+/*
+ * Free a list item, unless it was allocated together with the list itself.
+ * Also clears the value.  Does not notify watchers.
+ */
+    void
+listitem_free(list_T *l, listitem_T *item)
 {
     clear_tv(&item->li_tv);
-    vim_free(item);
+    list_free_item(l, item);
 }
 
 /*
@@ -266,7 +337,7 @@
 listitem_remove(list_T *l, listitem_T *item)
 {
     vimlist_remove(l, item, item);
-    listitem_free(item);
+    listitem_free(l, item);
 }
 
 /*
@@ -299,6 +370,9 @@
     if (list_len(l1) != list_len(l2))
 	return FALSE;
 
+    range_list_materialize(l1);
+    range_list_materialize(l2);
+
     for (item1 = l1->lv_first, item2 = l2->lv_first;
 	    item1 != NULL && item2 != NULL;
 			       item1 = item1->li_next, item2 = item2->li_next)
@@ -329,6 +403,8 @@
     if (n < 0 || n >= l->lv_len)
 	return NULL;
 
+    range_list_materialize(l);
+
     // When there is a cached index may start search from there.
     if (l->lv_idx_item != NULL)
     {
@@ -398,6 +474,26 @@
 {
     listitem_T	*li;
 
+    if (l != NULL && l->lv_first == &range_list_item)
+    {
+	long	    n = idx;
+
+	// not materialized range() list: compute the value.
+	// Negative index is relative to the end.
+	if (n < 0)
+	    n = l->lv_len + n;
+
+	// Check for index out of range.
+	if (n < 0 || n >= l->lv_len)
+	{
+	    if (errorp != NULL)
+		*errorp = TRUE;
+	    return -1L;
+	}
+
+	return l->lv_start + n * l->lv_stride;
+    }
+
     li = list_find(l, idx);
     if (li == NULL)
     {
@@ -437,6 +533,7 @@
 
     if (l == NULL)
 	return -1;
+    range_list_materialize(l);
     idx = 0;
     for (li = l->lv_first; li != NULL && li != item; li = li->li_next)
 	++idx;
@@ -451,6 +548,7 @@
     void
 list_append(list_T *l, listitem_T *item)
 {
+    range_list_materialize(l);
     if (l->lv_last == NULL)
     {
 	// empty list
@@ -469,7 +567,7 @@
 }
 
 /*
- * Append typval_T "tv" to the end of list "l".
+ * Append typval_T "tv" to the end of list "l".  "tv" is copied.
  * Return FAIL when out of memory.
  */
     int
@@ -485,6 +583,22 @@
 }
 
 /*
+ * As list_append_tv() but move the value instead of copying it.
+ * Return FAIL when out of memory.
+ */
+    int
+list_append_tv_move(list_T *l, typval_T *tv)
+{
+    listitem_T	*li = listitem_alloc();
+
+    if (li == NULL)
+	return FAIL;
+    li->li_tv = *tv;
+    list_append(l, li);
+    return OK;
+}
+
+/*
  * Add a dictionary to a list.  Used by getqflist().
  * Return FAIL when out of memory.
  */
@@ -584,6 +698,7 @@
     void
 list_insert(list_T *l, listitem_T *ni, listitem_T *item)
 {
+    range_list_materialize(l);
     if (item == NULL)
 	// Append new item at end of list.
 	list_append(l, ni);
@@ -618,6 +733,9 @@
     listitem_T	*item;
     int		todo = l2->lv_len;
 
+    range_list_materialize(l1);
+    range_list_materialize(l2);
+
     // We also quit the loop when we have inserted the original item count of
     // the list, avoid a hang when we extend a list with itself.
     for (item = l2->lv_first; item != NULL && --todo >= 0; item = item->li_next)
@@ -675,6 +793,7 @@
 	    orig->lv_copyID = copyID;
 	    orig->lv_copylist = copy;
 	}
+	range_list_materialize(orig);
 	for (item = orig->lv_first; item != NULL && !got_int;
 							 item = item->li_next)
 	{
@@ -715,6 +834,8 @@
 {
     listitem_T	*ip;
 
+    range_list_materialize(l);
+
     // notify watchers
     for (ip = item; ip != NULL; ip = ip->li_next)
     {
@@ -748,6 +869,7 @@
 	return NULL;
     ga_init2(&ga, (int)sizeof(char), 80);
     ga_append(&ga, '[');
+    range_list_materialize(tv->vval.v_list);
     if (list_join(&ga, tv->vval.v_list, (char_u *)", ",
 				       FALSE, restore_copyID, copyID) == FAIL)
     {
@@ -785,6 +907,7 @@
     char_u	*s;
 
     // Stringify each item in the list.
+    range_list_materialize(l);
     for (item = l->lv_first; item != NULL && !got_int; item = item->li_next)
     {
 	s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID,
@@ -915,7 +1038,7 @@
  * Return OK or FAIL.
  */
     int
-get_list_tv(char_u **arg, typval_T *rettv, int evaluate)
+get_list_tv(char_u **arg, typval_T *rettv, int evaluate, int do_error)
 {
     list_T	*l = NULL;
     typval_T	tv;
@@ -950,7 +1073,8 @@
 	    break;
 	if (**arg != ',')
 	{
-	    semsg(_("E696: Missing comma in List: %s"), *arg);
+	    if (do_error)
+		semsg(_("E696: Missing comma in List: %s"), *arg);
 	    goto failret;
 	}
 	*arg = skipwhite(*arg + 1);
@@ -958,7 +1082,8 @@
 
     if (**arg != ']')
     {
-	semsg(_("E697: Missing end of List ']': %s"), *arg);
+	if (do_error)
+	    semsg(_("E697: Missing end of List ']': %s"), *arg);
 failret:
 	if (evaluate)
 	    list_free(l);
@@ -983,6 +1108,7 @@
     int		ret = OK;
     char_u	*s;
 
+    range_list_materialize(list);
     for (li = list->lv_first; li != NULL; li = li->li_next)
     {
 	for (s = tv_get_string(&li->li_tv); *s != NUL; ++s)
@@ -1069,6 +1195,7 @@
     if (argvars[1].v_type != VAR_UNKNOWN)
 	utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
 
+    range_list_materialize(l);
     ga_init2(&ga, 1, 80);
     if (has_mbyte || utf8)
     {
@@ -1123,7 +1250,7 @@
 	    // Remove one item, return its value.
 	    vimlist_remove(l, item, item);
 	    *rettv = item->li_tv;
-	    vim_free(item);
+	    list_free_item(l, item);
 	}
 	else
 	{
@@ -1361,6 +1488,7 @@
 									TRUE))
 	    goto theend;
 	rettv_list_set(rettv, l);
+	range_list_materialize(l);
 
 	len = list_len(l);
 	if (len <= 1)
@@ -1519,7 +1647,7 @@
 		    else
 			l->lv_last = ptrs[i].item;
 		    list_fix_watch(l, li);
-		    listitem_free(li);
+		    listitem_free(l, li);
 		    l->lv_len--;
 		}
 	    }
@@ -1729,6 +1857,7 @@
 	    // set_vim_var_nr() doesn't set the type
 	    set_vim_var_type(VV_KEY, VAR_NUMBER);
 
+	    range_list_materialize(l);
 	    for (li = l->lv_first; li != NULL; li = nli)
 	    {
 		if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))