public void TypeCheck() { foreach (var proc in program.Procedures) { if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) { continue; } int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error int availableUptoLayerNum = int.MaxValue; List <int> attrs = FindLayers(proc.Attributes); if (attrs.Count == 1) { createdAtLayerNum = attrs[0]; } else if (attrs.Count == 2) { createdAtLayerNum = attrs[0]; availableUptoLayerNum = attrs[1]; } else { Error(proc, "Incorrect number of layers"); continue; } foreach (Ensures e in proc.Ensures) { MoverType moverType = GetMoverType(e); if (moverType == MoverType.Top) { continue; } CodeExpr codeExpr = e.Condition as CodeExpr; if (codeExpr == null) { Error(e, "An atomic action must be a CodeExpr"); continue; } if (procToActionInfo.ContainsKey(proc)) { Error(proc, "A procedure can have at most one atomic action"); continue; } if (availableUptoLayerNum <= createdAtLayerNum) { Error(proc, "Creation layer number must be less than the available upto layer number"); continue; } minLayerNum = int.MaxValue; maxLayerNum = -1; canAccessSharedVars = true; enclosingProc = proc; enclosingImpl = null; base.VisitEnsures(e); canAccessSharedVars = false; if (maxLayerNum > createdAtLayerNum) { Error(e, "A variable being accessed is introduced after this action is created"); } else if (availableUptoLayerNum > minLayerNum) { Error(e, "A variable being accessed is hidden before this action becomes unavailable"); } else { procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum); } } if (errorCount > 0) { continue; } if (!procToActionInfo.ContainsKey(proc)) { if (availableUptoLayerNum < createdAtLayerNum) { Error(proc, "Creation layer number must be no more than the available upto layer number"); continue; } else { procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); } } } if (errorCount > 0) { return; } foreach (var impl in program.Implementations) { if (!procToActionInfo.ContainsKey(impl.Proc)) { continue; } procToActionInfo[impl.Proc].hasImplementation = true; } foreach (var proc in procToActionInfo.Keys) { ActionInfo actionInfo = procToActionInfo[proc]; if (actionInfo.isExtern && actionInfo.hasImplementation) { Error(proc, "Extern procedure cannot have an implementation"); continue; } if (actionInfo.isExtern || actionInfo.hasImplementation) { continue; } if (leastUnimplementedLayerNum == int.MaxValue) { leastUnimplementedLayerNum = actionInfo.createdAtLayerNum; } else if (leastUnimplementedLayerNum != actionInfo.createdAtLayerNum) { Error(proc, "All unimplemented atomic actions must be created at the same layer"); } } foreach (var g in this.globalVarToSharedVarInfo.Keys) { var info = globalVarToSharedVarInfo[g]; if (!this.AllCreatedLayerNums.Contains(info.introLayerNum)) { Error(g, "Variable must be introduced with creation of some atomic action"); } if (info.hideLayerNum != int.MaxValue && !this.AllCreatedLayerNums.Contains(info.hideLayerNum)) { Error(g, "Variable must be hidden with creation of some atomic action"); } } if (errorCount > 0) { return; } this.VisitProgram(program); foreach (Procedure proc in program.Procedures) { if (procToActionInfo.ContainsKey(proc)) { continue; } foreach (var ie in proc.Modifies) { if (!SharedVariables.Contains(ie.Decl)) { continue; } Error(proc, "A ghost procedure must not modify a global variable with layer annotation"); } } if (errorCount > 0) { return; } YieldTypeChecker.PerformYieldSafeCheck(this); new LayerEraser().VisitProgram(program); }
public void TypeCheck() { foreach (var proc in program.Procedures) { if (!QKeyValue.FindBoolAttribute(proc.Attributes, "pure")) { continue; } if (QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) { Error(proc, "Pure procedure must not yield"); continue; } if (QKeyValue.FindBoolAttribute(proc.Attributes, "layer")) { Error(proc, "Pure procedure must not have layers"); continue; } if (proc.Modifies.Count > 0) { Error(proc, "Pure procedure must not modify a global variable"); continue; } procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(); } foreach (var proc in program.Procedures) { if (QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) { continue; } var procLayerNums = FindLayers(proc.Attributes); if (procLayerNums.Count == 0) { continue; } foreach (IdentifierExpr ie in proc.Modifies) { if (!globalVarToSharedVarInfo.ContainsKey(ie.Decl)) { Error(proc, "Atomic procedure cannot modify a global variable without layer numbers"); continue; } } int lower, upper; if (procLayerNums.Count == 1) { lower = procLayerNums[0]; upper = procLayerNums[0]; } else if (procLayerNums.Count == 2) { lower = procLayerNums[0]; upper = procLayerNums[1]; if (lower >= upper) { Error(proc, "Lower layer must be less than upper layer"); continue; } } else { Error(proc, "Atomic procedure must specify a layer range"); continue; } LayerRange layerRange = new LayerRange(lower, upper); procToAtomicProcedureInfo[proc] = new AtomicProcedureInfo(layerRange); } if (errorCount > 0) { return; } foreach (Implementation impl in program.Implementations) { if (!procToAtomicProcedureInfo.ContainsKey(impl.Proc)) { continue; } var atomicProcedureInfo = procToAtomicProcedureInfo[impl.Proc]; if (atomicProcedureInfo.isPure) { this.enclosingImpl = impl; (new PurityChecker(this)).VisitImplementation(impl); } else { this.enclosingImpl = impl; this.sharedVarsAccessed = new HashSet <Variable>(); (new PurityChecker(this)).VisitImplementation(impl); LayerRange upperBound = FindLayerRange(); LayerRange lowerBound = atomicProcedureInfo.layerRange; if (!lowerBound.Subset(upperBound)) { Error(impl, "Atomic procedure cannot access global variable"); } this.sharedVarsAccessed = null; } } if (errorCount > 0) { return; } foreach (var proc in program.Procedures) { if (!QKeyValue.FindBoolAttribute(proc.Attributes, "yields")) { continue; } int createdAtLayerNum; // must be initialized by the following code, otherwise it is an error int availableUptoLayerNum = int.MaxValue; List <int> attrs = FindLayers(proc.Attributes); if (attrs.Count == 1) { createdAtLayerNum = attrs[0]; } else if (attrs.Count == 2) { createdAtLayerNum = attrs[0]; availableUptoLayerNum = attrs[1]; } else { Error(proc, "Incorrect number of layers"); continue; } foreach (Ensures e in proc.Ensures) { MoverType moverType = GetMoverType(e); if (moverType == MoverType.Top) { continue; } CodeExpr codeExpr = e.Condition as CodeExpr; if (codeExpr == null) { Error(e, "An atomic action must be a CodeExpr"); continue; } if (procToActionInfo.ContainsKey(proc)) { Error(proc, "A procedure can have at most one atomic action"); continue; } if (availableUptoLayerNum <= createdAtLayerNum) { Error(proc, "Creation layer number must be less than the available upto layer number"); continue; } sharedVarsAccessed = new HashSet <Variable>(); enclosingProc = proc; enclosingImpl = null; base.VisitEnsures(e); LayerRange upperBound = FindLayerRange(); LayerRange lowerBound = new LayerRange(createdAtLayerNum, availableUptoLayerNum); if (lowerBound.Subset(upperBound)) { procToActionInfo[proc] = new AtomicActionInfo(proc, e, moverType, createdAtLayerNum, availableUptoLayerNum); } else { Error(e, "A variable being accessed in this action is unavailable"); } sharedVarsAccessed = null; } if (errorCount > 0) { continue; } if (!procToActionInfo.ContainsKey(proc)) { if (availableUptoLayerNum < createdAtLayerNum) { Error(proc, "Creation layer number must be no more than the available upto layer number"); continue; } else { procToActionInfo[proc] = new ActionInfo(proc, createdAtLayerNum, availableUptoLayerNum); } } } if (errorCount > 0) { return; } foreach (var impl in program.Implementations) { if (!procToActionInfo.ContainsKey(impl.Proc)) { continue; } ActionInfo actionInfo = procToActionInfo[impl.Proc]; procToActionInfo[impl.Proc].hasImplementation = true; if (actionInfo.isExtern) { Error(impl.Proc, "Extern procedure cannot have an implementation"); } } if (errorCount > 0) { return; } foreach (Procedure proc in procToActionInfo.Keys) { for (int i = 0; i < proc.InParams.Count; i++) { Variable v = proc.InParams[i]; var layer = FindLocalVariableLayer(proc, v, procToActionInfo[proc].createdAtLayerNum); if (layer == int.MinValue) { continue; } localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); } for (int i = 0; i < proc.OutParams.Count; i++) { Variable v = proc.OutParams[i]; var layer = FindLocalVariableLayer(proc, v, procToActionInfo[proc].createdAtLayerNum); if (layer == int.MinValue) { continue; } localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); } } foreach (Implementation node in program.Implementations) { if (!procToActionInfo.ContainsKey(node.Proc)) { continue; } foreach (Variable v in node.LocVars) { var layer = FindLocalVariableLayer(node, v, procToActionInfo[node.Proc].createdAtLayerNum); if (layer == int.MinValue) { continue; } localVarToLocalVariableInfo[v] = new LocalVariableInfo(layer); } for (int i = 0; i < node.Proc.InParams.Count; i++) { Variable v = node.Proc.InParams[i]; if (!localVarToLocalVariableInfo.ContainsKey(v)) { continue; } var layer = localVarToLocalVariableInfo[v].layer; localVarToLocalVariableInfo[node.InParams[i]] = new LocalVariableInfo(layer); } for (int i = 0; i < node.Proc.OutParams.Count; i++) { Variable v = node.Proc.OutParams[i]; if (!localVarToLocalVariableInfo.ContainsKey(v)) { continue; } var layer = localVarToLocalVariableInfo[v].layer; localVarToLocalVariableInfo[node.OutParams[i]] = new LocalVariableInfo(layer); } } if (errorCount > 0) { return; } this.VisitProgram(program); if (errorCount > 0) { return; } YieldTypeChecker.PerformYieldSafeCheck(this); new LayerEraser().VisitProgram(program); }