public BinaryOperatorSignature(BinaryOperatorKind kind, TypeSymbol returnType, TypeSymbol leftParameterType, TypeSymbol rightParameterType) { Kind = kind; ReturnType = returnType; _leftParameterType = leftParameterType; _rightParameterType = rightParameterType; }
internal SingleValueNode Parse(Lexer lexer) { while (lexer.MoveNext()) { var token = lexer.Current; switch (token.TokenType) { case TokenType.And: this.nextBinaryOperatorKind = BinaryOperatorKind.And; this.UpdateExpressionTree(); break; case TokenType.Or: this.nextBinaryOperatorKind = BinaryOperatorKind.Or; this.UpdateExpressionTree(); break; default: this.tokens.Enqueue(token); break; } } this.nextBinaryOperatorKind = BinaryOperatorKind.None; this.UpdateExpressionTree(); return this.nodeStack.Pop(); }
/// <summary> /// Compute the result type of a binary operator based on the type of its operands and the operator kind. /// </summary> /// <param name="typeReference">The type reference of the operators.</param> /// <param name="operatorKind">The kind of operator.</param> /// <returns>The result type reference of the binary operator.</returns> internal static IEdmPrimitiveTypeReference GetBinaryOperatorResultType(IEdmPrimitiveTypeReference typeReference, BinaryOperatorKind operatorKind) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(typeReference != null, "type != null"); switch (operatorKind) { case BinaryOperatorKind.Or: // fall through case BinaryOperatorKind.And: // fall through case BinaryOperatorKind.Equal: // fall through case BinaryOperatorKind.NotEqual: // fall through case BinaryOperatorKind.GreaterThan: // fall through case BinaryOperatorKind.GreaterThanOrEqual: // fall through case BinaryOperatorKind.LessThan: // fall through case BinaryOperatorKind.LessThanOrEqual: return EdmCoreModel.Instance.GetBoolean(typeReference.IsNullable); case BinaryOperatorKind.Add: // fall through case BinaryOperatorKind.Subtract: // fall through case BinaryOperatorKind.Multiply: // fall through case BinaryOperatorKind.Divide: // fall through case BinaryOperatorKind.Modulo: return typeReference; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.QueryNodeUtils_BinaryOperatorResultType_UnreachableCodepath)); } }
/// <summary> /// Compute the result type of a binary operator based on the type of its operands and the operator kind. /// </summary> /// <param name="type">The type of the operators.</param> /// <param name="operatorKind">The kind of operator.</param> /// <returns>The result type of the binary operator.</returns> internal static ResourceType GetBinaryOperatorResultType(ResourceType type, BinaryOperatorKind operatorKind) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(type != null, "type != null"); switch (operatorKind) { case BinaryOperatorKind.Or: // fall through case BinaryOperatorKind.And: // fall through case BinaryOperatorKind.Equal: // fall through case BinaryOperatorKind.NotEqual: // fall through case BinaryOperatorKind.GreaterThan: // fall through case BinaryOperatorKind.GreaterThanOrEqual: // fall through case BinaryOperatorKind.LessThan: // fall through case BinaryOperatorKind.LessThanOrEqual: Type resultType = Nullable.GetUnderlyingType(type.InstanceType) == null ? typeof(bool) : typeof(bool?); return ResourceType.GetPrimitiveResourceType(resultType); case BinaryOperatorKind.Add: // fall through case BinaryOperatorKind.Subtract: // fall through case BinaryOperatorKind.Multiply: // fall through case BinaryOperatorKind.Divide: // fall through case BinaryOperatorKind.Modulo: return type; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.QueryNodeUtils_BinaryOperatorResultType_UnreachableCodepath)); } }
public static AndConstraint<BinaryOperatorToken> ShouldBeBinaryOperatorQueryToken(this QueryToken token, BinaryOperatorKind expectedOperatorKind) { token.Should().BeOfType<BinaryOperatorToken>(); var propertyAccessQueryToken = token.As<BinaryOperatorToken>(); propertyAccessQueryToken.Kind.Should().Be(QueryTokenKind.BinaryOperator); propertyAccessQueryToken.OperatorKind.Should().Be(expectedOperatorKind); return new AndConstraint<BinaryOperatorToken>(propertyAccessQueryToken); }
public BoundAssignmentExpression(BoundExpression left, BinaryOperatorKind? operatorKind, BoundExpression right) : base(BoundNodeKind.AssignmentExpression) { OperatorKind = operatorKind; Left = left; Right = right; Type = left.Type; }
public BoundBinaryExpression(BinaryOperatorKind operatorKind, BoundExpression left, BoundExpression right, OverloadResolutionResult<BinaryOperatorSignature> result) : base(BoundNodeKind.BinaryExpression) { OperatorKind = operatorKind; Left = left; Right = right; Result = result; }
public BoundBinaryExpression(BinaryExpressionSyntax syntax, BinaryOperatorKind operatorKind, BoundExpression left, BoundExpression right, TypeSymbol type) : base(BoundNodeKind.BinaryExpression, syntax) { OperatorKind = operatorKind; Left = left; Right = right; Type = type; }
public BinaryOperatorSignature(BinaryOperatorKind kind, TypeSymbol leftType, TypeSymbol rightType, TypeSymbol returnType, MethodSymbol method = null) { this.Kind = kind; this.LeftType = leftType; this.RightType = rightType; this.ReturnType = returnType; this.Method = method; }
public override void PromoteBinaryOperandTypes( BinaryOperatorKind binaryOperatorKind, ref SingleValueNode leftNode, ref SingleValueNode rightNode, out IEdmTypeReference typeReference) { stringAsEnum.PromoteBinaryOperandTypes(binaryOperatorKind, ref leftNode, ref rightNode, out typeReference); }
private static OverloadResolutionResult<BinaryOperatorSignature> ResolveOverloads(BinaryOperatorKind kind, TypeSymbol leftOperandType, TypeSymbol rightOperandType) { var builtInSignatures = GetBuiltInSignatures(kind); if (BothTypesBuiltIn(leftOperandType, rightOperandType)) return OverloadResolution.Perform(builtInSignatures, leftOperandType, rightOperandType); return OverloadResolutionResult<BinaryOperatorSignature>.None; }
/// <summary> /// Promote the left and right operand types /// </summary> /// <param name="binaryOperatorKind">the operator kind</param> /// <param name="leftNode">the left operand</param> /// <param name="rightNode">the right operand</param> /// <param name="typeReference">type reference for the result BinaryOperatorNode.</param> public virtual void PromoteBinaryOperandTypes( BinaryOperatorKind binaryOperatorKind, ref SingleValueNode leftNode, ref SingleValueNode rightNode, out IEdmTypeReference typeReference) { typeReference = null; BinaryOperatorBinder.PromoteOperandTypes(binaryOperatorKind, ref leftNode, ref rightNode); }
/// <summary> /// Create a new BinaryOperatorQueryToken given the operator, left and right query. /// </summary> /// <param name="operatorKind">The operator represented by this node.</param> /// <param name="left">The left operand.</param> /// <param name="right">The right operand.</param> public BinaryOperatorQueryToken(BinaryOperatorKind operatorKind, QueryToken left, QueryToken right) { ExceptionUtils.CheckArgumentNotNull(left, "left"); ExceptionUtils.CheckArgumentNotNull(right, "right"); this.operatorKind = operatorKind; this.left = left; this.right = right; }
private BoundExpression MakeBinaryOperator( CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type, MethodSymbol method, bool isPointerElementAccess = false, bool isCompoundAssignment = false, BoundUnaryOperator applyParentUnaryOperator = null) { return MakeBinaryOperator(null, syntax, operatorKind, loweredLeft, loweredRight, type, method, isPointerElementAccess, isCompoundAssignment, applyParentUnaryOperator); }
/// <summary> /// Promote the left and right operand types /// </summary> /// <param name="binaryOperatorKind">the operator kind</param> /// <param name="left">the left operand</param> /// <param name="right">the right operand</param> internal static void PromoteOperandTypes(BinaryOperatorKind binaryOperatorKind, ref SingleValueNode left, ref SingleValueNode right) { IEdmTypeReference leftType; IEdmTypeReference rightType; if (!TypePromotionUtils.PromoteOperandTypes(binaryOperatorKind, left, right, out leftType, out rightType)) { string leftTypeName = left.TypeReference == null ? "<null>" : left.TypeReference.FullName(); string rightTypeName = right.TypeReference == null ? "<null>" : right.TypeReference.FullName(); throw new ODataException(ODataErrorStrings.MetadataBinder_IncompatibleOperandsError(leftTypeName, rightTypeName, binaryOperatorKind)); } left = MetadataBindingUtils.ConvertToTypeIfNeeded(left, leftType); right = MetadataBindingUtils.ConvertToTypeIfNeeded(right, rightType); }
//$filter=EnterpriseName%20eq%20%27DIEGO_520%27 public BinaryOperatorResolver(BinaryOperatorNode binaryOperator) { if (binaryOperator != null) { var property = binaryOperator.Left as SingleValuePropertyAccessNode ?? binaryOperator.Right as SingleValuePropertyAccessNode; var constant = binaryOperator.Left as ConstantNode ?? binaryOperator.Right as ConstantNode; if (property != null && property.Property != null && constant != null && constant.Value != null) { Property = property.Property.Name; Operator = binaryOperator.OperatorKind; Value = constant.LiteralText; } } }
private void AddDelegateOperation(BinaryOperatorKind kind, TypeSymbol delegateType, ArrayBuilder<BinaryOperatorSignature> operators) { switch (kind) { case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Delegate, delegateType, delegateType, Compilation.GetSpecialType(SpecialType.System_Boolean))); break; case BinaryOperatorKind.Addition: case BinaryOperatorKind.Subtraction: default: operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Delegate, delegateType, delegateType, delegateType)); break; } }
private static IEnumerable<BinaryOperatorSignature> GetBuiltInSignatures(BinaryOperatorKind kind) { switch (kind) { case BinaryOperatorKind.Multiply: return BuiltInMultiplySignatures; case BinaryOperatorKind.Divide: return BuiltInDivideSignatures; case BinaryOperatorKind.Modulo: return BuiltInModulusSignatures; case BinaryOperatorKind.Add: return BuiltInAddSignatures; case BinaryOperatorKind.Subtract: return BuiltInSubSignatures; case BinaryOperatorKind.Equal: return BuiltInEqualSignatures; case BinaryOperatorKind.NotEqual: return BuiltInNotEqualSignatures; case BinaryOperatorKind.Less: return BuiltInLessSignatures; case BinaryOperatorKind.LessEqual: return BuiltInLessOrEqualSignatures; case BinaryOperatorKind.Greater: return BuiltInGreaterSignatures; case BinaryOperatorKind.GreaterEqual: return BuiltInGreaterOrEqualSignatures; case BinaryOperatorKind.BitwiseXor: return BuiltInBitXorSignatures; case BinaryOperatorKind.BitwiseAnd: return BuiltInBitAndSignatures; case BinaryOperatorKind.BitwiseOr: return BuiltInBitOrSignatures; case BinaryOperatorKind.LeftShift: return BuiltInLeftShiftSignatures; case BinaryOperatorKind.RightShift: return BuiltInRightShiftSignatures; case BinaryOperatorKind.LogicalAnd: return BuiltInLogicalAndSignatures; case BinaryOperatorKind.LogicalOr: return BuiltInLogicalOrSignatures; default: throw new ArgumentOutOfRangeException(nameof(kind), kind.ToString()); } }
public override void PromoteBinaryOperandTypes( BinaryOperatorKind binaryOperatorKind, ref SingleValueNode leftNode, ref SingleValueNode rightNode, out IEdmTypeReference typeReference) { if (binaryOperatorKind == BinaryOperatorKind.Multiply && leftNode.TypeReference != null && leftNode.TypeReference.IsString() && rightNode.TypeReference != null && rightNode.TypeReference.IsInt32()) { // The result type should be Edm.String, as it could be nullable or not, we just took the left // node's type reference. typeReference = leftNode.TypeReference; return; } // fallback base.PromoteBinaryOperandTypes(binaryOperatorKind, ref leftNode, ref rightNode, out typeReference); }
/// <summary> /// Promote the left and right operand types, supports enum property and string constant scenario. /// </summary> /// <param name="binaryOperatorKind">the operator kind</param> /// <param name="leftNode">the left operand</param> /// <param name="rightNode">the right operand</param> /// <param name="typeReference">type reference for the result BinaryOperatorNode.</param> public override void PromoteBinaryOperandTypes( BinaryOperatorKind binaryOperatorKind, ref SingleValueNode leftNode, ref SingleValueNode rightNode, out IEdmTypeReference typeReference) { typeReference = null; if (leftNode.TypeReference != null && rightNode.TypeReference != null) { if ((leftNode.TypeReference.IsEnum()) && (rightNode.TypeReference.IsString()) && rightNode is ConstantNode) { string text = ((ConstantNode)rightNode).Value as string; ODataEnumValue val; IEdmTypeReference typeRef = leftNode.TypeReference; if (TryParseEnum(typeRef.Definition as IEdmEnumType, text, out val)) { rightNode = new ConstantNode(val, text, typeRef); return; } } else if ((rightNode.TypeReference.IsEnum()) && (leftNode.TypeReference.IsString()) && leftNode is ConstantNode) { string text = ((ConstantNode)leftNode).Value as string; ODataEnumValue val; IEdmTypeReference typeRef = rightNode.TypeReference; if (TryParseEnum(typeRef.Definition as IEdmEnumType, text, out val)) { leftNode = new ConstantNode(val, text, typeRef); return; } } } // fallback base.PromoteBinaryOperandTypes(binaryOperatorKind, ref leftNode, ref rightNode, out typeReference); }
private BoundExpression RewritePointerNumericOperator( CSharpSyntaxNode syntax, BinaryOperatorKind kind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol returnType, bool isPointerElementAccess, bool isLeftPointer) { if (isLeftPointer) { loweredRight = MakeSizeOfMultiplication(loweredRight, (PointerTypeSymbol)loweredLeft.Type, kind.IsChecked()); } else { loweredLeft = MakeSizeOfMultiplication(loweredLeft, (PointerTypeSymbol)loweredRight.Type, kind.IsChecked()); } if (isPointerElementAccess) { Debug.Assert(kind.Operator() == BinaryOperatorKind.Addition); // NOTE: This is here to persist a bug in Dev10. checked(p[n]) should be equivalent to checked(*(p + n)), // but Dev10 omits the check on the addition (though it retains the check on the multiplication of n by // the size). kind = kind & ~BinaryOperatorKind.Checked; } return new BoundBinaryOperator( syntax, kind, loweredLeft, loweredRight, ConstantValue.NotAvailable, null, LookupResultKind.Viable, returnType); }
internal void GetSimpleBuiltInOperators(BinaryOperatorKind kind, ArrayBuilder <BinaryOperatorSignature> operators) { if (builtInOperators == null) { var logicalOperators = new ImmutableArray <BinaryOperatorSignature>[] { ImmutableArray <BinaryOperatorSignature> .Empty, //multiplication ImmutableArray <BinaryOperatorSignature> .Empty, //addition ImmutableArray <BinaryOperatorSignature> .Empty, //subtraction ImmutableArray <BinaryOperatorSignature> .Empty, //division ImmutableArray <BinaryOperatorSignature> .Empty, //remainder ImmutableArray <BinaryOperatorSignature> .Empty, //left shift ImmutableArray <BinaryOperatorSignature> .Empty, //right shift ImmutableArray <BinaryOperatorSignature> .Empty, //equal ImmutableArray <BinaryOperatorSignature> .Empty, //not equal ImmutableArray <BinaryOperatorSignature> .Empty, //greater than ImmutableArray <BinaryOperatorSignature> .Empty, //less than ImmutableArray <BinaryOperatorSignature> .Empty, //greater than or equal ImmutableArray <BinaryOperatorSignature> .Empty, //less than or equal ImmutableArray.Create <BinaryOperatorSignature>(GetSignature(BinaryOperatorKind.LogicalBoolAnd)), //and ImmutableArray <BinaryOperatorSignature> .Empty, //xor ImmutableArray.Create <BinaryOperatorSignature>(GetSignature(BinaryOperatorKind.LogicalBoolOr)), //or }; var nonLogicalOperators = new ImmutableArray <BinaryOperatorSignature>[] { (new [] { GetSignature(BinaryOperatorKind.IntMultiplication), GetSignature(BinaryOperatorKind.UIntMultiplication), GetSignature(BinaryOperatorKind.LongMultiplication), GetSignature(BinaryOperatorKind.ULongMultiplication), GetSignature(BinaryOperatorKind.FloatMultiplication), GetSignature(BinaryOperatorKind.DoubleMultiplication), GetSignature(BinaryOperatorKind.DecimalMultiplication), GetSignature(BinaryOperatorKind.LiftedIntMultiplication), GetSignature(BinaryOperatorKind.LiftedUIntMultiplication), GetSignature(BinaryOperatorKind.LiftedLongMultiplication), GetSignature(BinaryOperatorKind.LiftedULongMultiplication), GetSignature(BinaryOperatorKind.LiftedFloatMultiplication), GetSignature(BinaryOperatorKind.LiftedDoubleMultiplication), GetSignature(BinaryOperatorKind.LiftedDecimalMultiplication), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntAddition), GetSignature(BinaryOperatorKind.UIntAddition), GetSignature(BinaryOperatorKind.LongAddition), GetSignature(BinaryOperatorKind.ULongAddition), GetSignature(BinaryOperatorKind.FloatAddition), GetSignature(BinaryOperatorKind.DoubleAddition), GetSignature(BinaryOperatorKind.DecimalAddition), GetSignature(BinaryOperatorKind.LiftedIntAddition), GetSignature(BinaryOperatorKind.LiftedUIntAddition), GetSignature(BinaryOperatorKind.LiftedLongAddition), GetSignature(BinaryOperatorKind.LiftedULongAddition), GetSignature(BinaryOperatorKind.LiftedFloatAddition), GetSignature(BinaryOperatorKind.LiftedDoubleAddition), GetSignature(BinaryOperatorKind.LiftedDecimalAddition), GetSignature(BinaryOperatorKind.StringConcatenation), GetSignature(BinaryOperatorKind.StringAndObjectConcatenation), GetSignature(BinaryOperatorKind.ObjectAndStringConcatenation), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntSubtraction), GetSignature(BinaryOperatorKind.UIntSubtraction), GetSignature(BinaryOperatorKind.LongSubtraction), GetSignature(BinaryOperatorKind.ULongSubtraction), GetSignature(BinaryOperatorKind.FloatSubtraction), GetSignature(BinaryOperatorKind.DoubleSubtraction), GetSignature(BinaryOperatorKind.DecimalSubtraction), GetSignature(BinaryOperatorKind.LiftedIntSubtraction), GetSignature(BinaryOperatorKind.LiftedUIntSubtraction), GetSignature(BinaryOperatorKind.LiftedLongSubtraction), GetSignature(BinaryOperatorKind.LiftedULongSubtraction), GetSignature(BinaryOperatorKind.LiftedFloatSubtraction), GetSignature(BinaryOperatorKind.LiftedDoubleSubtraction), GetSignature(BinaryOperatorKind.LiftedDecimalSubtraction), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntDivision), GetSignature(BinaryOperatorKind.UIntDivision), GetSignature(BinaryOperatorKind.LongDivision), GetSignature(BinaryOperatorKind.ULongDivision), GetSignature(BinaryOperatorKind.FloatDivision), GetSignature(BinaryOperatorKind.DoubleDivision), GetSignature(BinaryOperatorKind.DecimalDivision), GetSignature(BinaryOperatorKind.LiftedIntDivision), GetSignature(BinaryOperatorKind.LiftedUIntDivision), GetSignature(BinaryOperatorKind.LiftedLongDivision), GetSignature(BinaryOperatorKind.LiftedULongDivision), GetSignature(BinaryOperatorKind.LiftedFloatDivision), GetSignature(BinaryOperatorKind.LiftedDoubleDivision), GetSignature(BinaryOperatorKind.LiftedDecimalDivision), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntRemainder), GetSignature(BinaryOperatorKind.UIntRemainder), GetSignature(BinaryOperatorKind.LongRemainder), GetSignature(BinaryOperatorKind.ULongRemainder), GetSignature(BinaryOperatorKind.FloatRemainder), GetSignature(BinaryOperatorKind.DoubleRemainder), GetSignature(BinaryOperatorKind.DecimalRemainder), GetSignature(BinaryOperatorKind.LiftedIntRemainder), GetSignature(BinaryOperatorKind.LiftedUIntRemainder), GetSignature(BinaryOperatorKind.LiftedLongRemainder), GetSignature(BinaryOperatorKind.LiftedULongRemainder), GetSignature(BinaryOperatorKind.LiftedFloatRemainder), GetSignature(BinaryOperatorKind.LiftedDoubleRemainder), GetSignature(BinaryOperatorKind.LiftedDecimalRemainder), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntLeftShift), GetSignature(BinaryOperatorKind.UIntLeftShift), GetSignature(BinaryOperatorKind.LongLeftShift), GetSignature(BinaryOperatorKind.ULongLeftShift), GetSignature(BinaryOperatorKind.LiftedIntLeftShift), GetSignature(BinaryOperatorKind.LiftedUIntLeftShift), GetSignature(BinaryOperatorKind.LiftedLongLeftShift), GetSignature(BinaryOperatorKind.LiftedULongLeftShift), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntRightShift), GetSignature(BinaryOperatorKind.UIntRightShift), GetSignature(BinaryOperatorKind.LongRightShift), GetSignature(BinaryOperatorKind.ULongRightShift), GetSignature(BinaryOperatorKind.LiftedIntRightShift), GetSignature(BinaryOperatorKind.LiftedUIntRightShift), GetSignature(BinaryOperatorKind.LiftedLongRightShift), GetSignature(BinaryOperatorKind.LiftedULongRightShift), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntEqual), GetSignature(BinaryOperatorKind.UIntEqual), GetSignature(BinaryOperatorKind.LongEqual), GetSignature(BinaryOperatorKind.ULongEqual), GetSignature(BinaryOperatorKind.FloatEqual), GetSignature(BinaryOperatorKind.DoubleEqual), GetSignature(BinaryOperatorKind.DecimalEqual), GetSignature(BinaryOperatorKind.BoolEqual), GetSignature(BinaryOperatorKind.LiftedIntEqual), GetSignature(BinaryOperatorKind.LiftedUIntEqual), GetSignature(BinaryOperatorKind.LiftedLongEqual), GetSignature(BinaryOperatorKind.LiftedULongEqual), GetSignature(BinaryOperatorKind.LiftedFloatEqual), GetSignature(BinaryOperatorKind.LiftedDoubleEqual), GetSignature(BinaryOperatorKind.LiftedDecimalEqual), GetSignature(BinaryOperatorKind.LiftedBoolEqual), GetSignature(BinaryOperatorKind.ObjectEqual), GetSignature(BinaryOperatorKind.StringEqual), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntNotEqual), GetSignature(BinaryOperatorKind.UIntNotEqual), GetSignature(BinaryOperatorKind.LongNotEqual), GetSignature(BinaryOperatorKind.ULongNotEqual), GetSignature(BinaryOperatorKind.FloatNotEqual), GetSignature(BinaryOperatorKind.DoubleNotEqual), GetSignature(BinaryOperatorKind.DecimalNotEqual), GetSignature(BinaryOperatorKind.BoolNotEqual), GetSignature(BinaryOperatorKind.LiftedIntNotEqual), GetSignature(BinaryOperatorKind.LiftedUIntNotEqual), GetSignature(BinaryOperatorKind.LiftedLongNotEqual), GetSignature(BinaryOperatorKind.LiftedULongNotEqual), GetSignature(BinaryOperatorKind.LiftedFloatNotEqual), GetSignature(BinaryOperatorKind.LiftedDoubleNotEqual), GetSignature(BinaryOperatorKind.LiftedDecimalNotEqual), GetSignature(BinaryOperatorKind.LiftedBoolNotEqual), GetSignature(BinaryOperatorKind.ObjectNotEqual), GetSignature(BinaryOperatorKind.StringNotEqual), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntGreaterThan), GetSignature(BinaryOperatorKind.UIntGreaterThan), GetSignature(BinaryOperatorKind.LongGreaterThan), GetSignature(BinaryOperatorKind.ULongGreaterThan), GetSignature(BinaryOperatorKind.FloatGreaterThan), GetSignature(BinaryOperatorKind.DoubleGreaterThan), GetSignature(BinaryOperatorKind.DecimalGreaterThan), GetSignature(BinaryOperatorKind.LiftedIntGreaterThan), GetSignature(BinaryOperatorKind.LiftedUIntGreaterThan), GetSignature(BinaryOperatorKind.LiftedLongGreaterThan), GetSignature(BinaryOperatorKind.LiftedULongGreaterThan), GetSignature(BinaryOperatorKind.LiftedFloatGreaterThan), GetSignature(BinaryOperatorKind.LiftedDoubleGreaterThan), GetSignature(BinaryOperatorKind.LiftedDecimalGreaterThan), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntLessThan), GetSignature(BinaryOperatorKind.UIntLessThan), GetSignature(BinaryOperatorKind.LongLessThan), GetSignature(BinaryOperatorKind.ULongLessThan), GetSignature(BinaryOperatorKind.FloatLessThan), GetSignature(BinaryOperatorKind.DoubleLessThan), GetSignature(BinaryOperatorKind.DecimalLessThan), GetSignature(BinaryOperatorKind.LiftedIntLessThan), GetSignature(BinaryOperatorKind.LiftedUIntLessThan), GetSignature(BinaryOperatorKind.LiftedLongLessThan), GetSignature(BinaryOperatorKind.LiftedULongLessThan), GetSignature(BinaryOperatorKind.LiftedFloatLessThan), GetSignature(BinaryOperatorKind.LiftedDoubleLessThan), GetSignature(BinaryOperatorKind.LiftedDecimalLessThan), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntGreaterThanOrEqual), GetSignature(BinaryOperatorKind.UIntGreaterThanOrEqual), GetSignature(BinaryOperatorKind.LongGreaterThanOrEqual), GetSignature(BinaryOperatorKind.ULongGreaterThanOrEqual), GetSignature(BinaryOperatorKind.FloatGreaterThanOrEqual), GetSignature(BinaryOperatorKind.DoubleGreaterThanOrEqual), GetSignature(BinaryOperatorKind.DecimalGreaterThanOrEqual), GetSignature(BinaryOperatorKind.LiftedIntGreaterThanOrEqual), GetSignature(BinaryOperatorKind.LiftedUIntGreaterThanOrEqual), GetSignature(BinaryOperatorKind.LiftedLongGreaterThanOrEqual), GetSignature(BinaryOperatorKind.LiftedULongGreaterThanOrEqual), GetSignature(BinaryOperatorKind.LiftedFloatGreaterThanOrEqual), GetSignature(BinaryOperatorKind.LiftedDoubleGreaterThanOrEqual), GetSignature(BinaryOperatorKind.LiftedDecimalGreaterThanOrEqual), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntLessThanOrEqual), GetSignature(BinaryOperatorKind.UIntLessThanOrEqual), GetSignature(BinaryOperatorKind.LongLessThanOrEqual), GetSignature(BinaryOperatorKind.ULongLessThanOrEqual), GetSignature(BinaryOperatorKind.FloatLessThanOrEqual), GetSignature(BinaryOperatorKind.DoubleLessThanOrEqual), GetSignature(BinaryOperatorKind.DecimalLessThanOrEqual), GetSignature(BinaryOperatorKind.LiftedIntLessThanOrEqual), GetSignature(BinaryOperatorKind.LiftedUIntLessThanOrEqual), GetSignature(BinaryOperatorKind.LiftedLongLessThanOrEqual), GetSignature(BinaryOperatorKind.LiftedULongLessThanOrEqual), GetSignature(BinaryOperatorKind.LiftedFloatLessThanOrEqual), GetSignature(BinaryOperatorKind.LiftedDoubleLessThanOrEqual), GetSignature(BinaryOperatorKind.LiftedDecimalLessThanOrEqual), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntAnd), GetSignature(BinaryOperatorKind.UIntAnd), GetSignature(BinaryOperatorKind.LongAnd), GetSignature(BinaryOperatorKind.ULongAnd), GetSignature(BinaryOperatorKind.BoolAnd), GetSignature(BinaryOperatorKind.LiftedIntAnd), GetSignature(BinaryOperatorKind.LiftedUIntAnd), GetSignature(BinaryOperatorKind.LiftedLongAnd), GetSignature(BinaryOperatorKind.LiftedULongAnd), GetSignature(BinaryOperatorKind.LiftedBoolAnd), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntXor), GetSignature(BinaryOperatorKind.UIntXor), GetSignature(BinaryOperatorKind.LongXor), GetSignature(BinaryOperatorKind.ULongXor), GetSignature(BinaryOperatorKind.BoolXor), GetSignature(BinaryOperatorKind.LiftedIntXor), GetSignature(BinaryOperatorKind.LiftedUIntXor), GetSignature(BinaryOperatorKind.LiftedLongXor), GetSignature(BinaryOperatorKind.LiftedULongXor), GetSignature(BinaryOperatorKind.LiftedBoolXor), }).AsImmutableOrNull(), (new [] { GetSignature(BinaryOperatorKind.IntOr), GetSignature(BinaryOperatorKind.UIntOr), GetSignature(BinaryOperatorKind.LongOr), GetSignature(BinaryOperatorKind.ULongOr), GetSignature(BinaryOperatorKind.BoolOr), GetSignature(BinaryOperatorKind.LiftedIntOr), GetSignature(BinaryOperatorKind.LiftedUIntOr), GetSignature(BinaryOperatorKind.LiftedLongOr), GetSignature(BinaryOperatorKind.LiftedULongOr), GetSignature(BinaryOperatorKind.LiftedBoolOr), }).AsImmutableOrNull(), }; var allOperators = new[] { nonLogicalOperators, logicalOperators }; Interlocked.CompareExchange(ref builtInOperators, allOperators, null); } operators.AddRange(builtInOperators[kind.IsLogical() ? 1 : 0][kind.OperatorIndex()]); }
private BoundExpression MakeBuiltInIncrementOperator(BoundIncrementOperator node, BoundExpression rewrittenValueToIncrement) { BoundExpression result; // If we have a built-in increment or decrement then things get a bit trickier. Suppose for example we have // a user-defined conversion from X to short and from short to X, but no user-defined increment operator on // X. The increment portion of "++x" is then: (X)(short)((int)(short)x + 1). That is, first x must be // converted to short via an implicit user- defined conversion, then to int via an implicit numeric // conversion, then the addition is performed in integers. The resulting integer is converted back to short, // and then the short is converted to X. // This is the input and output type of the unary increment operator we're going to call. // That is, "short" in the example above. TypeSymbol unaryOperandType = GetUnaryOperatorType(node); // This is the kind of binary operator that we're going to realize the unary operator // as. That is, "int + int --> int" in the example above. BinaryOperatorKind binaryOperatorKind = GetCorrespondingBinaryOperator(node); binaryOperatorKind |= IsIncrement(node) ? BinaryOperatorKind.Addition : BinaryOperatorKind.Subtraction; // The "1" in the example above. ConstantValue constantOne = GetConstantOneForBinOp(binaryOperatorKind); Debug.Assert(constantOne != null); Debug.Assert(constantOne.SpecialType != SpecialType.None); Debug.Assert(binaryOperatorKind.OperandTypes() != 0); // The intput/output type of the binary operand. "int" in the example. TypeSymbol binaryOperandType = compilation.GetSpecialType(constantOne.SpecialType); // 1 BoundExpression boundOne = MakeLiteral( syntax: node.Syntax, constantValue: constantOne, type: binaryOperandType); if (binaryOperatorKind.IsLifted()) { binaryOperandType = compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(binaryOperandType); MethodSymbol ctor = GetNullableMethod(node.Syntax, binaryOperandType, SpecialMember.System_Nullable_T__ctor); boundOne = new BoundObjectCreationExpression(node.Syntax, ctor, boundOne); } // Now we construct the other operand to the binary addition. We start with just plain "x". BoundExpression binaryOperand = rewrittenValueToIncrement; bool @checked = node.OperatorKind.IsChecked(); // If we need to make a conversion from the original operand type to the operand type of the // underlying increment operation, do it now. if (!node.OperandConversion.IsIdentity) { // (short)x binaryOperand = MakeConversion( syntax: node.Syntax, rewrittenOperand: binaryOperand, conversion: node.OperandConversion, rewrittenType: unaryOperandType, @checked: @checked); } // Early-out for pointer increment - we don't need to convert the operands to a common type. if (node.OperatorKind.OperandTypes() == UnaryOperatorKind.Pointer) { Debug.Assert(binaryOperatorKind.OperandTypes() == BinaryOperatorKind.PointerAndInt); Debug.Assert(binaryOperand.Type.IsPointerType()); Debug.Assert(boundOne.Type.SpecialType == SpecialType.System_Int32); return(MakeBinaryOperator(node.Syntax, binaryOperatorKind, binaryOperand, boundOne, binaryOperand.Type, method: null)); } // If we need to make a conversion from the unary operator type to the binary operator type, // do it now. // (int)(short)x binaryOperand = MakeConversion(binaryOperand, binaryOperandType, @checked); // Perform the addition. // (int)(short)x + 1 BoundExpression binOp; if (unaryOperandType.SpecialType == SpecialType.System_Decimal) { binOp = MakeDecimalIncDecOperator(node.Syntax, binaryOperatorKind, binaryOperand); } else if (unaryOperandType.IsNullableType() && unaryOperandType.GetNullableUnderlyingType().SpecialType == SpecialType.System_Decimal) { binOp = MakeLiftedDecimalIncDecOperator(node.Syntax, binaryOperatorKind, binaryOperand); } else { binOp = MakeBinaryOperator(node.Syntax, binaryOperatorKind, binaryOperand, boundOne, binaryOperandType, method: null); } // Generate the conversion back to the type of the unary operator. // (short)((int)(short)x + 1) result = MakeConversion(binOp, unaryOperandType, @checked); return(result); }
/// <summary> /// Produces a chain of equality (or inequality) checks combined logically with AND (or OR) /// </summary> private BoundExpression RewriteNonNullableNestedTupleOperators(TupleBinaryOperatorInfo.Multiple operators, BoundExpression left, BoundExpression right, TypeSymbol type, ArrayBuilder <LocalSymbol> temps, ArrayBuilder <BoundExpression> effects, BinaryOperatorKind operatorKind) { ImmutableArray <TupleBinaryOperatorInfo> nestedOperators = operators.Operators; BoundExpression currentResult = null; for (int i = 0; i < nestedOperators.Length; i++) { BoundExpression leftElement = GetTuplePart(left, i); BoundExpression rightElement = GetTuplePart(right, i); BoundExpression nextLogicalOperand = RewriteTupleOperator(nestedOperators[i], leftElement, rightElement, type, temps, operatorKind); if (currentResult is null) { currentResult = nextLogicalOperand; } else { var logicalOperator = operatorKind == BinaryOperatorKind.Equal ? BinaryOperatorKind.LogicalBoolAnd : BinaryOperatorKind.LogicalBoolOr; currentResult = _factory.Binary(logicalOperator, type, currentResult, nextLogicalOperand); } } return(currentResult); }
/// <summary> /// Produce an element-wise comparison and logic to ensure the result is a bool type. /// /// If an element-wise comparison doesn't return bool, then: /// - if it is dynamic, we'll do `!(comparisonResult.false)` or `comparisonResult.true` /// - if it implicitly converts to bool, we'll just do the conversion /// - otherwise, we'll do `!(comparisonResult.false)` or `comparisonResult.true` (as we'd do for `if` or `while`) /// </summary> private BoundExpression RewriteTupleSingleOperator(TupleBinaryOperatorInfo.Single single, BoundExpression left, BoundExpression right, TypeSymbol boolType, BinaryOperatorKind operatorKind) { if (single.Kind.IsDynamic()) { // Produce // !((left == right).op_false) // (left != right).op_true BoundExpression dynamicResult = _dynamicFactory.MakeDynamicBinaryOperator(single.Kind, left, right, isCompoundAssignment: false, _compilation.DynamicType).ToExpression(); if (operatorKind == BinaryOperatorKind.Equal) { return(_factory.Not(MakeUnaryOperator(UnaryOperatorKind.DynamicFalse, left.Syntax, method: null, dynamicResult, boolType))); } else { return(MakeUnaryOperator(UnaryOperatorKind.DynamicTrue, left.Syntax, method: null, dynamicResult, boolType)); } } if (left.IsLiteralNull() && right.IsLiteralNull()) { // For `null == null` this is special-cased during initial binding return(new BoundLiteral(left.Syntax, ConstantValue.Create(operatorKind == BinaryOperatorKind.Equal), boolType)); } // We leave both operands in nullable-null conversions unconverted, MakeBinaryOperator has special for null-literal bool isNullableNullConversion = single.Kind.OperandTypes() == BinaryOperatorKind.NullableNull; BoundExpression convertedLeft = isNullableNullConversion ? left : MakeConversionNode(left.Syntax, left, single.LeftConversion, single.LeftConvertedTypeOpt, @checked: false); BoundExpression convertedRight = isNullableNullConversion ? right : MakeConversionNode(right.Syntax, right, single.RightConversion, single.RightConvertedTypeOpt, @checked: false); BoundExpression binary = MakeBinaryOperator(_factory.Syntax, single.Kind, convertedLeft, convertedRight, single.MethodSymbolOpt?.ReturnType ?? boolType, single.MethodSymbolOpt); UnaryOperatorSignature boolOperator = single.BoolOperator; Conversion boolConversion = single.ConversionForBool; BoundExpression result; if (boolOperator.Kind != UnaryOperatorKind.Error) { // Produce // !((left == right).op_false) // (left != right).op_true BoundExpression convertedBinary = MakeConversionNode(_factory.Syntax, binary, boolConversion, boolOperator.OperandType, @checked: false); Debug.Assert(boolOperator.ReturnType.SpecialType == SpecialType.System_Boolean); result = MakeUnaryOperator(boolOperator.Kind, binary.Syntax, boolOperator.Method, convertedBinary, boolType); if (operatorKind == BinaryOperatorKind.Equal) { result = _factory.Not(result); } } else if (!boolConversion.IsIdentity) { // Produce // (bool)(left == right) // (bool)(left != right) result = MakeConversionNode(_factory.Syntax, binary, boolConversion, boolType, @checked: false); } else { result = binary; } return(result); }
public static bool IsLogical(this BinaryOperatorKind kind) { return(0 != (kind & BinaryOperatorKind.Logical)); }
public static bool IsDynamic(this BinaryOperatorKind kind) { return(kind.OperandTypes() == BinaryOperatorKind.Dynamic); }
private string BuildFromPropertyNode(SingleValuePropertyAccessNode left, SingleValueNode right, BinaryOperatorKind operatorKind) { string result = string.Empty; if (right is ConstantNode) { result = BuildSingleClause(left, right as ConstantNode, operatorKind); } var rightSource = (right as ConvertNode)?.Source; if (rightSource is ConstantNode) { result = BuildSingleClause(left, rightSource as ConstantNode, operatorKind); } return(result); }
private string BuildSingleClause(SingleValuePropertyAccessNode propertyNode, ConstantNode valueNode, BinaryOperatorKind operatorKind) { string operatorString = string.Empty; switch (operatorKind) { case BinaryOperatorKind.Equal: operatorString = "="; break; case BinaryOperatorKind.NotEqual: operatorString = "!="; break; case BinaryOperatorKind.GreaterThan: operatorString = ">"; break; case BinaryOperatorKind.GreaterThanOrEqual: operatorString = ">="; break; case BinaryOperatorKind.LessThan: operatorString = "<"; break; case BinaryOperatorKind.LessThanOrEqual: operatorString = "<="; break; } string valueString = valueNode.Value?.ToString() ?? "null"; if (valueNode.Value == null) { if (operatorKind == BinaryOperatorKind.Equal) { return($"({propertyNode.Property.Name} IS NULL)"); } if (operatorKind == BinaryOperatorKind.NotEqual) { return($"({propertyNode.Property.Name} IS NOT NULL)"); } } return($"({propertyNode.Property.Name} {operatorString} {valueString})"); }
private static IEnumerable <BinaryOperatorSignature> GetBuiltInSignatures(BinaryOperatorKind kind) { switch (kind) { case BinaryOperatorKind.Multiply: return(BuiltInMultiplySignatures); case BinaryOperatorKind.Divide: return(BuiltInDivideSignatures); case BinaryOperatorKind.Modulo: return(BuiltInModulusSignatures); case BinaryOperatorKind.Add: return(BuiltInAddSignatures); case BinaryOperatorKind.Subtract: return(BuiltInSubSignatures); case BinaryOperatorKind.Equal: return(BuiltInEqualSignatures); case BinaryOperatorKind.NotEqual: return(BuiltInNotEqualSignatures); case BinaryOperatorKind.Less: return(BuiltInLessSignatures); case BinaryOperatorKind.LessEqual: return(BuiltInLessOrEqualSignatures); case BinaryOperatorKind.Greater: return(BuiltInGreaterSignatures); case BinaryOperatorKind.GreaterEqual: return(BuiltInGreaterOrEqualSignatures); case BinaryOperatorKind.BitwiseXor: return(BuiltInBitXorSignatures); case BinaryOperatorKind.BitwiseAnd: return(BuiltInBitAndSignatures); case BinaryOperatorKind.BitwiseOr: return(BuiltInBitOrSignatures); case BinaryOperatorKind.LeftShift: return(BuiltInLeftShiftSignatures); case BinaryOperatorKind.RightShift: return(BuiltInRightShiftSignatures); case BinaryOperatorKind.LogicalAnd: return(BuiltInLogicalAndSignatures); case BinaryOperatorKind.LogicalOr: return(BuiltInLogicalOrSignatures); default: throw new ArgumentOutOfRangeException(nameof(kind), kind.ToString()); } }
private static OverloadResolutionResult <BinaryOperatorSignature> ResolveOverloads(BinaryOperatorKind kind, TypeSymbol leftOperandType, TypeSymbol rightOperandType) { var builtInSignatures = GetBuiltInSignatures(kind); if (BothTypesBuiltIn(leftOperandType, rightOperandType)) { return(OverloadResolution.Perform(builtInSignatures, leftOperandType, rightOperandType)); } return(OverloadResolutionResult <BinaryOperatorSignature> .None); }
public static OverloadResolutionResult <BinaryOperatorSignature> Resolve(BinaryOperatorKind kind, TypeSymbol leftOperandType, TypeSymbol rightOperandType) { return(ResolveOverloads(kind, leftOperandType, rightOperandType)); }
private QueryNode ParsePropertyAccessNode() { QueryNode result = null; QueryNode leftNode = null; BinaryOperatorKind operatorKind = BinaryOperatorKind.None; QueryNode rightNode = null; while (this.tokens.Count > 0) { var token = this.tokens.Dequeue(); switch (token.TokenType) { case TokenType.BinaryOperator: if (operatorKind != BinaryOperatorKind.None) { result = new BinaryOperatorNode(leftNode, operatorKind, rightNode); leftNode = null; rightNode = null; } operatorKind = token.Value.ToBinaryOperatorKind(); break; case TokenType.OpenParentheses: this.groupingDepth++; break; case TokenType.CloseParentheses: this.groupingDepth--; break; case TokenType.FunctionName: if (leftNode == null) { leftNode = new FunctionCallNode(token.Value); } else if (rightNode == null) { rightNode = new FunctionCallNode(token.Value); } break; case TokenType.PropertyName: var propertyAccessNode = new PropertyAccessNode(this.model.GetProperty(token.Value)); if (leftNode == null) { leftNode = propertyAccessNode; } else if (rightNode == null) { rightNode = propertyAccessNode; } break; case TokenType.Date: case TokenType.DateTimeOffset: case TokenType.Decimal: case TokenType.Double: case TokenType.Duration: case TokenType.Enum: case TokenType.False: case TokenType.Guid: case TokenType.Integer: case TokenType.Null: case TokenType.Single: case TokenType.String: case TokenType.TimeOfDay: case TokenType.True: rightNode = ConstantNodeParser.ParseConstantNode(token); break; } } result = result == null ? new BinaryOperatorNode(leftNode, operatorKind, rightNode) : new BinaryOperatorNode(result, operatorKind, leftNode ?? rightNode); return(result); }
public BinaryOperatorSearcherItemData(BinaryOperatorKind kind) { Kind = kind; }
public static bool IsLifted(this BinaryOperatorKind kind) { return(0 != (kind & BinaryOperatorKind.Lifted)); }
private BoundExpression RewriteLiftedBinaryOperator(CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type, MethodSymbol method) { var conditionalLeft = loweredLeft as BoundLoweredConditionalAccess; // NOTE: we could in theory handle side-effecting loweredRight here too // by including it as a part of whenNull, but there is a concern // that it can lead to code duplication var optimize = conditionalLeft != null && !ReadIsSideeffecting(loweredRight) && (conditionalLeft.WhenNullOpt == null || conditionalLeft.WhenNullOpt.IsDefaultValue()); if (optimize) { loweredLeft = conditionalLeft.WhenNotNull; } var result = operatorKind.IsComparison() ? operatorKind.IsUserDefined() ? LowerLiftedUserDefinedComparisonOperator(syntax, operatorKind, loweredLeft, loweredRight, method) : LowerLiftedBuiltInComparisonOperator(syntax, operatorKind, loweredLeft, loweredRight) : LowerLiftedBinaryArithmeticOperator(syntax, operatorKind, loweredLeft, loweredRight, type, method); if (optimize) { BoundExpression whenNullOpt = null; // for all operators null-in means null-out // except for the Equal/NotEqual since null == null ==> true if (operatorKind.Operator() == BinaryOperatorKind.NotEqual || operatorKind.Operator() == BinaryOperatorKind.Equal) { whenNullOpt = RewriteLiftedBinaryOperator(syntax, operatorKind, _factory.Default(loweredLeft.Type), loweredRight, type, method); } result = conditionalLeft.Update( conditionalLeft.Receiver, conditionalLeft.HasValueMethodOpt, whenNotNull: result, whenNullOpt: whenNullOpt, id: conditionalLeft.Id, type: result.Type ); } return result; }
public static bool IsChecked(this BinaryOperatorKind kind) { return(0 != (kind & BinaryOperatorKind.Checked)); }
private BoundExpression LowerUserDefinedBinaryOperator( CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type, MethodSymbol method) { Debug.Assert(!operatorKind.IsLogical()); if (operatorKind.IsLifted()) { return RewriteLiftedBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, type, method); } // Otherwise, nothing special here. Debug.Assert((object)method != null); Debug.Assert(method.ReturnType == type); return BoundCall.Synthesized(syntax, null, method, loweredLeft, loweredRight); }
private BoundExpression RewriteTupleOperator(TupleBinaryOperatorInfo @operator, BoundExpression left, BoundExpression right, TypeSymbol boolType, ArrayBuilder <LocalSymbol> temps, BinaryOperatorKind operatorKind) { switch (@operator.InfoKind) { case TupleBinaryOperatorInfoKind.Multiple: return(RewriteTupleNestedOperators((TupleBinaryOperatorInfo.Multiple)@operator, left, right, boolType, temps, operatorKind)); case TupleBinaryOperatorInfoKind.Single: return(RewriteTupleSingleOperator((TupleBinaryOperatorInfo.Single)@operator, left, right, boolType, operatorKind)); case TupleBinaryOperatorInfoKind.NullNull: var nullnull = (TupleBinaryOperatorInfo.NullNull)@operator; return(new BoundLiteral(left.Syntax, ConstantValue.Create(nullnull.Kind == BinaryOperatorKind.Equal), boolType)); default: throw ExceptionUtilities.UnexpectedValue(@operator.InfoKind); } }
private BoundExpression LowerLiftedBuiltInComparisonOperator( CSharpSyntaxNode syntax, BinaryOperatorKind kind, BoundExpression loweredLeft, BoundExpression loweredRight) { // SPEC: For the equality operators == != : // SPEC: The lifted operator considers two null values equal and a null value unequal to // SPEC: any non-null value. If both operands are non-null the lifted operator unwraps // SPEC: the operands and applies the underlying operator to produce the bool result. // SPEC: // SPEC: For the relational operators < > <= >= : // SPEC: The lifted operator produces the value false if one or both operands // SPEC: are null. Otherwise the lifted operator unwraps the operands and // SPEC: applies the underlying operator to produce the bool result. // Note that this means that x == y is true but x <= y is false if both are null. // x <= y is not the same as (x < y) || (x == y). // Start with some simple optimizations for cases like one side being null. BoundExpression optimized = TrivialLiftedComparisonOperatorOptimizations(syntax, kind, loweredLeft, loweredRight, null); if (optimized != null) { return optimized; } // We rewrite x == y as // // tempx = x; // tempy = y; // result = tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ? // tempx.HasValue == tempy.HasValue : // false; // // and x != y as // // tempx = x; // tempy = y; // result = tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ? // tempx.HasValue != tempy.HasValue : // true; // // Otherwise, we rewrite x OP y as // // tempx = x; // tempy = y; // result = tempx.GetValueOrDefault() OP tempy.GetValueOrDefault() ? // tempx.HasValue & tempy.HasValue : // false; // // Note that there is no reason to generate "&&" over "&"; the cost of // the added code for the conditional branch would be about the same as simply doing // the bitwise & in the first place. // // We have not yet optimized the case where we have a known-not-null value on one side, // and an unknown value on the other. In those cases we will still generate a temp, but // we will not generate the call to the unnecessary nullable ctor or to GetValueOrDefault. // Rather, we will generate the value's temp instead of a call to GetValueOrDefault, and generate // literal true for HasValue. The tree construction methods we call will use those constants // to eliminate unnecessary branches. BoundExpression xNonNull = NullableAlwaysHasValue(loweredLeft); BoundExpression yNonNull = NullableAlwaysHasValue(loweredRight); BoundAssignmentOperator tempAssignmentX; BoundLocal boundTempX = _factory.StoreToTemp(xNonNull ?? loweredLeft, out tempAssignmentX); BoundAssignmentOperator tempAssignmentY; BoundLocal boundTempY = _factory.StoreToTemp(yNonNull ?? loweredRight, out tempAssignmentY); BoundExpression callX_GetValueOrDefault = MakeOptimizedGetValueOrDefault(syntax, boundTempX); BoundExpression callY_GetValueOrDefault = MakeOptimizedGetValueOrDefault(syntax, boundTempY); BoundExpression callX_HasValue = MakeOptimizedHasValue(syntax, boundTempX); BoundExpression callY_HasValue = MakeOptimizedHasValue(syntax, boundTempY); // tempx.GetValueOrDefault() == tempy.GetValueOrDefault() BinaryOperatorKind operatorKind = kind.Operator(); BinaryOperatorKind conditionOperator = operatorKind == BinaryOperatorKind.NotEqual ? BinaryOperatorKind.Equal : operatorKind; TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean); BoundExpression condition = MakeBinaryOperator( syntax: syntax, operatorKind: conditionOperator.WithType(kind.OperandTypes()), loweredLeft: callX_GetValueOrDefault, loweredRight: callY_GetValueOrDefault, type: boolType, method: null); BinaryOperatorKind consequenceOperator; switch (operatorKind) { case BinaryOperatorKind.Equal: consequenceOperator = BinaryOperatorKind.BoolEqual; break; case BinaryOperatorKind.NotEqual: consequenceOperator = BinaryOperatorKind.BoolNotEqual; break; default: consequenceOperator = BinaryOperatorKind.BoolAnd; break; } // tempx.HasValue == tempy.HasValue BoundExpression consequence = MakeBinaryOperator( syntax: syntax, operatorKind: consequenceOperator, loweredLeft: callX_HasValue, loweredRight: callY_HasValue, type: boolType, method: null); // false BoundExpression alternative = this.MakeBooleanConstant(syntax, operatorKind == BinaryOperatorKind.NotEqual); // tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ? // tempx.HasValue == tempy.HasValue : // false; BoundExpression conditionalExpression = RewriteConditionalOperator( syntax: syntax, rewrittenCondition: condition, rewrittenConsequence: consequence, rewrittenAlternative: alternative, constantValueOpt: null, rewrittenType: boolType); // tempx = x; // tempy = y; // result = tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ? // tempx.HasValue == tempy.HasValue : // false; return new BoundSequence( syntax: syntax, locals: ImmutableArray.Create<LocalSymbol>(boundTempX.LocalSymbol, boundTempY.LocalSymbol), sideEffects: ImmutableArray.Create<BoundExpression>(tempAssignmentX, tempAssignmentY), value: conditionalExpression, type: boolType); }
private BoundExpression MakeLiftedDecimalIncDecOperator(CSharpSyntaxNode syntax, BinaryOperatorKind oper, BoundExpression operand) { Debug.Assert(operand.Type.IsNullableType() && operand.Type.GetNullableUnderlyingType().SpecialType == SpecialType.System_Decimal); // This method assumes that operand is already a temporary and so there is no need to copy it again. MethodSymbol method = GetDecimalIncDecOperator(oper); MethodSymbol hasValue = GetNullableMethod(syntax, operand.Type, SpecialMember.System_Nullable_T_get_HasValue); MethodSymbol getValueOrDefault = GetNullableMethod(syntax, operand.Type, SpecialMember.System_Nullable_T_GetValueOrDefault); MethodSymbol ctor = GetNullableMethod(syntax, operand.Type, SpecialMember.System_Nullable_T__ctor); // x.HasValue BoundExpression condition = BoundCall.Synthesized(syntax, operand, hasValue); // x.GetValueOrDefault() BoundExpression getValueCall = BoundCall.Synthesized(syntax, operand, getValueOrDefault); // op_Inc(x.GetValueOrDefault()) BoundExpression methodCall = BoundCall.Synthesized(syntax, null, method, getValueCall); // new decimal?(op_Inc(x.GetValueOrDefault())) BoundExpression consequence = new BoundObjectCreationExpression(syntax, ctor, methodCall); // default(decimal?) BoundExpression alternative = new BoundDefaultOperator(syntax, null, operand.Type); // x.HasValue ? new decimal?(op_Inc(x.GetValueOrDefault())) : default(decimal?) return(RewriteConditionalOperator(syntax, condition, consequence, alternative, ConstantValue.NotAvailable, operand.Type)); }
/// <summary>Checks that the operands (possibly promoted) are valid for the specified operation.</summary> /// <param name="operatorKind">The operator kind to promote the operand types for.</param> /// <param name="leftNode">The left operand node.</param> /// <param name="rightNode">The right operand node.</param> /// <param name="left">The left operand type after promotion.</param> /// <param name="right">The right operand type after promotion.</param> /// <returns>True if a valid function signature was found that matches the given types after any necessary promotions are made. /// False if there is no binary operators </returns> internal static bool PromoteOperandTypes(BinaryOperatorKind operatorKind, SingleValueNode leftNode, SingleValueNode rightNode, out IEdmTypeReference left, out IEdmTypeReference right) { left = leftNode.TypeReference; right = rightNode.TypeReference; // The types for the operands can be null // if they (a) represent the null literal or (b) represent an open type/property. // If both argument types are null we lack type information on both sides and cannot promote arguments. if (left == null && right == null) { // if we find null literals or open properties on both sides we cannot promote; the result type will also be null return true; } if (operatorKind == BinaryOperatorKind.NotEqual || operatorKind == BinaryOperatorKind.Equal) { if (TryHandleEqualityOperatorForEntityOrComplexTypes(ref left, ref right)) { return true; } // enum and spatial type support equality operator for null operand: if ((left == null) && (right != null) && (right.IsEnum() || right is IEdmSpatialTypeReference)) { left = right; return true; } if ((right == null) && (left != null) && (left.IsEnum() || left is IEdmSpatialTypeReference)) { right = left; return true; } } // enum support, check type full names if (left != null && right != null && left.IsEnum() && right.IsEnum()) { return string.Equals(left.FullName(), right.FullName(), StringComparison.Ordinal); } // type definition support, treat type definitions as their underlying types. if (left != null && left.IsTypeDefinition()) { left = left.AsPrimitive(); } if (right != null && right.IsTypeDefinition()) { right = right.AsPrimitive(); } // Except for above, binary operators are only supported on primitive types if (left != null && !left.IsODataPrimitiveTypeKind() || right != null && !right.IsODataPrimitiveTypeKind()) { return false; } // The following will match primitive argument types to build in function signatures, choosing the best one possible. FunctionSignature[] signatures = GetFunctionSignatures(operatorKind); SingleValueNode[] argumentNodes = new SingleValueNode[] { leftNode, rightNode }; IEdmTypeReference[] argumentTypes = new IEdmTypeReference[] { left, right }; bool success = FindBestSignature(signatures, argumentNodes, argumentTypes) == 1; if (success) { left = argumentTypes[0]; right = argumentTypes[1]; if (left == null) { left = right; } else if (right == null) { right = left; } } return success; }
private BoundExpression RewriteTupleNestedOperators(TupleBinaryOperatorInfo.Multiple operators, BoundExpression left, BoundExpression right, TypeSymbol boolType, ArrayBuilder <LocalSymbol> temps, BinaryOperatorKind operatorKind) { left = Binder.GiveTupleTypeToDefaultLiteralIfNeeded(left, right.Type); right = Binder.GiveTupleTypeToDefaultLiteralIfNeeded(right, left.Type); // If either left or right is nullable, produce: // // // outer sequence // leftHasValue = left.HasValue; (or true if !leftNullable) // leftHasValue == right.HasValue (or true if !rightNullable) // ? leftHasValue ? ... inner sequence ... : true/false // : false/true // // where inner sequence is: // leftValue = left.GetValueOrDefault(); (or left if !leftNullable) // rightValue = right.GetValueOrDefault(); (or right if !rightNullable) // ... logical expression using leftValue and rightValue ... // // and true/false and false/true depend on operatorKind (== vs. !=) // // But if neither is nullable, then just produce the inner sequence. // // Note: all the temps are created in a single bucket (rather than different scopes of applicability) for simplicity var outerEffects = ArrayBuilder <BoundExpression> .GetInstance(); var innerEffects = ArrayBuilder <BoundExpression> .GetInstance(); BoundExpression leftHasValue, leftValue; bool isLeftNullable; MakeNullableParts(left, temps, innerEffects, outerEffects, saveHasValue: true, out leftHasValue, out leftValue, out isLeftNullable); BoundExpression rightHasValue, rightValue; bool isRightNullable; // no need for local for right.HasValue since used once MakeNullableParts(right, temps, innerEffects, outerEffects, saveHasValue: false, out rightHasValue, out rightValue, out isRightNullable); // Produces: // ... logical expression using leftValue and rightValue ... BoundExpression logicalExpression = RewriteNonNullableNestedTupleOperators(operators, leftValue, rightValue, boolType, temps, innerEffects, operatorKind); // Produces: // leftValue = left.GetValueOrDefault(); (or left if !leftNullable) // rightValue = right.GetValueOrDefault(); (or right if !rightNullable) // ... logical expression using leftValue and rightValue ... BoundExpression innerSequence = MakeSequenceOrResultValue(locals: ImmutableArray <LocalSymbol> .Empty, innerEffects.ToImmutableAndFree(), logicalExpression); if (!isLeftNullable && !isRightNullable) { // The outer sequence degenerates when we know that both `leftHasValue` and `rightHasValue` are true return(innerSequence); } bool boolValue = operatorKind == BinaryOperatorKind.Equal; // true/false if (rightHasValue.ConstantValue == ConstantValue.False) { // The outer sequence degenerates when we known that `rightHasValue` is false // Produce: !leftHasValue (or leftHasValue for inequality comparison) return(MakeSequenceOrResultValue(ImmutableArray <LocalSymbol> .Empty, outerEffects.ToImmutableAndFree(), returnValue: boolValue?_factory.Not(leftHasValue) : leftHasValue)); } if (leftHasValue.ConstantValue == ConstantValue.False) { // The outer sequence degenerates when we known that `leftHasValue` is false // Produce: !rightHasValue (or rightHasValue for inequality comparison) return(MakeSequenceOrResultValue(ImmutableArray <LocalSymbol> .Empty, outerEffects.ToImmutableAndFree(), returnValue: boolValue?_factory.Not(rightHasValue) : rightHasValue)); } // outer sequence: // leftHasValue == rightHasValue // ? leftHasValue ? ... inner sequence ... : true/false // : false/true BoundExpression outerSequence = MakeSequenceOrResultValue(ImmutableArray <LocalSymbol> .Empty, outerEffects.ToImmutableAndFree(), _factory.Conditional( _factory.Binary(BinaryOperatorKind.Equal, boolType, leftHasValue, rightHasValue), _factory.Conditional(leftHasValue, innerSequence, MakeBooleanConstant(right.Syntax, boolValue), boolType), MakeBooleanConstant(right.Syntax, !boolValue), boolType)); return(outerSequence); }
public static Expression <Func <TModel, bool> > FilterObjectSet(SingleValuePropertyAccessNode rule, ConstantNode constant, BinaryOperatorKind kind, string name = "model") { Type type = typeof(TModel); var par = Expression.Parameter(type, name); Type fieldPropertyType; Expression fieldPropertyExpression; FieldInfo fieldInfo = type.GetField(rule.Property.Name); if (fieldInfo == null) { PropertyInfo propertyInfo = type.GetProperty(rule.Property.Name); if (propertyInfo == null) { throw new Exception(); } fieldPropertyType = propertyInfo.PropertyType; fieldPropertyExpression = Expression.Property(par, propertyInfo); } else { fieldPropertyType = fieldInfo.FieldType; fieldPropertyExpression = Expression.Field(par, fieldInfo); } object data2 = null; if (fieldPropertyType.IsGenericType && fieldPropertyType.GetGenericTypeDefinition() == typeof(Nullable <>)) { System.ComponentModel.TypeConverter conv = System.ComponentModel.TypeDescriptor.GetConverter(fieldPropertyType); data2 = conv.ConvertFrom(constant.LiteralText); //data2 = Convert.ChangeType(constant.LiteralText, Nullable.GetUnderlyingType()); } else { data2 = Convert.ChangeType(constant.LiteralText, fieldPropertyType); } if (fieldPropertyType == typeof(string)) { data2 = data2.ToString().Replace("'", ""); } BinaryExpression eq = null; switch (kind) { case BinaryOperatorKind.Or: eq = Expression.Or(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.And: eq = Expression.And(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.Equal: eq = Expression.Equal(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.NotEqual: eq = Expression.NotEqual(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.GreaterThan: eq = Expression.GreaterThan(fieldPropertyExpression, Expression.Constant(data2)); break; case BinaryOperatorKind.GreaterThanOrEqual: eq = Expression.GreaterThanOrEqual(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.LessThan: eq = Expression.LessThan(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.LessThanOrEqual: eq = Expression.LessThanOrEqual(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.Add: eq = Expression.Add(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.Subtract: eq = Expression.Subtract(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.Multiply: eq = Expression.Multiply(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.Divide: eq = Expression.Divide(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.Modulo: eq = Expression.Modulo(fieldPropertyExpression, Expression.Constant(data2, fieldPropertyType)); break; case BinaryOperatorKind.Has: break; } ; return(Expression.Lambda <Func <TModel, bool> >(eq, par)); }
private BoundExpression MakeNullCheck(CSharpSyntaxNode syntax, BoundExpression rewrittenExpr, BinaryOperatorKind operatorKind) { Debug.Assert((operatorKind == BinaryOperatorKind.Equal) || (operatorKind == BinaryOperatorKind.NotEqual) || (operatorKind == BinaryOperatorKind.NullableNullEqual) || (operatorKind == BinaryOperatorKind.NullableNullNotEqual)); TypeSymbol exprType = rewrittenExpr.Type; // Don't even call this method if the expression isn't nullable. Debug.Assert( (object)exprType == null || exprType.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T || !exprType.IsValueType || exprType.IsPointerType()); TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean); // Fold compile-time comparisons. if (rewrittenExpr.ConstantValue != null) { switch (operatorKind) { case BinaryOperatorKind.Equal: return MakeLiteral(syntax, ConstantValue.Create(rewrittenExpr.ConstantValue.IsNull, ConstantValueTypeDiscriminator.Boolean), boolType); case BinaryOperatorKind.NotEqual: return MakeLiteral(syntax, ConstantValue.Create(!rewrittenExpr.ConstantValue.IsNull, ConstantValueTypeDiscriminator.Boolean), boolType); } } TypeSymbol objectType = _compilation.GetSpecialType(SpecialType.System_Object); if ((object)exprType != null) { if (exprType.Kind == SymbolKind.TypeParameter) { // Box type parameters. rewrittenExpr = MakeConversionNode(syntax, rewrittenExpr, Conversion.Boxing, objectType, @checked: false); } else if (exprType.IsNullableType()) { operatorKind |= BinaryOperatorKind.NullableNull; } } return MakeBinaryOperator( syntax, operatorKind, rewrittenExpr, MakeLiteral(syntax, ConstantValue.Null, objectType), boolType, null); }
private void CheckForBitwiseOrSignExtend(BoundExpression node, BinaryOperatorKind operatorKind, BoundExpression leftOperand, BoundExpression rightOperand) { // We wish to give a warning for situations where an unexpected sign extension wipes // out some bits. For example: // // int x = 0x0ABC0000; // short y = -2; // 0xFFFE // int z = x | y; // // The user might naively expect the result to be 0x0ABCFFFE. But the short is sign-extended // when it is converted to int before the bitwise or, so this is in fact the same as: // // int x = 0x0ABC0000; // short y = -2; // 0xFFFE // int ytemp = y; // 0xFFFFFFFE // int z = x | ytemp; // // Which gives 0xFFFFFFFE, not 0x0ABCFFFE. // // However, we wish to suppress the warning if: // // * The sign extension is "expected" -- for instance, because there was an explicit cast // from short to int: "int z = x | (int)y;" should not produce the warning. // Note that "uint z = (uint)x | (uint)y;" should still produce the warning because // the user might not realize that converting y to uint does a sign extension. // // * There is the same amount of sign extension on both sides. For example, when // doing "short | sbyte", both sides are sign extended. The left creates two FF bytes // and the right creates three, so we are potentially wiping out information from the // left side. But "short | short" adds two FF bytes on both sides, so no information is lost. // // The native compiler also suppresses this warning in a bizarre and inconsistent way. If // the side whose bits are going to be wiped out by sign extension is a *constant*, then the // warning is suppressed *if the constant, when converted to a signed long, fits into the // range of the type that is being sign-extended.* // // Consider the effects of this rule: // // (uint)0xFFFF0000 | y -- gives the warning because 0xFFFF0000 as a long is not in the range of a short, // *even though the result will not be affected by the sign extension*. // (ulong)0xFFFFFFFFFFFFFFFF | y -- suppresses the warning, because 0xFFFFFFFFFFFFFFFF as a signed long fits into a short. // (int)0x0000ABCD | y -- suppresses the warning, even though the 0000 is going to be wiped out by the sign extension. // // It seems clear that the intention of the heuristic is to *suppress the warning when the bits being hammered // on are either all zero, or all one.* Therefore that is the heuristic we will *actually* implement here. // switch (operatorKind) { case BinaryOperatorKind.LiftedUIntOr: case BinaryOperatorKind.LiftedIntOr: case BinaryOperatorKind.LiftedULongOr: case BinaryOperatorKind.LiftedLongOr: case BinaryOperatorKind.UIntOr: case BinaryOperatorKind.IntOr: case BinaryOperatorKind.ULongOr: case BinaryOperatorKind.LongOr: break; default: return; } // The native compiler skips this warning if both sides of the operator are constants. // // CONSIDER: Is that sensible? It seems reasonable that if we would warn on int | short // when they are non-constants, or when one is a constant, that we would similarly warn // when both are constants. if (node.ConstantValue != null) { return; } // Start by determining *which bits on each side are going to be unexpectedly turned on*. ulong left = FindSurprisingSignExtensionBits(leftOperand); ulong right = FindSurprisingSignExtensionBits(rightOperand); // If they are all the same then there's no warning to give. if (left == right) { return; } // Suppress the warning if one side is a constant, and either all the unexpected // bits are already off, or all the unexpected bits are already on. ConstantValue constVal = GetConstantValueForBitwiseOrCheck(leftOperand); if (constVal != null) { ulong val = constVal.UInt64Value; if ((val & right) == right || (~val & right) == right) { return; } } constVal = GetConstantValueForBitwiseOrCheck(rightOperand); if (constVal != null) { ulong val = constVal.UInt64Value; if ((val & left) == left || (~val & left) == left) { return; } } // CS0675: Bitwise-or operator used on a sign-extended operand; consider casting to a smaller unsigned type first Error(ErrorCode.WRN_BitwiseOrSignExtend, node); }
public static Expression <Func <T, bool> > CombineExpression <T>(Expression <Func <T, bool> > expr1, Expression <Func <T, bool> > expr2, BinaryOperatorKind kind, string name = "model") { var parameter = Expression.Parameter(typeof(T), name); var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter); var left = leftVisitor.Visit(expr1.Body); var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter); var right = rightVisitor.Visit(expr2.Body); switch (kind) { case BinaryOperatorKind.Or: return(Expression.Lambda <Func <T, bool> >(Expression.Or(left, right), parameter)); case BinaryOperatorKind.And: return(Expression.Lambda <Func <T, bool> >(Expression.AndAlso(left, right), parameter)); case BinaryOperatorKind.Equal: break; case BinaryOperatorKind.NotEqual: break; case BinaryOperatorKind.GreaterThan: break; case BinaryOperatorKind.GreaterThanOrEqual: break; case BinaryOperatorKind.LessThan: break; case BinaryOperatorKind.LessThanOrEqual: break; case BinaryOperatorKind.Add: break; case BinaryOperatorKind.Subtract: break; case BinaryOperatorKind.Multiply: break; case BinaryOperatorKind.Divide: break; case BinaryOperatorKind.Modulo: break; case BinaryOperatorKind.Has: break; default: break; } return(null); }
public static BinaryOperatorKind Operator(this BinaryOperatorKind kind) { return(kind & BinaryOperatorKind.OpMask); }
public static BinaryOperatorKind Unlifted(this BinaryOperatorKind kind) { return(kind & ~BinaryOperatorKind.Lifted); }
public static BinaryOperatorKind OperatorWithLogical(this BinaryOperatorKind kind) { return(kind & (BinaryOperatorKind.OpMask | BinaryOperatorKind.Logical)); }
/// <summary> /// Spec section 7.9: if the left operand is int or uint, mask the right operand with 0x1F; /// if the left operand is long or ulong, mask the right operand with 0x3F. /// </summary> private BoundExpression RewriteBuiltInShiftOperation( BoundBinaryOperator oldNode, CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type, int rightMask) { CSharpSyntaxNode rightSyntax = loweredRight.Syntax; ConstantValue rightConstantValue = loweredRight.ConstantValue; TypeSymbol rightType = loweredRight.Type; Debug.Assert(rightType.SpecialType == SpecialType.System_Int32); if (rightConstantValue != null && rightConstantValue.IsIntegral) { int shiftAmount = rightConstantValue.Int32Value & rightMask; if (shiftAmount == 0) { return loweredLeft; } loweredRight = MakeLiteral(rightSyntax, ConstantValue.Create(shiftAmount), rightType); } else { BinaryOperatorKind andOperatorKind = (operatorKind & ~BinaryOperatorKind.OpMask) | BinaryOperatorKind.And; loweredRight = new BoundBinaryOperator( rightSyntax, andOperatorKind, loweredRight, MakeLiteral(rightSyntax, ConstantValue.Create(rightMask), rightType), null, null, LookupResultKind.Viable, rightType); } return oldNode == null ? new BoundBinaryOperator( syntax, operatorKind, loweredLeft, loweredRight, null, null, LookupResultKind.Viable, type) : oldNode.Update( operatorKind, loweredLeft, loweredRight, null, null, oldNode.ResultKind, type); }
public static BinaryOperatorKind WithType(this BinaryOperatorKind kind, BinaryOperatorKind type) { Debug.Assert(kind == (kind & ~BinaryOperatorKind.TypeMask)); Debug.Assert(type == (type & BinaryOperatorKind.TypeMask)); return(kind | type); }
private BoundExpression RewritePointerSubtraction( BinaryOperatorKind kind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol returnType) { Debug.Assert(loweredLeft.Type.IsPointerType()); Debug.Assert(loweredRight.Type.IsPointerType()); Debug.Assert(returnType.SpecialType == SpecialType.System_Int64); PointerTypeSymbol pointerType = (PointerTypeSymbol)loweredLeft.Type; var sizeOfExpression = _factory.Sizeof(pointerType.PointedAtType); // NOTE: to match dev10, the result of the subtraction is treated as an IntPtr // and then the result of the division is converted to long. // NOTE: dev10 doesn't optimize away division by 1. return _factory.Convert( returnType, _factory.Binary( BinaryOperatorKind.Division, _factory.SpecialType(SpecialType.System_IntPtr), _factory.Binary( kind & ~BinaryOperatorKind.Checked, // For some reason, dev10 never checks for subtraction overflow. returnType, loweredLeft, loweredRight), sizeOfExpression), Conversion.PointerToInteger); }
public bool All(BinaryOperatorKind relation, uint value) { if (_hasLarge && relation switch { LessThan => true, LessThanOrEqual => true, _ => false })
private BoundExpression MakeDynamicLogicalBinaryOperator( CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, MethodSymbol leftTruthOperator, TypeSymbol type, bool isCompoundAssignment, BoundUnaryOperator applyParentUnaryOperator) { Debug.Assert(operatorKind.Operator() == BinaryOperatorKind.And || operatorKind.Operator() == BinaryOperatorKind.Or); // Dynamic logical && and || operators are lowered as follows: // left && right -> IsFalse(left) ? left : And(left, right) // left || right -> IsTrue(left) ? left : Or(left, right) // // Optimization: If the binary AND/OR is directly contained in IsFalse/IsTrue operator (parentUnaryOperator != null) // we can avoid calling IsFalse/IsTrue twice on the same object. // IsFalse(left && right) -> IsFalse(left) || IsFalse(And(left, right)) // IsTrue(left || right) -> IsTrue(left) || IsTrue(Or(left, right)) bool isAnd = operatorKind.Operator() == BinaryOperatorKind.And; // Operator to be used to test the left operand: var testOperator = isAnd ? UnaryOperatorKind.DynamicFalse : UnaryOperatorKind.DynamicTrue; // VisitUnaryOperator ensures we are never called with parentUnaryOperator != null when we can't perform the optimization. Debug.Assert(applyParentUnaryOperator == null || applyParentUnaryOperator.OperatorKind == testOperator); ConstantValue constantLeft = loweredLeft.ConstantValue ?? UnboxConstant(loweredLeft); if (testOperator == UnaryOperatorKind.DynamicFalse && constantLeft == ConstantValue.False || testOperator == UnaryOperatorKind.DynamicTrue && constantLeft == ConstantValue.True) { Debug.Assert(leftTruthOperator == null); if (applyParentUnaryOperator != null) { // IsFalse(false && right) -> true // IsTrue(true || right) -> true return _factory.Literal(true); } else { // false && right -> box(false) // true || right -> box(true) return MakeConversionNode(loweredLeft, type, @checked: false); } } BoundExpression result; var boolean = _compilation.GetSpecialType(SpecialType.System_Boolean); // Store left to local if needed. If constant or already local we don't need a temp // since the value of left can't change until right is evaluated. BoundAssignmentOperator tempAssignment; BoundLocal temp; if (constantLeft == null && loweredLeft.Kind != BoundKind.Local && loweredLeft.Kind != BoundKind.Parameter) { BoundAssignmentOperator assignment; var local = _factory.StoreToTemp(loweredLeft, out assignment); loweredLeft = local; tempAssignment = assignment; temp = local; } else { tempAssignment = null; temp = null; } var op = _dynamicFactory.MakeDynamicBinaryOperator(operatorKind, loweredLeft, loweredRight, isCompoundAssignment, type).ToExpression(); // IsFalse(true) or IsTrue(false) are always false: bool leftTestIsConstantFalse = testOperator == UnaryOperatorKind.DynamicFalse && constantLeft == ConstantValue.True || testOperator == UnaryOperatorKind.DynamicTrue && constantLeft == ConstantValue.False; if (applyParentUnaryOperator != null) { // IsFalse(left && right) -> IsFalse(left) || IsFalse(And(left, right)) // IsTrue(left || right) -> IsTrue(left) || IsTrue(Or(left, right)) result = _dynamicFactory.MakeDynamicUnaryOperator(testOperator, op, boolean).ToExpression(); if (!leftTestIsConstantFalse) { BoundExpression leftTest = MakeTruthTestForDynamicLogicalOperator(syntax, loweredLeft, boolean, leftTruthOperator, negative: isAnd); result = _factory.Binary(BinaryOperatorKind.LogicalOr, boolean, leftTest, result); } } else { // left && right -> IsFalse(left) ? left : And(left, right) // left || right -> IsTrue(left) ? left : Or(left, right) if (leftTestIsConstantFalse) { result = op; } else { // We might need to box. BoundExpression leftTest = MakeTruthTestForDynamicLogicalOperator(syntax, loweredLeft, boolean, leftTruthOperator, negative: isAnd); var convertedLeft = MakeConversionNode(loweredLeft, type, @checked: false); result = _factory.Conditional(leftTest, convertedLeft, op, type); } } if (tempAssignment != null) { return _factory.Sequence(ImmutableArray.Create(temp.LocalSymbol), ImmutableArray.Create<BoundExpression>(tempAssignment), result); } return result; }
private static void VerifyBinaryOperatorToken <T>(string expectedEndPathIdentifier, BinaryOperatorKind expectedOperator, T expectedLiteralValue, BinaryOperatorToken actual) { actual.Should().NotBeNull(); actual.OperatorKind.Should().Be(expectedOperator); var left = actual.Left as EndPathToken; left.Should().NotBeNull(); left.Identifier.Should().Be(expectedEndPathIdentifier); var right = actual.Right as LiteralToken; right.Should().NotBeNull(); right.Value.Should().Be(expectedLiteralValue); }
private BoundExpression TrivialLiftedComparisonOperatorOptimizations( CSharpSyntaxNode syntax, BinaryOperatorKind kind, BoundExpression left, BoundExpression right, MethodSymbol method) { Debug.Assert(left != null); Debug.Assert(right != null); // Optimization #1: if both sides are null then the result // is either true (for equality) or false (for everything else.) bool leftAlwaysNull = NullableNeverHasValue(left); bool rightAlwaysNull = NullableNeverHasValue(right); TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean); if (leftAlwaysNull && rightAlwaysNull) { return MakeLiteral(syntax, ConstantValue.Create(kind.Operator() == BinaryOperatorKind.Equal), boolType); } // Optimization #2: If both sides are non-null then we can again eliminate the lifting entirely. BoundExpression leftNonNull = NullableAlwaysHasValue(left); BoundExpression rightNonNull = NullableAlwaysHasValue(right); if (leftNonNull != null && rightNonNull != null) { return MakeBinaryOperator( syntax: syntax, operatorKind: kind.Unlifted(), loweredLeft: leftNonNull, loweredRight: rightNonNull, type: boolType, method: method); } // Optimization #3: If one side is null and the other is definitely not, then we generate the side effects // of the non-null side and result in true (for not-equals) or false (for everything else.) BinaryOperatorKind operatorKind = kind.Operator(); if (leftAlwaysNull && rightNonNull != null || rightAlwaysNull && leftNonNull != null) { BoundExpression result = MakeLiteral(syntax, ConstantValue.Create(operatorKind == BinaryOperatorKind.NotEqual), boolType); BoundExpression nonNull = leftAlwaysNull ? rightNonNull : leftNonNull; if (ReadIsSideeffecting(nonNull)) { result = new BoundSequence( syntax: syntax, locals: ImmutableArray<LocalSymbol>.Empty, sideEffects: ImmutableArray.Create<BoundExpression>(nonNull), value: result, type: boolType); } return result; } // Optimization #4: If one side is null and the other is unknown, then we have three cases: // #4a: If we have x == null then that becomes !x.HasValue. // #4b: If we have x != null then that becomes x.HasValue. // #4c: If we have x OP null then that becomes side effects of x, result in false. if (leftAlwaysNull || rightAlwaysNull) { BoundExpression maybeNull = leftAlwaysNull ? right : left; if (operatorKind == BinaryOperatorKind.Equal || operatorKind == BinaryOperatorKind.NotEqual) { BoundExpression callHasValue = MakeNullableHasValue(syntax, maybeNull); BoundExpression result = operatorKind == BinaryOperatorKind.Equal ? MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, callHasValue, boolType) : callHasValue; return result; } else { BoundExpression falseExpr = MakeBooleanConstant(syntax, operatorKind == BinaryOperatorKind.NotEqual); return _factory.Sequence(maybeNull, falseExpr); } } return null; }
/// <summary> /// Build BinaryOperatorNode to uri /// </summary> /// <param name="operatorKind">the kind of the BinaryOperatorNode</param> /// <returns>String format of the operator</returns> private String BinaryOperatorNodeToString(BinaryOperatorKind operatorKind) { switch (operatorKind) { case BinaryOperatorKind.Has: return(ExpressionConstants.KeywordHas); case BinaryOperatorKind.Equal: return(ExpressionConstants.KeywordEqual); case BinaryOperatorKind.NotEqual: return(ExpressionConstants.KeywordNotEqual); case BinaryOperatorKind.GreaterThan: return(ExpressionConstants.KeywordGreaterThan); case BinaryOperatorKind.GreaterThanOrEqual: return(ExpressionConstants.KeywordGreaterThanOrEqual); case BinaryOperatorKind.LessThan: return(ExpressionConstants.KeywordLessThan); case BinaryOperatorKind.LessThanOrEqual: return(ExpressionConstants.KeywordLessThanOrEqual); // if current translated node is SearchNode, the BinaryOperator should return AND, OR; or return and, or. case BinaryOperatorKind.And: if (searchFlag) { return(ExpressionConstants.SearchKeywordAnd); } return(ExpressionConstants.KeywordAnd); case BinaryOperatorKind.Or: if (searchFlag) { return(ExpressionConstants.SearchKeywordOr); } return(ExpressionConstants.KeywordOr); case BinaryOperatorKind.Add: return(ExpressionConstants.KeywordAdd); case BinaryOperatorKind.Subtract: return(ExpressionConstants.KeywordSub); case BinaryOperatorKind.Multiply: return(ExpressionConstants.KeywordMultiply); case BinaryOperatorKind.Divide: return(ExpressionConstants.KeywordDivide); case BinaryOperatorKind.Modulo: return(ExpressionConstants.KeywordModulo); default: return(null); } }
private BoundExpression LowerLiftedUserDefinedComparisonOperator( CSharpSyntaxNode syntax, BinaryOperatorKind kind, BoundExpression loweredLeft, BoundExpression loweredRight, MethodSymbol method) { // If both sides are null, or neither side is null, then we can do some simple optimizations. BoundExpression optimized = TrivialLiftedComparisonOperatorOptimizations(syntax, kind, loweredLeft, loweredRight, method); if (optimized != null) { return optimized; } // Otherwise, the expression // // x == y // // becomes // // tempX = x; // tempY = y; // result = tempX.HasValue == tempY.HasValue ? // (tempX.HasValue ? // tempX.GetValueOrDefault() == tempY.GetValueOrDefault() : // true) : // false; // // // the expression // // x != y // // becomes // // tempX = x; // tempY = y; // result = tempX.HasValue == tempY.HasValue ? // (tempX.HasValue ? // tempX.GetValueOrDefault() != tempY.GetValueOrDefault() : // false) : // true; // // // For the other comparison operators <, <=, >, >=, // // x OP y // // becomes // // tempX = x; // tempY = y; // result = tempX.HasValue & tempY.HasValue ? // tempX.GetValueOrDefault() OP tempY.GetValueOrDefault() : // false; // // We have not yet optimized the case where we have a known-not-null value on one side, // and an unknown value on the other. In those cases we will still generate a temp, but // we will not generate the call to the unnecessary nullable ctor or to GetValueOrDefault. // Rather, we will generate the value's temp instead of a call to GetValueOrDefault, and generate // literal true for HasValue. The tree construction methods we call will use those constants // to eliminate unnecessary branches. BoundExpression xNonNull = NullableAlwaysHasValue(loweredLeft); BoundExpression yNonNull = NullableAlwaysHasValue(loweredRight); // TODO: (This TODO applies throughout this file, not just to this method.) // TODO: We might be storing a constant to this temporary that we could simply inline. // TODO: (There are other expressions that can be safely moved around other than constants // TODO: as well -- for example a boxing conversion of a constant int to object.) // TODO: Build a better temporary-storage management system that decides whether or not // TODO: to store a temporary. BoundAssignmentOperator tempAssignmentX; BoundLocal boundTempX = _factory.StoreToTemp(xNonNull ?? loweredLeft, out tempAssignmentX); BoundAssignmentOperator tempAssignmentY; BoundLocal boundTempY = _factory.StoreToTemp(yNonNull ?? loweredRight, out tempAssignmentY); BoundExpression callX_GetValueOrDefault = MakeOptimizedGetValueOrDefault(syntax, boundTempX); BoundExpression callY_GetValueOrDefault = MakeOptimizedGetValueOrDefault(syntax, boundTempY); BoundExpression callX_HasValue = MakeOptimizedHasValue(syntax, boundTempX); BoundExpression callY_HasValue = MakeOptimizedHasValue(syntax, boundTempY); // tempx.HasValue == tempy.HasValue BinaryOperatorKind conditionOperator; BinaryOperatorKind operatorKind = kind.Operator(); switch (operatorKind) { case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: conditionOperator = BinaryOperatorKind.BoolEqual; break; default: conditionOperator = BinaryOperatorKind.BoolAnd; break; } TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean); BoundExpression condition = MakeBinaryOperator( syntax: syntax, operatorKind: conditionOperator, loweredLeft: callX_HasValue, loweredRight: callY_HasValue, type: boolType, method: null); // tempX.GetValueOrDefault() OP tempY.GetValueOrDefault() BoundExpression unliftedOp = MakeBinaryOperator( syntax: syntax, operatorKind: kind.Unlifted(), loweredLeft: callX_GetValueOrDefault, loweredRight: callY_GetValueOrDefault, type: boolType, method: method); BoundExpression consequence; if (operatorKind == BinaryOperatorKind.Equal || operatorKind == BinaryOperatorKind.NotEqual) { // tempx.HasValue ? tempX.GetValueOrDefault() == tempY.GetValueOrDefault() : true consequence = RewriteConditionalOperator( syntax: syntax, rewrittenCondition: callX_HasValue, rewrittenConsequence: unliftedOp, rewrittenAlternative: MakeLiteral(syntax, ConstantValue.Create(operatorKind == BinaryOperatorKind.Equal), boolType), constantValueOpt: null, rewrittenType: boolType); } else { // tempX.GetValueOrDefault() OP tempY.GetValueOrDefault() consequence = unliftedOp; } // false BoundExpression alternative = MakeBooleanConstant(syntax, operatorKind == BinaryOperatorKind.NotEqual); BoundExpression conditionalExpression = RewriteConditionalOperator( syntax: syntax, rewrittenCondition: condition, rewrittenConsequence: consequence, rewrittenAlternative: alternative, constantValueOpt: null, rewrittenType: boolType); return new BoundSequence( syntax: syntax, locals: ImmutableArray.Create<LocalSymbol>(boundTempX.LocalSymbol, boundTempY.LocalSymbol), sideEffects: ImmutableArray.Create<BoundExpression>(tempAssignmentX, tempAssignmentY), value: conditionalExpression, type: boolType); }
public static int OperatorIndex(this BinaryOperatorKind kind) { return(((int)kind.Operator() >> 8) - 16); }