/// <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); }