public LatticeCell Meet(LatticeCell other) { if (other.Kind == LatticeCellKind.Top) { return(this); } switch (Kind) { case LatticeCellKind.Top: return(other); case LatticeCellKind.Constant: if (other.Kind == LatticeCellKind.Constant && Value.Equals(other.Value)) { return(this); } else { return(Bottom); } case LatticeCellKind.NonNull: if (other.Kind == LatticeCellKind.NonNull) { return(this); } else { return(Bottom); } case LatticeCellKind.Bottom: default: return(this); } }
private LatticeCell EvaluateInstruction( Instruction instruction, IReadOnlyDictionary <ValueTag, LatticeCell> cells, FlowGraph graph) { if (instruction.Prototype is CopyPrototype) { // Special case on copy instructions because they're // easy to deal with: just return the lattice cell for // the argument. return(GetCellForValue(instruction.Arguments[0], cells)); } var foundTop = false; var args = new Constant[instruction.Arguments.Count]; for (int i = 0; i < args.Length; i++) { var argCell = GetCellForValue(instruction.Arguments[i], cells); if (argCell.Kind == LatticeCellKind.Top) { // We can't evaluate this value *yet*. Keep looking // for bottom argument cells and set a flag to record // that this value cannot be evaluated yet. foundTop = true; } else if (argCell.Kind == LatticeCellKind.Constant) { // Yay. We found a compile-time constant. args[i] = argCell.Value; } else { // We can't evaluate this value at compile-time // because one if its arguments is unknown. // Time to early-out. return(EvaluateNonConstantInstruction(instruction, graph)); } } if (foundTop) { // We can't evaluate this value yet. return(LatticeCell.Top); } else { // Evaluate the instruction. var constant = Evaluate(instruction.Prototype, args); if (constant == null) { // Turns out we can't evaluate the instruction. But maybe // we can say something sensible about its nullability? return(EvaluateNonConstantInstruction(instruction, graph)); } else { return(LatticeCell.Constant(constant)); } } }