public void CollectExistentialVars(Statement position, InitializedVariables iv) { // add to the (static) table one line (stmt, existential delayed variables that reach "stmt") nodeExistentialTable.Add(position, iv.MayHaveExistentialDelayedVars); }
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; }
/// <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; }
private bool CallOnThis(InitializedVariables iv, Variable receiver) { if (receiver == null) return false; if (this.mpc.currentMethod.ThisParameter != null && iv.IsEqual(receiver, this.mpc.currentMethod.ThisParameter)) { return true; } return false; }
private void CheckTargetDelayLongerThanSource(InitializedVariables iv, Variable pointer, Variable source, TypeNode type, Node context) { if (type.IsValueType) return; if (iv.TargetDelayLongerThanSource(pointer, source)) return; Node offendingNode = (source.SourceContext.Document == null) ? context : source; if ((pointer == null || !mpc.reportedErrors.Contains(pointer)) && !mpc.reportedErrors.Contains(source)) { if (source.Name != null) { mpc.typeSystem.HandleError(offendingNode, Error.StoreIntoLessDelayedLocation, source.Name.Name); } } }
/// <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> /// 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; }
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> /// Standard check function, except that it returns a PreDAStatus data structure /// that contains the three tables mentioned above. /// </summary> /// <param name="t"></param> /// <param name="method"></param> /// <param name="analyzer"></param> /// <returns>A PreDAStatus data structure, or a null if error occurs. </returns> public static PreDAStatus Check(TypeSystem t, Method method, Analyzer analyzer) { Debug.Assert(method != null && analyzer != null); MethodReachingDefNNArrayChecker checker = new MethodReachingDefNNArrayChecker(t, analyzer, method); ControlFlowGraph cfg = analyzer.GetCFG(method); if (cfg == null) return null; InitializedVariables iv = new InitializedVariables(analyzer); NNArrayStatus status = new NNArrayStatus(iv); NNArrayStatus.Checker = checker; checker.Run(cfg, status); // Check whether there are arrays that have been created but not committed NNArrayStatus exitStatus2 = checker.exitState as NNArrayStatus; if (exitStatus2 != null) { if (Analyzer.Debug) { Console.WriteLine("exit state of {0} is", method.FullName); exitStatus2.Dump(); } ArrayList notCommitted = exitStatus2.CreatedButNotInitedArrays(); if (notCommitted != null && notCommitted.Count != 0) { foreach (object o in notCommitted) { string offendingString = "A non null element array"; Node offendingNode = method; if (o is Variable) { offendingString = "Variable \'" + o + "\'"; offendingNode = o as Variable; } if (o is Pair<Variable, Field>) { Pair<Variable, Field> pair = o as Pair<Variable, Field>; Variable var = pair.Fst; Field fld = pair.Snd; offendingString = "Field \'" + var + "." + fld + "\'"; if (NNArrayStatus.FieldsToMB.ContainsKey(pair)) { offendingNode = NNArrayStatus.FieldsToMB[pair] as MemberBinding; if (offendingNode == null) { offendingNode = fld; } else { MemberBinding mb = offendingNode as MemberBinding; if (mb.TargetObject == null || mb.SourceContext.SourceText == null) { offendingNode = fld; } } } } checker.HandleError(offendingNode, Error.ShouldCommit, offendingString); } } ArrayList notCommittedOnAllPaths = exitStatus2.CreatedButNotFullyCommittedArrays(); if (notCommittedOnAllPaths != null && notCommittedOnAllPaths.Count != 0) { foreach (object o in notCommittedOnAllPaths) { string offendingString = "A non-null element array"; Node offendingNode = method; if (o is Variable) { offendingString = "variable \'" + o + "\'"; offendingNode = o as Variable; } else if (o is Pair<Variable, Field>) { Pair<Variable, Field> pair = o as Pair<Variable, Field>; Variable var = pair.Fst; Field fld = pair.Snd; if (NNArrayStatus.FieldsToMB.ContainsKey(pair)) { offendingNode = NNArrayStatus.FieldsToMB[pair] as MemberBinding; if (offendingNode == null) { offendingNode = fld; } else { MemberBinding mb = offendingNode as MemberBinding; if (mb.TargetObject == null || mb.SourceContext.SourceText==null) { offendingNode = fld; } } } offendingString = "field \'" + var + "." + fld + "\'"; } checker.HandleError(offendingNode, Error.ShouldCommitOnAllPaths, offendingString); } } if (checker.errors != null && checker.errors.Count != 0) { checker.HandleError(); checker.errors.Clear(); return null; } } return new PreDAStatus(checker.NotCommitted, checker.Committed, checker.OKTable, checker.NonDelayArrayTable); }
/// <summary> /// Find out which layer (top: level 0) contains the value of variable v. /// If v is not on the stack, return -1; /// </summary> /// <param name="v"></param> /// <param name="iv"></param> /// <returns></returns> public int LevelOf(Variable v, InitializedVariables iv) { int depth = layers.Count; int i = 0; while (i < depth) { if (ContainsValueOf(v, iv, this[i])) { return i; } i++; } return -1; }
/// <summary> /// Copy Constructor /// </summary> /// <param name="old"></param> public InitializedVariables(InitializedVariables old) { this.analyzer = old.analyzer; this.egraph = (IEGraph)old.egraph.Clone(); this.referenceStatus = old.referenceStatus; }
protected override IDataFlowState VisitBlock(CfgBlock block, IDataFlowState state) { Debug.Assert(block!=null); InitializedVariables onEntry = (InitializedVariables)state; currBlock=block; if (Analyzer.Debug) { Analyzer.Write("---------block: "+block.UniqueId+";"); Analyzer.Write(" Exit:"); foreach (CfgBlock b in block.NormalSuccessors) Analyzer.Write(b.UniqueId+";"); if (block.UniqueSuccessor!=null) Analyzer.Write(" FallThrough: "+block.UniqueSuccessor+";"); if (block.ExceptionHandler!=null) Analyzer.Write(" ExHandler: "+block.ExceptionHandler.UniqueId+";"); Analyzer.WriteLine(""); state.Dump(); } if (block.ExceptionHandler!=null) { InitializedVariables exnState = onEntry; onEntry = new InitializedVariables(onEntry); // Copy state, since common ancestor cannot be modified any longer PushExceptionState(block, exnState); } InitializedVariables resultState = (InitializedVariables)base.VisitBlock(block, onEntry); if(block.UniqueId== cfg.NormalExit.UniqueId) { exitState=resultState; } return resultState; }
/// <summary> /// Entry point of the check. /// /// It create a new instance of the checker, and run the checker on the given method. /// </summary> /// <param name="t"></param> /// <param name="method"></param> public static IDelayInfo Check(TypeSystem t, Method method, Analyzer analyzer, PreDAStatus preResult) { Debug.Assert(method!=null && analyzer != null); MethodDefiniteAssignmentChecker checker= new MethodDefiniteAssignmentChecker(t, analyzer, preResult); checker.currentMethod=method; ControlFlowGraph cfg=analyzer.GetCFG(method); if(cfg==null) return null; InitializedVariables iv = new InitializedVariables(analyzer); checker.Run(cfg,iv); if (checker.exitState == null) { // Method has no normal return. We should consider having such method as annotated with [NoReturn]. return checker.NodeExistentialTable; } InitializedVariables onExit = new InitializedVariables((InitializedVariables)checker.exitState); // check for unassigned Out parameters. ParameterList pl=checker.currentMethod.Parameters; if(pl!=null){ for(int i=0; i < pl.Count; i++){ Parameter p = pl[i]; if(p.Type is Reference && p.IsOut && !onExit.IsAssignedRef(p, ((Reference)p.Type).ElementType as Struct)) checker.typeSystem.HandleError(method.Name,Error.ParamUnassigned,p.Name.Name); } } // check for struct fields in constructor if (method is InstanceInitializer && method.DeclaringType != null && method.DeclaringType.IsValueType) { Field unassignedfield = onExit.NonAssignedRefField(method.ThisParameter, (Struct)method.DeclaringType); if (unassignedfield != null) { checker.typeSystem.HandleError(method, Error.UnassignedThis, checker.typeSystem.GetTypeName(unassignedfield.DeclaringType)+"."+unassignedfield.Name.Name); } } // if delayed constructor, check for field initializations here if (method is InstanceInitializer && checker.iVisitor.IsUniversallyDelayed(method.ThisParameter)) { checker.iVisitor.CheckCtorNonNullFieldInitialization(method.ThisParameter, method.Name, onExit, Error.NonNullFieldNotInitializedAtEndOfDelayedConstructor); } // Check for uninitialized base class if (method is InstanceInitializer && method.DeclaringType is Class && method.DeclaringType.BaseType != null && method.DeclaringType.BaseType != SystemTypes.MulticastDelegate && !onExit.IsBaseAssigned()) checker.typeSystem.HandleError(method, Error.BaseNotInitialized); // Check for assigned but unreferenced variables. //TODO: this check should be moved to Looker so that constant folding does not affect it onExit.EmitAssignedButNotReferencedErrors(checker.typeSystem); return (checker.NodeExistentialTable); }
static InitializedVarStack mergeStack(InitializedVarStack stack1, InitializedVarStack stack2, InitializedVariables ivs) { return InitializedVarStack.Merge(stack1, stack2, ivs); }
// equals for two hash set of variables static bool ContainSameValue(HashSet s1, HashSet s2, InitializedVariables iv) { foreach (Variable v in s1) { if (!ContainsValueOf(v, iv, s2)) { return false; } } foreach (Variable v in s2) { if (!ContainsValueOf(v, iv, s1)) { return false; } } return true; }
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); }
/// <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; }
private void CheckUse(InitializedVariables iv, Variable var, Node context){ if (var==null) return; if(var is This) return; else if(! iv.IsAssigned(var)) { if(!mpc.reportedErrors.Contains(var) && var.Name != null && var.Name.Name!=""){ if (var.Name.Name.Equals("return value")){ mpc.typeSystem.HandleError(mpc.currentMethod.Name, Error.ReturnExpected, mpc.typeSystem.GetMemberSignature(mpc.currentMethod)); mpc.reportedErrors.Add(var,null); }else{ Node offendingNode = (var.SourceContext.Document == null)?context:var; mpc.typeSystem.HandleError(offendingNode, Error.UseDefViolation, var.Name.Name); mpc.reportedErrors.Add(var, null); } iv.SetReferencedAfterError(var); return; } iv.SetValueAssignedAndNonDelayed(var); } iv.SetReferenced(var); }
/// <summary> /// Whether a value or its alias is contained in a set, according to iv /// /// iv contains alias information. /// </summary> static bool ContainsValueOf(Variable v, InitializedVariables iv, HashSet set) { foreach (Variable u in set) { if (iv.HasSameValue(u, v)) { return true; } } return false; }
/// <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); }
/// <summary> /// For a variable v, if, according to iv, its value is the same as one of the /// variables kept on the top of stack, remove that value from the top of the stack. /// /// </summary> /// <param name="v"> The variable.</param> /// <param name="iv"> An InitializedVariables data structure, where an EGraph supposedly /// maintains the alias information. /// </param> public void RemoveVar(Variable v, InitializedVariables iv) { if (layers!= null && layers.Count != 0) { HashSet set = (HashSet)layers.Peek(); ArrayList toDelete = new ArrayList(); foreach (Variable u in set) { if (iv.HasSameValue(u, v)) { toDelete.Add(u); } } if (toDelete.Count != 0) { foreach (object o in toDelete) { set.Remove(o); } } } }
private void FixupNewlyConstructedObjectDelay(InitializedVariables iv, Variable receiver, InstanceInitializer ctor) { if (receiver == null) return; if (ctor == null) return; }
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> /// /// </summary> /// <param name="e"></param> /// <returns> /// true if 1) current method deos not contain a delayed parameter /// or 2) the type of concern does not contain a constructor that accepts delayed parameters otherthan /// "this" /// </returns> private bool delayedParametersNoEffect(TypeNode type, InitializedVariables ivs, PreDAStatus nns, Statement s) { if (type == null) return false; bool result = false; // see if this element type can possibly // have a constructor that accepts delayed parameters result = result || (!hasConstructorAcceptingDelay(type)); result = result || nns.OKToCommit(s); return result; }
/// <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 void CheckCtorNonNullFieldInitialization(Variable receiver, Node context, InitializedVariables iv, Error errorCode) { TypeSystem ts = this.mpc.typeSystem; Method currMethod = this.mpc.currentMethod; MemberList members = this.analyzer.GetTypeView(InitializedVariables.Canonical(currMethod.DeclaringType)).Members; for (int i = 0, n = members.Count; i < n; i++) { Field f = members[i] as Field; if (f == null) continue; if (f.IsStatic) continue; // don't worry about static fields here, this is only for instance fields if (!ts.IsNonNullType(f.Type)) continue; //if (f.IsModelfield) continue; //modelfields are assigned to implicitly, by a pack. But what about non-null modelfields and explicit superclass constructor calls? if (!iv.IsAssignedStructField(receiver, f)) { if (currMethod.HasCompilerGeneratedSignature) { // then it was a default ctor created for the class and the error message // should point at the field's declaration if (!(currMethod.DeclaringType is ClosureClass)) ts.HandleError(f, Error.NonNullFieldNotInitializedByDefaultConstructor, ts.GetMemberSignature(f)); } else { // the error message should point at the explicit base call that the user wrote or the one // inserted by the compiler ts.HandleError(context, errorCode, ts.GetMemberSignature(f)); } } } }
public static InitializedVariables Merge(InitializedVariables atMerge, InitializedVariables incoming, CfgBlock joinPoint) { bool unchanged; IEGraph result = atMerge.egraph.Join(incoming.egraph, joinPoint, out unchanged); if (unchanged) return null; return new InitializedVariables(incoming.analyzer, result, atMerge.referenceStatus); }