patch 8.2.0703: Vim9: closure cannot store value in outer context

Problem:    Vim9: closure cannot store value in outer context.
Solution:   Make storing value in outer context work.  Make :disassemble
            accept a function reference.
diff --git a/src/eval.c b/src/eval.c
index 72cb089..b7003a8 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -4337,9 +4337,11 @@
 	partial_T	*pt = tv->vval.v_partial;
 	int		i;
 
-	// A partial does not have a copyID, because it cannot contain itself.
-	if (pt != NULL)
+	if (pt != NULL && pt->pt_copyID != copyID)
 	{
+	    // Didn't see this partial yet.
+	    pt->pt_copyID = copyID;
+
 	    abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
 
 	    if (pt->pt_dict != NULL)
diff --git a/src/structs.h b/src/structs.h
index 7fd325a..69233a9 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1812,6 +1812,7 @@
     typval_T	*pt_argv;	// arguments in allocated array
 
     dict_T	*pt_dict;	// dict for "self"
+    int		pt_copyID;	// funcstack may contain pointer to partial
 };
 
 typedef struct AutoPatCmd_S AutoPatCmd;
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index 4e2caf0..1170341 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -291,6 +291,42 @@
         res)
 enddef
 
+def s:CreateRefs()
+  let local = 'a'
+  def Append(arg: string)
+    local ..= arg
+  enddef
+  g:Append = Append
+  def Get(): string
+    return local
+  enddef
+  g:Get = Get
+enddef
+
+def Test_disassemble_closure()
+  CreateRefs()
+  let res = execute('disass g:Append')
+  assert_match('<lambda>\d.*' ..
+        'local ..= arg.*' ..
+        '\d LOADOUTER $0.*' ..
+        '\d LOAD arg\[-1\].*' ..
+        '\d CONCAT.*' ..
+        '\d STOREOUTER $0.*' ..
+        '\d PUSHNR 0.*' ..
+        '\d RETURN.*',
+        res)
+
+  res = execute('disass g:Get')
+  assert_match('<lambda>\d.*' ..
+        'return local.*' ..
+        '\d LOADOUTER $0.*' ..
+        '\d RETURN.*',
+        res)
+
+  unlet g:Append
+  unlet g:Get
+enddef
+
 
 def EchoArg(arg: string): string
   return arg
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index 49dc2f2..83cef67 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -738,6 +738,32 @@
   unlet g:UseVararg
 enddef
 
+def MakeGetAndAppendRefs()
+  let local = 'a'
+
+  def Append(arg: string)
+    local ..= arg
+  enddef
+  g:Append = Append
+
+  def Get(): string
+    return local
+  enddef
+  g:Get = Get
+enddef
+
+def Test_closure_append_get()
+  MakeGetAndAppendRefs()
+  assert_equal('a', g:Get())
+  g:Append('-b')
+  assert_equal('a-b', g:Get())
+  g:Append('-c')
+  assert_equal('a-b-c', g:Get())
+
+  unlet g:Append
+  unlet g:Get
+enddef
+
 def Test_nested_closure()
   let local = 'text'
   def Closure(arg: string): string
diff --git a/src/version.c b/src/version.c
index 523791c..b507c89 100644
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    703,
+/**/
     702,
 /**/
     701,
diff --git a/src/vim9.h b/src/vim9.h
index aac776a..709716e 100644
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -40,8 +40,9 @@
     ISN_STOREW,	    // pop into window-local variable isn_arg.string
     ISN_STORET,	    // pop into tab-local variable isn_arg.string
     ISN_STORES,	    // pop into script variable isn_arg.loadstore
+    ISN_STOREOUTER,  // pop variable into outer scope isn_arg.number
     ISN_STORESCRIPT, // pop into script variable isn_arg.script
-    ISN_STOREOPT,   // pop into option isn_arg.string
+    ISN_STOREOPT,    // pop into option isn_arg.string
     ISN_STOREENV,    // pop into environment variable isn_arg.string
     ISN_STOREREG,    // pop into register isn_arg.number
     // ISN_STOREOTHER, // pop into other script variable isn_arg.other.
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 42fc074..5e29cc0 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -4496,7 +4496,11 @@
 		    generate_LOADV(cctx, name + 2, TRUE);
 		    break;
 		case dest_local:
-		    generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type);
+		    if (lvar->lv_from_outer)
+			generate_LOAD(cctx, ISN_LOADOUTER, lvar->lv_idx,
+								   NULL, type);
+		    else
+			generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type);
 		    break;
 	    }
 	}
@@ -4713,8 +4717,8 @@
 
 		// optimization: turn "var = 123" from ISN_PUSHNR + ISN_STORE
 		// into ISN_STORENR
-		if (instr->ga_len == instr_count + 1
-						&& isn->isn_type == ISN_PUSHNR)
+		if (!lvar->lv_from_outer && instr->ga_len == instr_count + 1
+					 && isn->isn_type == ISN_PUSHNR)
 		{
 		    varnumber_T val = isn->isn_arg.number;
 		    garray_T	*stack = &cctx->ctx_type_stack;
@@ -4725,6 +4729,8 @@
 		    if (stack->ga_len > 0)
 			--stack->ga_len;
 		}
+		else if (lvar->lv_from_outer)
+		    generate_STORE(cctx, ISN_STOREOUTER, lvar->lv_idx, NULL);
 		else
 		    generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
 	    }
@@ -6686,6 +6692,7 @@
 	case ISN_PUSHSPEC:
 	case ISN_RETURN:
 	case ISN_STORE:
+	case ISN_STOREOUTER:
 	case ISN_STOREV:
 	case ISN_STORENR:
 	case ISN_STOREREG:
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 5915ea1..9651f5e 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -1070,6 +1070,14 @@
 		*tv = *STACK_TV_BOT(0);
 		break;
 
+	    // store variable or argument in outer scope
+	    case ISN_STOREOUTER:
+		--ectx.ec_stack.ga_len;
+		tv = STACK_OUT_TV_VAR(iptr->isn_arg.number);
+		clear_tv(tv);
+		*tv = *STACK_TV_BOT(0);
+		break;
+
 	    // store s: variable in old script
 	    case ISN_STORES:
 		{
@@ -2133,7 +2141,7 @@
     int		is_global = FALSE;
 
     fname = trans_function_name(&arg, &is_global, FALSE,
-	     TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
+			    TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL);
     if (fname == NULL)
     {
 	semsg(_(e_invarg2), eap->arg);
@@ -2275,12 +2283,17 @@
 		break;
 
 	    case ISN_STORE:
+	    case ISN_STOREOUTER:
+		{
+		    char *add = iptr->isn_type == ISN_STORE ? "" : "OUTER";
+
 		if (iptr->isn_arg.number < 0)
-		    smsg("%4d STORE arg[%lld]", current,
+		    smsg("%4d STORE%s arg[%lld]", current, add,
 			 (long long)(iptr->isn_arg.number + STACK_FRAME_SIZE));
 		else
-		    smsg("%4d STORE $%lld", current,
+		    smsg("%4d STORE%s $%lld", current, add,
 					    (long long)(iptr->isn_arg.number));
+		}
 		break;
 	    case ISN_STOREV:
 		smsg("%4d STOREV v:%s", current,