public static BoundConstantExpression FoldConstantBinaryExpression( BindContext context, BinaryExpressionSyntax syntax, MethodSymbol binaryOperator, BoundExpression lhs, BoundExpression rhs) { // Value type + null comparison which will always be false for == and true for != // This folding is needed for null comparisons in generics to work as expected if ((lhs.ValueType.IsValueType && rhs.IsConstant && rhs.ConstantValue.Value == null) || (rhs.ValueType.IsValueType && lhs.IsConstant && lhs.ConstantValue.Value == null)) { if (syntax.OperatorToken.Kind() == SyntaxKind.EqualsEqualsToken) { return(new BoundConstantExpression(new ConstantValue <bool>(false), context.GetTypeSymbol(typeof(bool)), syntax)); } if (syntax.OperatorToken.Kind() == SyntaxKind.ExclamationEqualsToken) { return(new BoundConstantExpression(new ConstantValue <bool>(true), context.GetTypeSymbol(typeof(bool)), syntax)); } } if (!lhs.IsConstant || !rhs.IsConstant) { return(null); } if (binaryOperator == null || (binaryOperator.IsOperator && binaryOperator.IsExtern)) { object foldedValue; object lhsValue = lhs.ConstantValue.Value; object rhsValue = rhs.ConstantValue.Value; switch (syntax.OperatorToken.Kind()) { case SyntaxKind.PlusToken: foldedValue = DynamicInvoke.Add(lhsValue, rhsValue); break; case SyntaxKind.MinusToken: foldedValue = DynamicInvoke.Sub(lhsValue, rhsValue); break; case SyntaxKind.AsteriskToken: foldedValue = DynamicInvoke.Mul(lhsValue, rhsValue); break; case SyntaxKind.SlashToken: foldedValue = DynamicInvoke.Div(lhsValue, rhsValue); break; case SyntaxKind.PercentToken: foldedValue = DynamicInvoke.Mod(lhsValue, rhsValue); break; case SyntaxKind.LessThanLessThanToken: foldedValue = DynamicInvoke.LSh(lhsValue, rhsValue); break; case SyntaxKind.GreaterThanGreaterThanToken: foldedValue = DynamicInvoke.RSh(lhsValue, rhsValue); break; case SyntaxKind.CaretToken: foldedValue = DynamicInvoke.Xor(lhsValue, rhsValue); break; case SyntaxKind.AmpersandToken: case SyntaxKind.AmpersandAmpersandToken: // When we're dealing with constants short circuiting shouldn't matter foldedValue = DynamicInvoke.BitwiseAnd(lhsValue, rhsValue); break; case SyntaxKind.BarToken: case SyntaxKind.BarBarToken: foldedValue = DynamicInvoke.BitwiseOr(lhsValue, rhsValue); break; case SyntaxKind.GreaterThanToken: foldedValue = DynamicInvoke.GreaterThan(lhsValue, rhsValue); break; case SyntaxKind.GreaterThanEqualsToken: foldedValue = DynamicInvoke.GreaterThanOrEquals(lhsValue, rhsValue); break; case SyntaxKind.LessThanToken: foldedValue = DynamicInvoke.LessThan(lhsValue, rhsValue); break; case SyntaxKind.LessThanOrEqualExpression: foldedValue = DynamicInvoke.LessThanOrEquals(lhsValue, rhsValue); break; case SyntaxKind.EqualsEqualsToken: foldedValue = DynamicInvoke.Equal(lhsValue, rhsValue); break; case SyntaxKind.ExclamationEqualsToken: foldedValue = DynamicInvoke.NotEqual(lhsValue, rhsValue); break; default: return(null); } IConstantValue constantValue = (IConstantValue)Activator.CreateInstance(typeof(ConstantValue <>).MakeGenericType(foldedValue.GetType()), foldedValue); return(new BoundConstantExpression(constantValue, context.GetTypeSymbol(foldedValue.GetType()), syntax)); } return(null); }