patch 9.0.0379: cleaning up after writefile() is a hassle

Problem:    Cleaning up after writefile() is a hassle.
Solution:   Add the 'D' flag to defer deleting the written file.  Very useful
            in tests.
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 3c4f1a2..3194f87 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -845,41 +845,71 @@
     return FALSE;
 }
 
+// Ugly static to avoid passing the execution context around through many
+// layers.
+static ectx_T *current_ectx = NULL;
+
 /*
- * Handle ISN_DEFER.  Stack has a function reference and "argcount" arguments.
- * The local variable that lists deferred functions is "var_idx".
- * Returns OK or FAIL.
+ * Return TRUE if currently executing a :def function.
+ * Can be used by builtin functions only.
  */
-    static int
-add_defer_func(int var_idx, int argcount, ectx_T *ectx)
+    int
+in_def_function(void)
+{
+    return current_ectx != NULL;
+}
+
+/*
+ * Add an entry for a deferred function call to the currently executing
+ * function.
+ * Return the list or NULL when failed.
+ */
+    static list_T *
+add_defer_item(int var_idx, int argcount, ectx_T *ectx)
 {
     typval_T	*defer_tv = STACK_TV_VAR(var_idx);
     list_T	*defer_l;
-    typval_T	*func_tv;
     list_T	*l;
-    int		i;
     typval_T	listval;
 
     if (defer_tv->v_type != VAR_LIST)
     {
 	// first time, allocate the list
 	if (rettv_list_alloc(defer_tv) == FAIL)
-	    return FAIL;
+	    return NULL;
     }
     defer_l = defer_tv->vval.v_list;
 
     l = list_alloc_with_items(argcount + 1);
     if (l == NULL)
-	return FAIL;
+	return NULL;
     listval.v_type = VAR_LIST;
     listval.vval.v_list = l;
     listval.v_lock = 0;
     if (list_insert_tv(defer_l, &listval, defer_l->lv_first) == FAIL)
     {
 	vim_free(l);
-	return FAIL;
+	return NULL;
     }
 
+    return l;
+}
+
+/*
+ * Handle ISN_DEFER.  Stack has a function reference and "argcount" arguments.
+ * The local variable that lists deferred functions is "var_idx".
+ * Returns OK or FAIL.
+ */
+    static int
+defer_command(int var_idx, int argcount, ectx_T *ectx)
+{
+    list_T	*l = add_defer_item(var_idx, argcount, ectx);
+    int		i;
+    typval_T	*func_tv;
+
+    if (l == NULL)
+	return FAIL;
+
     func_tv = STACK_TV_BOT(-argcount - 1);
     // TODO: check type is a funcref
     list_set_item(l, 0, func_tv);
@@ -891,6 +921,43 @@
 }
 
 /*
+ * Add a deferred function "name" with one argument "arg_tv".
+ * Consumes "name", also on failure.
+ * Only to be called when in_def_function() returns TRUE.
+ */
+    int
+add_defer_function(char_u *name, int argcount, typval_T *argvars)
+{
+    dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
+						  + current_ectx->ec_dfunc_idx;
+    list_T	*l;
+    typval_T	func_tv;
+    int		i;
+
+    if (dfunc->df_defer_var_idx == 0)
+    {
+	iemsg("df_defer_var_idx is zero");
+	vim_free(func_tv.vval.v_string);
+	return FAIL;
+    }
+    func_tv.v_type = VAR_FUNC;
+    func_tv.v_lock = 0;
+    func_tv.vval.v_string = name;
+
+    l = add_defer_item(dfunc->df_defer_var_idx - 1, 1, current_ectx);
+    if (l == NULL)
+    {
+	vim_free(func_tv.vval.v_string);
+	return FAIL;
+    }
+
+    list_set_item(l, 0, &func_tv);
+    for (i = 0; i < argcount; ++i)
+	list_set_item(l, i + 1, argvars + i);
+    return OK;
+}
+
+/*
  * Invoked when returning from a function: Invoke any deferred calls.
  */
     static void
@@ -1068,10 +1135,6 @@
     return OK;
 }
 
-// Ugly global to avoid passing the execution context around through many
-// layers.
-static ectx_T *current_ectx = NULL;
-
 /*
  * Call a builtin function by index.
  */
@@ -3748,7 +3811,7 @@
 
 	    // :defer func(arg)
 	    case ISN_DEFER:
-		if (add_defer_func(iptr->isn_arg.defer.defer_var_idx,
+		if (defer_command(iptr->isn_arg.defer.defer_var_idx,
 			     iptr->isn_arg.defer.defer_argcount, ectx) == FAIL)
 		    goto on_error;
 		break;
@@ -5121,7 +5184,7 @@
 }
 
 /*
- * Execute the instructions from a VAR_INSTR typeval and put the result in
+ * Execute the instructions from a VAR_INSTR typval and put the result in
  * "rettv".
  * Return OK or FAIL.
  */