private void CheckReturnNotDelay(InitializedVariables iv, Variable var, Node context) { if (var == null) return; if (!iv.CanAssumeNotDelayed(var) && !this.mpc.currentMethod.IsPropertyGetter) { if (!mpc.reportedErrors.Contains(var) && var.Name != null && var.Name.Name != "") { Error errorCode = Error.ReturnOfDelayedValue; Node offendingNode = (var.SourceContext.Document == null) ? context : var; mpc.typeSystem.HandleError(offendingNode, errorCode, var.Name.Name); mpc.reportedErrors.Add(var, null); } } iv.SetValueNonDelayed(var); }
/// <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; } }
private void CheckNonDelay(InitializedVariables iv, Variable var, Node context, Error errorCode) { if (var == null) return; if (!iv.CanAssumeNotDelayed(var)) { if (!mpc.reportedErrors.Contains(var) && var.Name != null && var.Name.Name != "") { // Ugly hack to get delayed analysis past non-conformant use of get_FrameGuard. if (!(mpc.currentMethod.Name != null && mpc.currentMethod.Name.Name.StartsWith("get_SpecSharp::FrameGuard"))) { Node offendingNode = (var.SourceContext.Document == null) ? context : var; mpc.typeSystem.HandleError(offendingNode, errorCode, var.Name.Name); mpc.reportedErrors.Add(var, null); } } } iv.SetValueNonDelayed(var); }