*** src/eval.c	2009-05-03 11:09:54.000000000 -0700
--- src/eval_fixed2.c	2009-05-03 11:16:07.000000000 -0700
***************
*** 129,135 ****
--- 129,140 ----
  /*
   * When recursively copying lists and dicts we need to remember which ones we
   * have done to avoid endless recursiveness.  This unique ID is used for that.
+  * The lowest bit stores if a list or dict is used in the previous_funccal
+  * list.
   */
+ #define COPY_ID_PREV_BIT 1
+ #define COPY_ID_PREV_MASK ~COPY_ID_PREV_BIT
+ #define COPY_ID_STEP 2
  static int current_copyID = 0;
  
  /*
***************
*** 442,447 ****
--- 447,455 ----
  static void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID));
  static void set_ref_in_list __ARGS((list_T *l, int copyID));
  static void set_ref_in_item __ARGS((typval_T *tv, int copyID));
+ static void set_ref_bit_in_ht __ARGS((hashtab_T *ht, int copyID));
+ static void set_ref_bit_in_list __ARGS((list_T *l, int copyID));
+ static void set_ref_bit_in_item __ARGS((typval_T *tv, int copyID));
  static void dict_unref __ARGS((dict_T *d));
  static void dict_free __ARGS((dict_T *d, int recurse));
  static dictitem_T *dictitem_alloc __ARGS((char_u *key));
***************
*** 6497,6503 ****
  {
      dict_T	*dd;
      list_T	*ll;
!     int		copyID = ++current_copyID;
      buf_T	*buf;
      win_T	*wp;
      int		i;
--- 6505,6511 ----
  {
      dict_T	*dd;
      list_T	*ll;
!     int		copyID = (current_copyID += COPY_ID_STEP);
      buf_T	*buf;
      win_T	*wp;
      int		i;
***************
*** 6547,6557 ****
      /* v: vars */
      set_ref_in_ht(&vimvarht, copyID);
  
      /*
       * 2. Go through the list of dicts and free items without the copyID.
       */
      for (dd = first_dict; dd != NULL; )
! 	if (dd->dv_copyID != copyID)
  	{
  	    /* Free the Dictionary and ordinary items it contains, but don't
  	     * recurse into Lists and Dictionaries, they will be in the list
--- 6555,6572 ----
      /* v: vars */
      set_ref_in_ht(&vimvarht, copyID);
  
+     /* don't free variables in the previous_funccal list before step 4 */
+     for (fc = previous_funccal; fc != NULL; fc = fc->caller)
+     {
+ 	set_ref_bit_in_ht(&fc->l_vars.dv_hashtab, COPY_ID_PREV_BIT);
+ 	set_ref_bit_in_ht(&fc->l_avars.dv_hashtab, COPY_ID_PREV_BIT);
+     }
+ 
      /*
       * 2. Go through the list of dicts and free items without the copyID.
       */
      for (dd = first_dict; dd != NULL; )
! 	if (dd->dv_copyID != copyID && (dd->dv_copyID & COPY_ID_PREV_BIT) == 0)
  	{
  	    /* Free the Dictionary and ordinary items it contains, but don't
  	     * recurse into Lists and Dictionaries, they will be in the list
***************
*** 6571,6577 ****
       *    are not referenced anywhere.
       */
      for (ll = first_list; ll != NULL; )
! 	if (ll->lv_copyID != copyID && ll->lv_watch == NULL)
  	{
  	    /* Free the List and ordinary items it contains, but don't recurse
  	     * into Lists and Dictionaries, they will be in the list of dicts
--- 6586,6593 ----
       *    are not referenced anywhere.
       */
      for (ll = first_list; ll != NULL; )
! 	if (ll->lv_copyID != copyID && ll->lv_watch == NULL
! 		&& (ll->lv_copyID & COPY_ID_PREV_BIT) == 0)
  	{
  	    /* Free the List and ordinary items it contains, but don't recurse
  	     * into Lists and Dictionaries, they will be in the list of dicts
***************
*** 6585,6591 ****
  	else
  	    ll = ll->lv_used_next;
  
!     /* check if any funccal can be freed now */
      for (pfc = &previous_funccal; *pfc != NULL; )
      {
  	if (can_free_funccal(*pfc, copyID))
--- 6601,6607 ----
  	else
  	    ll = ll->lv_used_next;
  
!     /* 4. Check if any funccal can be freed now. */
      for (pfc = &previous_funccal; *pfc != NULL; )
      {
  	if (can_free_funccal(*pfc, copyID))
***************
*** 6673,6678 ****
--- 6689,6765 ----
  }
  
  /*
+  * Sets "bit" in copyId in all lists and dicts referenced through hashtab "ht".
+  */
+     static void
+ set_ref_bit_in_ht(ht, bit)
+     hashtab_T	*ht;
+     int		bit;
+ {
+     int		todo;
+     hashitem_T	*hi;
+ 
+     todo = (int)ht->ht_used;
+     for (hi = ht->ht_array; todo > 0; ++hi)
+ 	if (!HASHITEM_EMPTY(hi))
+ 	{
+ 	    --todo;
+ 	    set_ref_bit_in_item(&HI2DI(hi)->di_tv, bit);
+ 	}
+ }
+ 
+ /*
+  * Sets "bit" in copyId in all lists and dicts referenced through list "l".
+  */
+     static void
+ set_ref_bit_in_list(l, bit)
+     list_T	*l;
+     int		bit;
+ {
+     listitem_T *li;
+ 
+     for (li = l->lv_first; li != NULL; li = li->li_next)
+ 	set_ref_bit_in_item(&li->li_tv, bit);
+ }
+ 
+ /*
+  * Sets "bit" in copyId in all lists and dicts referenced through typval "tv".
+  */
+     static void
+ set_ref_bit_in_item(tv, bit)
+     typval_T	*tv;
+     int		bit;
+ {
+     dict_T	*dd;
+     list_T	*ll;
+ 
+     switch (tv->v_type)
+     {
+ 	case VAR_DICT:
+ 	    dd = tv->vval.v_dict;
+ 	    if (dd != NULL && (dd->dv_copyID & bit) != bit)
+ 	    {
+ 		/* Didn't see this dict yet. */
+ 		dd->dv_copyID |= bit;
+ 		set_ref_bit_in_ht(&dd->dv_hashtab, bit);
+ 	    }
+ 	    break;
+ 
+ 	case VAR_LIST:
+ 	    ll = tv->vval.v_list;
+ 	    if (ll != NULL && (ll->lv_copyID & bit) != bit)
+ 	    {
+ 		/* Didn't see this list yet. */
+ 		ll->lv_copyID |= bit;
+ 		set_ref_bit_in_list(ll, bit);
+ 	    }
+ 	    break;
+     }
+     return;
+ }
+ 
+ 
+ /*
   * Allocate an empty header for a dictionary.
   */
      dict_T *
***************
*** 18946,18951 ****
--- 19033,19039 ----
      dictitem_T	*dict_var;
  {
      hash_init(&dict->dv_hashtab);
+     dict->dv_copyID = 0;
      dict->dv_refcount = DO_NOT_FREE_CNT;
      dict_var->di_tv.vval.v_dict = dict;
      dict_var->di_tv.v_type = VAR_DICT;
***************
*** 21446,21454 ****
      funccall_T	*fc;
      int		copyID;
  {
!     return (fc->l_varlist.lv_copyID != copyID
! 	    && fc->l_vars.dv_copyID != copyID
! 	    && fc->l_avars.dv_copyID != copyID);
  }
  
  /*
--- 21534,21542 ----
      funccall_T	*fc;
      int		copyID;
  {
!     return ((fc->l_varlist.lv_copyID & COPY_ID_PREV_MASK) != copyID
! 	    && (fc->l_vars.dv_copyID & COPY_ID_PREV_MASK) != copyID
! 	    && (fc->l_avars.dv_copyID & COPY_ID_PREV_MASK) != copyID);
  }
  
  /*
