public NNArrayStatus(InitializedVariables ivs, HashSet vars, HashSet fields, HashSet zeroInts, InitializedVarStack stack) {
   this.ivs = ivs;
   this.vars = vars;
   this.fields = fields;
   this.zeroInts = zeroInts;
   this.stack = stack;
 }
 static InitializedVarStack mergeStack(InitializedVarStack stack1, InitializedVarStack stack2, InitializedVariables ivs) {
   return InitializedVarStack.Merge(stack1, stack2, ivs);
 }
 /// <summary>
 /// This constructor is called at the beginning of checking a method.
 /// </summary>
 /// <param name="old"></param>
 public NNArrayStatus(InitializedVariables old) {
   this.ivs = old;
   vars = new HashSet();
   fields = new HashSet();
   fieldsToMB.Clear();
   this.zeroInts = new HashSet();
   stack = new InitializedVarStack();
 }
 public NNArrayStatus(NNArrayStatus nnas) {
   this.ivs = new InitializedVariables(nnas.ivs);
   this.vars = nnas.vars;
   this.fields = nnas.fields;
   this.zeroInts = nnas.zeroInts;
   stack = new InitializedVarStack(nnas.stack);
 }
    /// <summary>
    /// Whether two IVStacks are the same, alias wise.
    /// </summary>
    /// <returns></returns>
    static bool Same(InitializedVarStack stack1, InitializedVarStack stack2, InitializedVariables iv) {
      if (stack1.layers.Count != stack2.layers.Count) {
        return false;
      }
      object[] array1 = stack1.layers.ToArray();
      object[] array2 = stack2.layers.ToArray();
      for (int i = 0; i < array1.Length; i++) {
        if (!ContainSameValue((HashSet)array1[i], (HashSet)array2[i], iv)) {
          return false;
        }
      }

      return true;
    }
    /// <summary>
    /// Merges two initialization stacks. 
    /// </summary>
    /// <param name="stack1">Input stack 1.</param>
    /// <param name="stack2">Input stack 2.</param>
    /// <returns>
    /// A new InitializedVarStack retvalue, such that:
    /// retvalue = {v | v in union(stack1, stack2) and v not in common trunk}
    /// "common trunk" = CDR^n (stack1) where n is the smallest non-negative integer such that
    /// there exists a non-negative m such that CDR ^m (stack2) = CDR ^n (stack1);
    /// </returns>
    public static InitializedVarStack Merge(InitializedVarStack stack1, InitializedVarStack stack2, InitializedVariables iv) {
      InitializedVarStack retvalue;

      // shallow one's depth
      int depth1 = stack1.layers.Count;
      int depth2 = stack2.layers.Count;

      // they may both be zero, which is contained by this case
      if (depth1 == depth2) {
        if (Same(stack1, stack2, iv)) {
          retvalue = new InitializedVarStack(stack1);
          return retvalue;
        }
        // if not the same, go on
      }

      // if one of them is zero, return the other
      if (depth1 == 0 ) {
        retvalue = new InitializedVarStack(stack2); 
        return retvalue;
      }
      if (depth2 == 0) {
        retvalue = new InitializedVarStack(stack1);
        return retvalue;
      }

      retvalue = new InitializedVarStack();

      int depth = depth1 > depth2 ? depth1 : depth2;
      InitializedVarStack shallowone = (depth1 < depth2) ? stack1 : stack2;
      InitializedVarStack deepone = (depth1 < depth2) ? stack2 : stack1;

      // shallow one's top must be the crush of the deep one's top |depth1-depth2| + 1 layers. 
      HashSet set = new HashSet();
      object[] array = deepone.layers.ToArray();
      for (int i = 0; i < Math.Abs(depth1 - depth2) +1 ; i++) {
        set = (HashSet)Set.Union(set, (HashSet)array[i]);
      }

      if (!ContainSameValue((HashSet)shallowone.layers.Peek(), set, iv)) {
        //Leave this print-out here to signal possible unknown problems.  
        if (Analyzer.Debug) {
          Console.WriteLine("New delayed value created not in all paths");
        }
        retvalue = new InitializedVarStack(shallowone);
        return retvalue;
      }

      // make a copy of shallow one and return
      retvalue = new InitializedVarStack(shallowone);
      
      // shallow one's CDR must be the same as the deeper one's 
      object[] array2 = shallowone.layers.ToArray();
      int diff = Math.Abs(depth1 - depth2); 
      for (int j = 1; j < array2.Length; j++) {
        if (!ContainSameValue((HashSet)array2[j], (HashSet)array[j + diff], iv)) {
          // TODO: This is unlikely to happen. Still should consider to report 
          // an error. 
        }
      }
      return retvalue;
    }
    /// <summary>
    /// copy constructor. We need to copy the set.
    /// </summary>
    /// <param name="stack"></param>
    public InitializedVarStack(InitializedVarStack stack) {
      layers = new Stack();

      object[] arr = stack.layers.ToArray();
      for (int i = arr.Length - 1; i >= 0; i--) {
        HashSet set = arr[i] as HashSet;
        if (set == null) {
          // this is an internal error
          continue;
        }
        layers.Push(set.Clone());
      }
    }