public static DataType?GetResult(this ArithmeticOperation operation, DataType lhs, DataType rhs, out bool verifiable) { Contract.Requires(operation.IsBinary()); Contract.Requires(lhs.IsStackType()); Contract.Requires(rhs.IsStackType()); verifiable = true; switch (operation) { // ECMA 335 III.1.5 Table 2: Binary Numeric Operations (add, div, mul, rem, sub) case ArithmeticOperation.Addition: case ArithmeticOperation.Division: case ArithmeticOperation.Multiplication: case ArithmeticOperation.Remainder: case ArithmeticOperation.Subtraction: // ECMA 335 III.1.5 Table 7: Overflow Arithmetic Operations (add.ovf, add.ovf.un, mul.ovf, mul.ovf.un, sub.ovf, sub.ovf.un) case ArithmeticOperation.Addition_OverflowCheck: case ArithmeticOperation.Addition_UnsignedWithOverflowCheck: case ArithmeticOperation.Multiplication_OverflowCheck: case ArithmeticOperation.Multiplication_UnsignedWithOverflowCheck: case ArithmeticOperation.Subtraction_OverflowCheck: case ArithmeticOperation.Subtraction_UnsignedWithOverflowCheck: if (lhs == rhs) { if (lhs.IsIntegerStackType()) { return(lhs); } if (lhs.IsFloat() && !operation.IsOverflowChecked()) { return(lhs); } if (lhs.IsManagedPointer() && (operation == ArithmeticOperation.Subtraction || operation == ArithmeticOperation.Subtraction_UnsignedWithOverflowCheck)) { verifiable = false; return(DataType.NativeInt); } } else { if ((lhs == DataType.Int32 && rhs == DataType.NativeInt) || (lhs == DataType.NativeInt && rhs == DataType.Int32)) { return(DataType.NativeInt); } if (lhs.IsManagedPointer() && (rhs == DataType.Int32 || rhs == DataType.NativeInt) && (operation == ArithmeticOperation.Addition || operation == ArithmeticOperation.Subtraction || operation == ArithmeticOperation.Addition_UnsignedWithOverflowCheck || operation == ArithmeticOperation.Subtraction_UnsignedWithOverflowCheck)) { verifiable = false; return(lhs); } if ((lhs == DataType.Int32 || lhs == DataType.NativeInt) && rhs.IsManagedPointer() && (operation == ArithmeticOperation.Addition || operation == ArithmeticOperation.Addition_UnsignedWithOverflowCheck)) { verifiable = false; return(rhs); } } break; // ECMA 335 III.1.5 Table 5: Integer Operations (and, div.un, or, rem.un, xor - 'not' excluded) case ArithmeticOperation.BitwiseAnd: case ArithmeticOperation.Division_Unsigned: case ArithmeticOperation.BitwiseOr: case ArithmeticOperation.Remainder_Unsigned: case ArithmeticOperation.BitwiseXor: if (lhs == rhs) { if (lhs.IsIntegerStackType()) { return(lhs); } } else { if ((lhs == DataType.Int32 && rhs == DataType.NativeInt) || (lhs == DataType.NativeInt && rhs == DataType.Int32)) { return(DataType.NativeInt); } } break; // ECMA 335 III.1.5 Table 6: Shift Operations (shl, shr, shr.un) case ArithmeticOperation.BitShiftLeft: case ArithmeticOperation.BitShiftRight: case ArithmeticOperation.BitShiftRight_Unsigned: if (lhs.IsIntegerStackType() && (rhs == DataType.Int32 || rhs == DataType.NativeInt)) { return(lhs); } break; default: throw new ArgumentException("Invalid arithmetic operation enumerant.", "operation"); } verifiable = false; return(null); }