private static ConstantValue GetConstantOneForBinOp( BinaryOperatorKind binaryOperatorKind) { switch (binaryOperatorKind.OperandTypes()) { case BinaryOperatorKind.PointerAndInt: case BinaryOperatorKind.Int: return(ConstantValue.Create(1)); case BinaryOperatorKind.UInt: return(ConstantValue.Create(1U)); case BinaryOperatorKind.Long: return(ConstantValue.Create(1L)); case BinaryOperatorKind.ULong: return(ConstantValue.Create(1LU)); case BinaryOperatorKind.Float: return(ConstantValue.Create(1f)); case BinaryOperatorKind.Double: return(ConstantValue.Create(1.0)); case BinaryOperatorKind.Decimal: return(ConstantValue.Create(1m)); default: throw ExceptionUtilities.UnexpectedValue(binaryOperatorKind.OperandTypes()); } }
private RelationalDispatch(SyntaxNode syntax, ConstantValue value, BinaryOperatorKind op, ValueDispatchNode left, ValueDispatchNode right) : base(syntax) { Debug.Assert(op.OperandTypes() != 0); this.Value = value; this.Operator = op; WithLeftAndRight(left, right); }
private TypeSymbol LiftedType(BinaryOperatorKind kind) { Debug.Assert(kind.IsLifted()); var nullable = _compilation.GetSpecialType(SpecialType.core_Option_T); switch (kind.OperandTypes()) { case BinaryOperatorKind.Int32: return(nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Int32))); case BinaryOperatorKind.UInt32: return(nullable.Construct(_compilation.GetSpecialType(SpecialType.System_UInt32))); case BinaryOperatorKind.Int64: return(nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Int64))); case BinaryOperatorKind.UInt64: return(nullable.Construct(_compilation.GetSpecialType(SpecialType.System_UInt64))); case BinaryOperatorKind.Float32: return(nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Float32))); case BinaryOperatorKind.Float64: return(nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Float64))); case BinaryOperatorKind.Int: return(nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Int))); case BinaryOperatorKind.UInt: return(nullable.Construct(_compilation.GetSpecialType(SpecialType.System_UInt))); case BinaryOperatorKind.Bool: return(nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Boolean))); } Debug.Assert(false, "Bad operator kind in lifted type"); return(null); }
private TypeSymbol LiftedType(BinaryOperatorKind kind) { Debug.Assert(kind.IsLifted()); var nullable = Compilation.GetSpecialType(SpecialType.System_Nullable_T); switch (kind.OperandTypes()) { case BinaryOperatorKind.Int: return(nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Int32))); case BinaryOperatorKind.UInt: return(nullable.Construct(Compilation.GetSpecialType(SpecialType.System_UInt32))); case BinaryOperatorKind.Long: return(nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Int64))); case BinaryOperatorKind.ULong: return(nullable.Construct(Compilation.GetSpecialType(SpecialType.System_UInt64))); case BinaryOperatorKind.Float: return(nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Single))); case BinaryOperatorKind.Double: return(nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Double))); case BinaryOperatorKind.Decimal: return(nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Decimal))); case BinaryOperatorKind.Bool: return(nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Boolean))); } Debug.Assert(false, "Bad operator kind in lifted type"); return(null); }
public static bool IsIntegral(this BinaryOperatorKind kind) { switch (kind.OperandTypes()) { case BinaryOperatorKind.Int: case BinaryOperatorKind.UInt: case BinaryOperatorKind.Long: case BinaryOperatorKind.ULong: case BinaryOperatorKind.NInt: case BinaryOperatorKind.NUInt: case BinaryOperatorKind.Char: case BinaryOperatorKind.Enum: case BinaryOperatorKind.EnumAndUnderlying: case BinaryOperatorKind.UnderlyingAndEnum: case BinaryOperatorKind.Pointer: case BinaryOperatorKind.PointerAndInt: case BinaryOperatorKind.PointerAndUInt: case BinaryOperatorKind.PointerAndLong: case BinaryOperatorKind.PointerAndULong: case BinaryOperatorKind.IntAndPointer: case BinaryOperatorKind.UIntAndPointer: case BinaryOperatorKind.LongAndPointer: case BinaryOperatorKind.ULongAndPointer: return(true); } return(false); }
private static bool IsUnsignedBinaryOperator(BoundBinaryOperator op) { BinaryOperatorKind opKind = op.OperatorKind; BinaryOperatorKind type = opKind.OperandTypes(); switch (type) { case BinaryOperatorKind.Enum: case BinaryOperatorKind.EnumAndUnderlying: return(IsUnsigned(Binder.GetEnumPromotedType(op.Left.Type.GetEnumUnderlyingType().SpecialType))); case BinaryOperatorKind.UnderlyingAndEnum: return(IsUnsigned(Binder.GetEnumPromotedType(op.Right.Type.GetEnumUnderlyingType().SpecialType))); case BinaryOperatorKind.UInt: case BinaryOperatorKind.ULong: case BinaryOperatorKind.ULongAndPointer: case BinaryOperatorKind.PointerAndInt: case BinaryOperatorKind.PointerAndUInt: case BinaryOperatorKind.PointerAndLong: case BinaryOperatorKind.PointerAndULong: case BinaryOperatorKind.Pointer: return(true); // Dev10 bases signedness on the first operand (see ILGENREC::genOperatorExpr). case BinaryOperatorKind.IntAndPointer: case BinaryOperatorKind.LongAndPointer: // Dev10 converts the uint to a native int, so it counts as signed. case BinaryOperatorKind.UIntAndPointer: default: return(false); } }
private BoundExpression VisitBinaryOperator(BinaryOperatorKind opKind, MethodSymbol methodOpt, TypeSymbol type, BoundExpression left, BoundExpression right) { bool isChecked, isLifted, requiresLifted; string opName = GetBinaryOperatorName(opKind, out isChecked, out isLifted, out requiresLifted); // Fix up the null value for a nullable comparison vs null if ((object)left.Type == null && left.IsLiteralNull()) { left = _bound.Default(right.Type); } if ((object)right.Type == null && right.IsLiteralNull()) { right = _bound.Default(left.Type); } // Enums are handled as per their promoted underlying type switch (opKind.OperandTypes()) { case BinaryOperatorKind.EnumAndUnderlying: case BinaryOperatorKind.UnderlyingAndEnum: case BinaryOperatorKind.Enum: { var enumOperand = (opKind.OperandTypes() == BinaryOperatorKind.UnderlyingAndEnum) ? right : left; var promotedType = PromotedType(enumOperand.Type.StrippedType().GetEnumUnderlyingType()); if (opKind.IsLifted()) { promotedType = _nullableType.Construct(promotedType); } var loweredLeft = VisitAndPromoteEnumOperand(left, promotedType, isChecked); var loweredRight = VisitAndPromoteEnumOperand(right, promotedType, isChecked); var result = MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight); return(Demote(result, type, isChecked)); } default: { var loweredLeft = Visit(left); var loweredRight = Visit(right); return(MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight)); } } }
public static bool IsEnum(this BinaryOperatorKind kind) { switch (kind.OperandTypes()) { case BinaryOperatorKind.Enum: case BinaryOperatorKind.EnumAndUnderlying: case BinaryOperatorKind.UnderlyingAndEnum: return(true); } return(false); }
private TypeSymbol ReturnType(BinaryOperatorKind kind) { switch (kind.OperandTypes()) { case BinaryOperatorKind.Int: return(_compilation.GetSpecialType(SpecialType.System_Int32)); case BinaryOperatorKind.String: return(_compilation.GetSpecialType(SpecialType.System_String)); } Debug.Assert(false, "Bad operator kind in return type"); return(null); }
private static bool IsFloat(BinaryOperatorKind opKind) { var type = opKind.OperandTypes(); switch (type) { case BinaryOperatorKind.Float: case BinaryOperatorKind.Double: return(true); default: return(false); } }
private TypeSymbol RightType(BinaryOperatorKind kind) { if (kind.IsLifted()) { return(LiftedType(kind)); } else { switch (kind.OperandTypes()) { case BinaryOperatorKind.Int32: return(_compilation.GetSpecialType(SpecialType.System_Int32)); case BinaryOperatorKind.UInt32: return(_compilation.GetSpecialType(SpecialType.System_UInt32)); case BinaryOperatorKind.Int64: return(_compilation.GetSpecialType(SpecialType.System_Int64)); case BinaryOperatorKind.UInt64: return(_compilation.GetSpecialType(SpecialType.System_UInt64)); case BinaryOperatorKind.Float32: return(_compilation.GetSpecialType(SpecialType.System_Float32)); case BinaryOperatorKind.Float64: return(_compilation.GetSpecialType(SpecialType.System_Float64)); case BinaryOperatorKind.Int: return(_compilation.GetSpecialType(SpecialType.System_Int)); case BinaryOperatorKind.UInt: return(_compilation.GetSpecialType(SpecialType.System_UInt)); case BinaryOperatorKind.Bool: return(_compilation.GetSpecialType(SpecialType.System_Boolean)); case BinaryOperatorKind.ObjectAndString: case BinaryOperatorKind.String: return(_compilation.GetSpecialType(SpecialType.System_String)); case BinaryOperatorKind.StringAndObject: case BinaryOperatorKind.Object: return(_compilation.GetSpecialType(SpecialType.System_Object)); } } Debug.Assert(false, "Bad operator kind in right type"); return(null); }
private static bool IsConditional(BinaryOperatorKind opKind) { switch (opKind.OperatorWithLogical()) { case BinaryOperatorKind.LogicalAnd: case BinaryOperatorKind.LogicalOr: case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.LessThanOrEqual: case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.GreaterThanOrEqual: return(true); case BinaryOperatorKind.And: case BinaryOperatorKind.Or: case BinaryOperatorKind.Xor: return(opKind.OperandTypes() == BinaryOperatorKind.Bool); } return(false); }
private TypeSymbol LeftType(BinaryOperatorKind kind) { if (kind.IsLifted()) { return(LiftedType(kind)); } else { switch (kind.OperandTypes()) { case BinaryOperatorKind.Int: return(Compilation.GetSpecialType(SpecialType.System_Int32)); case BinaryOperatorKind.UInt: return(Compilation.GetSpecialType(SpecialType.System_UInt32)); case BinaryOperatorKind.Long: return(Compilation.GetSpecialType(SpecialType.System_Int64)); case BinaryOperatorKind.ULong: return(Compilation.GetSpecialType(SpecialType.System_UInt64)); case BinaryOperatorKind.Float: return(Compilation.GetSpecialType(SpecialType.System_Single)); case BinaryOperatorKind.Double: return(Compilation.GetSpecialType(SpecialType.System_Double)); case BinaryOperatorKind.Decimal: return(Compilation.GetSpecialType(SpecialType.System_Decimal)); case BinaryOperatorKind.Bool: return(Compilation.GetSpecialType(SpecialType.System_Boolean)); case BinaryOperatorKind.ObjectAndString: case BinaryOperatorKind.Object: return(Compilation.GetSpecialType(SpecialType.System_Object)); case BinaryOperatorKind.String: case BinaryOperatorKind.StringAndObject: return(Compilation.GetSpecialType(SpecialType.System_String)); } } Debug.Assert(false, "Bad operator kind in left type"); return(null); }
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 MakeBinaryOperator( BoundBinaryOperator oldNode, CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type, MethodSymbol method, bool isPointerElementAccess = false, bool isCompoundAssignment = false, BoundUnaryOperator applyParentUnaryOperator = null) { Debug.Assert(oldNode == null || (oldNode.Syntax == syntax)); if (_inExpressionLambda) { switch (operatorKind.Operator() | operatorKind.OperandTypes()) { case BinaryOperatorKind.ObjectAndStringConcatenation: case BinaryOperatorKind.StringAndObjectConcatenation: case BinaryOperatorKind.StringConcatenation: return RewriteStringConcatenation(syntax, operatorKind, loweredLeft, loweredRight, type); case BinaryOperatorKind.DelegateCombination: return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Combine); case BinaryOperatorKind.DelegateRemoval: return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Remove); case BinaryOperatorKind.DelegateEqual: return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Equality); case BinaryOperatorKind.DelegateNotEqual: return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Inequality); } } else // try to lower the expression. { if (operatorKind.IsDynamic()) { Debug.Assert(!isPointerElementAccess); if (operatorKind.IsLogical()) { return MakeDynamicLogicalBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, method, type, isCompoundAssignment, applyParentUnaryOperator); } else { Debug.Assert((object)method == null); return _dynamicFactory.MakeDynamicBinaryOperator(operatorKind, loweredLeft, loweredRight, isCompoundAssignment, type).ToExpression(); } } if (operatorKind.IsLifted()) { return RewriteLiftedBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, type, method); } if (operatorKind.IsUserDefined()) { return LowerUserDefinedBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, type, method); } switch (operatorKind.OperatorWithLogical() | operatorKind.OperandTypes()) { case BinaryOperatorKind.NullableNullEqual: case BinaryOperatorKind.NullableNullNotEqual: return RewriteNullableNullEquality(syntax, operatorKind, loweredLeft, loweredRight, type); case BinaryOperatorKind.ObjectAndStringConcatenation: case BinaryOperatorKind.StringAndObjectConcatenation: case BinaryOperatorKind.StringConcatenation: return RewriteStringConcatenation(syntax, operatorKind, loweredLeft, loweredRight, type); case BinaryOperatorKind.StringEqual: return RewriteStringEquality(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_String__op_Equality); case BinaryOperatorKind.StringNotEqual: return RewriteStringEquality(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_String__op_Inequality); case BinaryOperatorKind.DelegateCombination: return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Combine); case BinaryOperatorKind.DelegateRemoval: return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Remove); case BinaryOperatorKind.DelegateEqual: return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Equality); case BinaryOperatorKind.DelegateNotEqual: return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Inequality); case BinaryOperatorKind.LogicalBoolAnd: if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft; if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight; if (loweredLeft.ConstantValue == ConstantValue.False) return loweredLeft; if (loweredRight.Kind == BoundKind.Local || loweredRight.Kind == BoundKind.Parameter) { operatorKind &= ~BinaryOperatorKind.Logical; } goto default; case BinaryOperatorKind.LogicalBoolOr: if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft; if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight; if (loweredLeft.ConstantValue == ConstantValue.True) return loweredLeft; if (loweredRight.Kind == BoundKind.Local || loweredRight.Kind == BoundKind.Parameter) { operatorKind &= ~BinaryOperatorKind.Logical; } goto default; case BinaryOperatorKind.BoolAnd: if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft; if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight; goto default; case BinaryOperatorKind.BoolOr: if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft; if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight; goto default; case BinaryOperatorKind.BoolEqual: if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight; if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft; if (loweredLeft.ConstantValue == ConstantValue.False) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredRight, loweredRight.Type); if (loweredRight.ConstantValue == ConstantValue.False) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredLeft, loweredLeft.Type); goto default; case BinaryOperatorKind.BoolNotEqual: if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight; if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft; if (loweredLeft.ConstantValue == ConstantValue.True) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredRight, loweredRight.Type); if (loweredRight.ConstantValue == ConstantValue.True) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredLeft, loweredLeft.Type); goto default; case BinaryOperatorKind.BoolXor: if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight; if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft; if (loweredLeft.ConstantValue == ConstantValue.True) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredRight, loweredRight.Type); if (loweredRight.ConstantValue == ConstantValue.True) return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredLeft, loweredLeft.Type); goto default; case BinaryOperatorKind.IntLeftShift: case BinaryOperatorKind.UIntLeftShift: case BinaryOperatorKind.IntRightShift: case BinaryOperatorKind.UIntRightShift: return RewriteBuiltInShiftOperation(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, 0x1F); case BinaryOperatorKind.LongLeftShift: case BinaryOperatorKind.ULongLeftShift: case BinaryOperatorKind.LongRightShift: case BinaryOperatorKind.ULongRightShift: return RewriteBuiltInShiftOperation(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, 0x3F); case BinaryOperatorKind.DecimalAddition: case BinaryOperatorKind.DecimalSubtraction: case BinaryOperatorKind.DecimalMultiplication: case BinaryOperatorKind.DecimalDivision: case BinaryOperatorKind.DecimalRemainder: case BinaryOperatorKind.DecimalEqual: case BinaryOperatorKind.DecimalNotEqual: case BinaryOperatorKind.DecimalLessThan: case BinaryOperatorKind.DecimalLessThanOrEqual: case BinaryOperatorKind.DecimalGreaterThan: case BinaryOperatorKind.DecimalGreaterThanOrEqual: return RewriteDecimalBinaryOperation(syntax, loweredLeft, loweredRight, operatorKind); case BinaryOperatorKind.PointerAndIntAddition: case BinaryOperatorKind.PointerAndUIntAddition: case BinaryOperatorKind.PointerAndLongAddition: case BinaryOperatorKind.PointerAndULongAddition: case BinaryOperatorKind.PointerAndIntSubtraction: case BinaryOperatorKind.PointerAndUIntSubtraction: case BinaryOperatorKind.PointerAndLongSubtraction: case BinaryOperatorKind.PointerAndULongSubtraction: if (loweredRight.IsDefaultValue()) { return loweredLeft; } return RewritePointerNumericOperator(syntax, operatorKind, loweredLeft, loweredRight, type, isPointerElementAccess, isLeftPointer: true); case BinaryOperatorKind.IntAndPointerAddition: case BinaryOperatorKind.UIntAndPointerAddition: case BinaryOperatorKind.LongAndPointerAddition: case BinaryOperatorKind.ULongAndPointerAddition: if (loweredLeft.IsDefaultValue()) { return loweredRight; } return RewritePointerNumericOperator(syntax, operatorKind, loweredLeft, loweredRight, type, isPointerElementAccess, isLeftPointer: false); case BinaryOperatorKind.PointerSubtraction: return RewritePointerSubtraction(operatorKind, loweredLeft, loweredRight, type); case BinaryOperatorKind.IntAddition: case BinaryOperatorKind.UIntAddition: case BinaryOperatorKind.LongAddition: case BinaryOperatorKind.ULongAddition: if (loweredLeft.IsDefaultValue()) { return loweredRight; } if (loweredRight.IsDefaultValue()) { return loweredLeft; } goto default; case BinaryOperatorKind.IntSubtraction: case BinaryOperatorKind.LongSubtraction: case BinaryOperatorKind.UIntSubtraction: case BinaryOperatorKind.ULongSubtraction: if (loweredRight.IsDefaultValue()) { return loweredLeft; } goto default; case BinaryOperatorKind.IntMultiplication: case BinaryOperatorKind.LongMultiplication: case BinaryOperatorKind.UIntMultiplication: case BinaryOperatorKind.ULongMultiplication: if (loweredLeft.IsDefaultValue()) { return loweredLeft; } if (loweredRight.IsDefaultValue()) { return loweredRight; } if (loweredLeft.ConstantValue?.UInt64Value == 1) { return loweredRight; } if (loweredRight.ConstantValue?.UInt64Value == 1) { return loweredLeft; } goto default; case BinaryOperatorKind.IntGreaterThan: case BinaryOperatorKind.IntLessThanOrEqual: if (loweredLeft.Kind == BoundKind.ArrayLength && loweredRight.IsDefaultValue()) { //array length is never negative var newOp = operatorKind == BinaryOperatorKind.IntGreaterThan ? BinaryOperatorKind.NotEqual : BinaryOperatorKind.Equal; operatorKind &= ~BinaryOperatorKind.OpMask; operatorKind |= newOp; loweredLeft = UnconvertArrayLength((BoundArrayLength)loweredLeft); } goto default; case BinaryOperatorKind.IntLessThan: case BinaryOperatorKind.IntGreaterThanOrEqual: if (loweredRight.Kind == BoundKind.ArrayLength && loweredLeft.IsDefaultValue()) { //array length is never negative var newOp = operatorKind == BinaryOperatorKind.IntLessThan ? BinaryOperatorKind.NotEqual : BinaryOperatorKind.Equal; operatorKind &= ~BinaryOperatorKind.OpMask; operatorKind |= newOp; loweredRight = UnconvertArrayLength((BoundArrayLength)loweredRight); } goto default; case BinaryOperatorKind.IntEqual: case BinaryOperatorKind.IntNotEqual: if (loweredLeft.Kind == BoundKind.ArrayLength && loweredRight.IsDefaultValue()) { loweredLeft = UnconvertArrayLength((BoundArrayLength)loweredLeft); } else if (loweredRight.Kind == BoundKind.ArrayLength && loweredLeft.IsDefaultValue()) { loweredRight = UnconvertArrayLength((BoundArrayLength)loweredRight); } goto default; default: break; } } return (oldNode != null) ? oldNode.Update(operatorKind, loweredLeft, loweredRight, oldNode.ConstantValueOpt, oldNode.MethodOpt, oldNode.ResultKind, type) : new BoundBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, null, null, LookupResultKind.Viable, type); }
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 input/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 = UnsafeGetNullableMethod(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 = MakeConversionNode( 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 = MakeConversionNode(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 = MakeConversionNode(binOp, unaryOperandType, @checked); return(result); }
private static bool IsConditional(BinaryOperatorKind opKind) { switch (opKind.OperatorWithLogical()) { case BinaryOperatorKind.LogicalAnd: case BinaryOperatorKind.LogicalOr: case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.LessThanOrEqual: case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.GreaterThanOrEqual: return true; case BinaryOperatorKind.And: case BinaryOperatorKind.Or: case BinaryOperatorKind.Xor: return opKind.OperandTypes() == BinaryOperatorKind.Bool; } return false; }
private BoundExpression VisitBinaryOperator(BinaryOperatorKind opKind, MethodSymbol methodOpt, TypeSymbol type, BoundExpression left, BoundExpression right) { bool isChecked, isLifted, requiresLifted; string opName = GetBinaryOperatorName(opKind, out isChecked, out isLifted, out requiresLifted); // Fix up the null value for a nullable comparison vs null if ((object)left.Type == null && left.IsLiteralNull()) { left = _bound.Default(right.Type); } if ((object)right.Type == null && right.IsLiteralNull()) { right = _bound.Default(left.Type); } var loweredLeft = Visit(left); var loweredRight = Visit(right); // Enums are handled as per their promoted underlying type switch (opKind.OperandTypes()) { case BinaryOperatorKind.Enum: case BinaryOperatorKind.EnumAndUnderlying: case BinaryOperatorKind.UnderlyingAndEnum: { var enumOperand = (opKind.OperandTypes() == BinaryOperatorKind.UnderlyingAndEnum) ? right : left; var promotedType = PromotedType(enumOperand.Type.StrippedType().GetEnumUnderlyingType()); if (opKind.IsLifted()) { promotedType = _nullableType.Construct(promotedType); } loweredLeft = PromoteEnumOperand(left, loweredLeft, promotedType, isChecked); loweredRight = PromoteEnumOperand(right, loweredRight, promotedType, isChecked); var result = MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight); return Demote(result, type, isChecked); } default: return MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight); } }
private static bool IsFloat(BinaryOperatorKind opKind) { var type = opKind.OperandTypes(); switch (type) { case BinaryOperatorKind.Float: case BinaryOperatorKind.Double: return true; default: return false; } }
private static ConstantValue GetConstantOneForBinOp( BinaryOperatorKind binaryOperatorKind) { switch (binaryOperatorKind.OperandTypes()) { case BinaryOperatorKind.PointerAndInt: case BinaryOperatorKind.Int: return ConstantValue.Create(1); case BinaryOperatorKind.UInt: return ConstantValue.Create(1U); case BinaryOperatorKind.Long: return ConstantValue.Create(1L); case BinaryOperatorKind.ULong: return ConstantValue.Create(1LU); case BinaryOperatorKind.Float: return ConstantValue.Create(1f); case BinaryOperatorKind.Double: return ConstantValue.Create(1.0); case BinaryOperatorKind.Decimal: return ConstantValue.Create(1m); default: throw ExceptionUtilities.UnexpectedValue(binaryOperatorKind.OperandTypes()); } }
public static bool IsDynamic(this BinaryOperatorKind kind) { return(kind.OperandTypes() == BinaryOperatorKind.Dynamic); }
private TypeSymbol LiftedType(BinaryOperatorKind kind) { Debug.Assert(kind.IsLifted()); var nullable = Compilation.GetSpecialType(SpecialType.System_Nullable_T); switch (kind.OperandTypes()) { case BinaryOperatorKind.Int: return nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Int32)); case BinaryOperatorKind.UInt: return nullable.Construct(Compilation.GetSpecialType(SpecialType.System_UInt32)); case BinaryOperatorKind.Long: return nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Int64)); case BinaryOperatorKind.ULong: return nullable.Construct(Compilation.GetSpecialType(SpecialType.System_UInt64)); case BinaryOperatorKind.Float: return nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Single)); case BinaryOperatorKind.Double: return nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Double)); case BinaryOperatorKind.Decimal: return nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Decimal)); case BinaryOperatorKind.Bool: return nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Boolean)); } Debug.Assert(false, "Bad operator kind in lifted type"); return null; }
private TypeSymbol ReturnType(BinaryOperatorKind kind) { if (kind.IsLifted()) { return LiftedType(kind); } else { switch (kind.OperandTypes()) { case BinaryOperatorKind.Int: return Compilation.GetSpecialType(SpecialType.System_Int32); case BinaryOperatorKind.UInt: return Compilation.GetSpecialType(SpecialType.System_UInt32); case BinaryOperatorKind.Long: return Compilation.GetSpecialType(SpecialType.System_Int64); case BinaryOperatorKind.ULong: return Compilation.GetSpecialType(SpecialType.System_UInt64); case BinaryOperatorKind.Float: return Compilation.GetSpecialType(SpecialType.System_Single); case BinaryOperatorKind.Double: return Compilation.GetSpecialType(SpecialType.System_Double); case BinaryOperatorKind.Decimal: return Compilation.GetSpecialType(SpecialType.System_Decimal); case BinaryOperatorKind.Bool: return Compilation.GetSpecialType(SpecialType.System_Boolean); case BinaryOperatorKind.Object: return Compilation.GetSpecialType(SpecialType.System_Object); case BinaryOperatorKind.ObjectAndString: case BinaryOperatorKind.StringAndObject: case BinaryOperatorKind.String: return Compilation.GetSpecialType(SpecialType.System_String); } } Debug.Assert(false, "Bad operator kind in return type"); return null; }