/// <summary>
    /// The instantiated formal type is non-delayed unless the parameter is marked delayed and "delayedInstance" is true.
    /// [Existential Delay Change] When there is only one delayed argument, we allow it to be existential delayed
    /// This is done by keeping track of the number of possible delay matches. 
    /// if actual/formal is universal/universal, then this number (possibleDelayMatch) is not changed, we allow it only when
    ///      the number is not zero (the only way it can be zero at this point (delayinstance is true) is because
    ///      an existential/universal delay match happened.
    /// if actual/formal is existential/universal, then match happens only when the number is 1
    ///      number is changed to zero to disallow future existential/universal match
    /// Delay match error will be reported as delay not compatible with the witness. If the witness does not have an appropriate delay
    /// we do not report an error, which will be safe (see comments below).
    /// </summary>
    private void CheckParameterDelay(InitializedVariables iv, Variable actual, Method callee, Parameter p, 
      bool delayedInstance, Node context,
      int witness, int num) {
      if (actual == null) return;
      if (p == null) return;

      // Special check that we don't pass pointers to delayed objects by reference
      Reference r = p.Type as Reference;
      if (r != null && !r.ElementType.IsValueType) {
        if (iv.IsDelayed(actual) || iv.IsDelayedRefContents(actual)) {
          Node offendingNode = (actual.SourceContext.Document != null) ? actual : context;
          mpc.typeSystem.HandleError(offendingNode, Error.DelayedReferenceByReference);
          return;
        }
      }

      // delayed instance requires that for every delayed formal, the corresponding actual must
      // be committed to an appropriate delay type. 
      if (delayedInstance && this.IsUniversallyDelayed(p)) {
        // CanAssumeDelay Decides whether the actual 1) is of the same delay (universal delay) as the formal
        //                                        or 2) is bottom, thus can be assumed to be universal delay afterwards
        // CanAssumeDelay cannot decide, and thus returns false when actual is existentially delayed
        bool actualIsSameDelayAsFormal = iv.CanAssumeDelayed(actual);

        if (actualIsSameDelayAsFormal) { 
          return;
        }

        if (iv.IsExistentialDelayed(actual))
        {
          // errors, if any, has been handled already in MethodCallDelayInstance
          // return here to avoid falling into the error reporting below. 
          return;
        }

        // if p is a universally delayed parameter, while actual cannot take a delayed type, 
        // (e.g., it is top), report error
        Node offendingNode = (actual.SourceContext.Document != null) ? actual : context;
        if (p is This) {
          mpc.typeSystem.HandleError(offendingNode, Error.ReceiverMustBeDelayed);
        }
        else {
          if (num != witness) // note this is not an extra check, the fact that witness is the position of the
            // first known delayed actual doesnt mean it will match correctly (i.e., possibly delay match might
            // not be right. 
            // We are not losing warnings either because if num == witness, only if possiblyDelayMatch == 1
            // we will have no warning, in which case, we are guaranteed to have a delay match and won't reach here
          {
            mpc.typeSystem.HandleError(offendingNode, Error.ActualMustBeDelayed, num.ToString(), (witness==0)?"this(receiver)": "No."+witness.ToString());
          }
        }
        return;
      }
      else {
        /* 
        if (callee is InstanceInitializer && p is This && iv.IsBottom(actual)) {
          if (ThisIsSoleDelayedParameter(callee)) {
            // leave undetermined status of this.
            return;
          }
        }
        */
        // actual is known to be not delayed. CanAssumeNotDelay has this side effect to change
        // actual's delay type from bottom to nondelay if its type is not already nondelay
        if (iv.CanAssumeNotDelayed(actual)) {
          return;
        }
        // if its type is delayed, or top, report error... it is assumed that actual's type cannot 
        // be top, which, when violated (likely to happen), leads to inaccurate error message.
        // TODO: distinguish between actual's type being delayed or being top.
        Node offendingNode = (actual.SourceContext.Document != null) ? actual : context;
        if (p is This) {
        //  System.Console.WriteLine("p is Universally delayed: {0}", this.IsUniversallyDelayed(p));
        //  System.Console.WriteLine("delayInstance is {0}", delayedInstance);
        //  System.Console.WriteLine("{0} violates delay of {1}", actual, p);
        //  System.Console.WriteLine("Value of possible delay match:{0} ", possibleDelayMatch);
          mpc.typeSystem.HandleError(offendingNode, Error.ReceiverCannotBeDelayed);
        }
        else {
          //System.Console.WriteLine("{0} is offending {1} for function {2}", actual, p, callee.Name);
          //System.Console.WriteLine("delayinstance:{0}; possibleDelayMatch:{1}", delayedInstance, possibleDelayMatch);
          //iv.PrintStatus(actual);
          //System.Console.WriteLine("p is universally delayed: {0}", this.IsUniversallyDelayed(p));
          mpc.typeSystem.HandleError(offendingNode, Error.ActualCannotBeDelayed);
        }
        return;
      }
    }
 /// <summary>
 /// Returns an arraylist of delayed parameters of the current method, based on their status in the analysis
 /// (not based on whether they are declared as delayed).  
 /// </summary>
 /// <param name="ivs"> the state of variable-initialization (def-assign) analysis </param>
 /// <returns>Returns an arraylist of program variables that are delayed, according to a particular var-initialization
 /// analysis state</returns>
 private ArrayList delayedParameters (InitializedVariables ivs) {
   ArrayList result = new ArrayList();
   if (ivs == null) return result;
   if (this.mpc.currentMethod == null) return result;
   if (this.mpc.currentMethod.Parameters == null) return result;
   foreach (Parameter p in this.mpc.currentMethod.Parameters) {
     if (ivs.IsDelayed(p)) {
       result.Add(p);
     }
   }
   if (!this.mpc.currentMethod.IsStatic) {
     if (ivs.IsDelayed(this.mpc.currentMethod.ThisParameter)) {
       result.Add(this.mpc.currentMethod.ThisParameter);
     }
   }
   return result;
 }
    /// <summary>
    /// Figure out how to instantiate the quantified delay of the method parameters (if any).
    /// We assume that each method has the form \forall T. where T is a delay. Parameters with the "Delayed" attribute
    /// are assumed to have type Delay(T). 
    /// Given the concrete arguments, this method determines if any parameter whose formal is delayed is actually delayed.
    /// [existential delay change]
    /// In addition, put the checking of existential delayed actuals here
    /// For error diagnostics purpose, we also note the position of the first delay-matched argument
    /// </summary>
    /// <param name="receiver"></param>
    /// <param name="callee"></param>
    /// <param name="arguments"></param>
    /// <returns></returns>
    public bool MethodCallDelayInstance(InitializedVariables iv, Variable receiver, Method callee, 
      ExpressionList arguments, Node context, out int witness)
    {
      Node off = receiver;
      witness = -1;

      if (receiver != null && this.IsUniversallyDelayed(callee.ThisParameter) && iv.IsDelayed(receiver)) {
        if (witness == -1) witness = 0;
      }
      if (callee.Parameters == null || arguments == null)
      {
        // dont have more parameters, not possible to have MoreThan2ExistentialDelay
        return (witness != -1);
      }
      for (int i = 0; i<callee.Parameters.Count; i++) {
        Parameter p = callee.Parameters[i];
        Variable arg = (Variable)arguments[i];
        if (this.IsUniversallyDelayed(p) && iv.IsDelayed(arg)) {
          if (iv.IsExistentialDelayed(arg))
          {
            if (witness != -1)
            {
              // report error
              Node offendingNode = (arg.SourceContext.Document != null) ? arg : context;
              mpc.typeSystem.HandleError(offendingNode, Error.ActualMustBeDelayed, (i+1).ToString(), 
                (witness == 0) ? "this(receiver)" : "No." + witness.ToString());
            };
            off = arg;
          }
          if (witness == -1) witness = i + 1;
        }
      }

      // System.Console.WriteLine("result is:{0}, numDelayMatch is {1}", result, numDelayMatch);
      return (witness != -1);
    }