patch 8.2.4607: sourcing buffer lines may lead to errors for conflicts

Problem:    Sourcing buffer lines may lead to errors for conflicts.
Solution:   Add the ++clear argument. (Yegappan Lakshmanan, closes #9991)
diff --git a/src/scriptfile.c b/src/scriptfile.c
index 3faed4a..ae46e7a 100644
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -23,7 +23,7 @@
 static int		last_current_SID_seq = 0;
 #endif
 
-static int do_source_ext(char_u *fname, int check_other, int is_vimrc, int *ret_sid, exarg_T *eap);
+static int do_source_ext(char_u *fname, int check_other, int is_vimrc, int *ret_sid, exarg_T *eap, int clearvars);
 
 /*
  * Initialize the execution stack.
@@ -1084,6 +1084,20 @@
     static void
 cmd_source(char_u *fname, exarg_T *eap)
 {
+    int clearvars = FALSE;
+
+    if (*fname != NUL && STRNCMP(fname, "++clear", 7) == 0)
+    {
+	// ++clear argument is supplied
+	clearvars = TRUE;
+	fname = fname + 7;
+	if (*fname != NUL)
+	{
+	    semsg(_(e_invalid_argument_str), eap->arg);
+	    return;
+	}
+    }
+
     if (*fname != NUL && eap != NULL && eap->addr_count > 0)
     {
 	// if a filename is specified to :source, then a range is not allowed
@@ -1098,7 +1112,7 @@
 	    emsg(_(e_argument_required));
 	else
 	    // source ex commands from the current buffer
-	    do_source_ext(NULL, FALSE, FALSE, NULL, eap);
+	    do_source_ext(NULL, FALSE, FALSE, NULL, eap, clearvars);
     }
     else if (eap != NULL && eap->forceit)
 	// ":source!": read Normal mode commands
@@ -1292,6 +1306,10 @@
  * The 'eap' argument is used when sourcing lines from a buffer instead of a
  * file.
  *
+ * If 'clearvars' is TRUE, then for scripts which are loaded more than
+ * once, clear all the functions and variables previously defined in that
+ * script.
+ *
  * This function may be called recursively!
  *
  * Return FAIL if file could not be opened, OK otherwise.
@@ -1303,7 +1321,8 @@
     int		check_other,	    // check for .vimrc and _vimrc
     int		is_vimrc,	    // DOSO_ value
     int		*ret_sid UNUSED,
-    exarg_T	*eap)
+    exarg_T	*eap,
+    int		clearvars UNUSED)
 {
     source_cookie_T	    cookie;
     char_u		    *p;
@@ -1527,20 +1546,25 @@
 	{
 	    si->sn_state = SN_STATE_RELOAD;
 
-	    // Script-local variables remain but "const" can be set again.
-	    // In Vim9 script variables will be cleared when "vim9script" is
-	    // encountered without the "noclear" argument.
-	    ht = &SCRIPT_VARS(sid);
-	    todo = (int)ht->ht_used;
-	    for (hi = ht->ht_array; todo > 0; ++hi)
-		if (!HASHITEM_EMPTY(hi))
-		{
-		    --todo;
-		    di = HI2DI(hi);
-		    di->di_flags |= DI_FLAGS_RELOAD;
-		}
-	    // imports can be redefined once
-	    mark_imports_for_reload(sid);
+	    if (!clearvars)
+	    {
+		// Script-local variables remain but "const" can be set again.
+		// In Vim9 script variables will be cleared when "vim9script"
+		// is encountered without the "noclear" argument.
+		ht = &SCRIPT_VARS(sid);
+		todo = (int)ht->ht_used;
+		for (hi = ht->ht_array; todo > 0; ++hi)
+		    if (!HASHITEM_EMPTY(hi))
+		    {
+			--todo;
+			di = HI2DI(hi);
+			di->di_flags |= DI_FLAGS_RELOAD;
+		    }
+		// imports can be redefined once
+		mark_imports_for_reload(sid);
+	    }
+	    else
+		clear_vim9_scriptlocal_vars(sid);
 
 	    // reset version, "vim9script" may have been added or removed.
 	    si->sn_version = 1;
@@ -1731,7 +1755,7 @@
     int		is_vimrc,	    // DOSO_ value
     int		*ret_sid UNUSED)
 {
-    return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL);
+    return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, FALSE);
 }