in src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs [154:478]
private BoundExpression MakeBinaryOperator(
BoundBinaryOperator oldNode,
SyntaxNode 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;
// Note that we are using IsDefaultValue instead of False.
// That is just to catch cases like default(bool) or others resulting in
// a default bool value, that we know to be "false"
// bool? generally should not reach here, since it is handled by RewriteLiftedBinaryOperator.
// Regardless, the following code should handle default(bool?) correctly since
// default(bool?) & <expr> == default(bool?) with sideeffects of <expr>
if (loweredLeft.IsDefaultValue())
{
return _factory.MakeSequence(loweredRight, loweredLeft);
}
if (loweredRight.IsDefaultValue())
{
return _factory.MakeSequence(loweredLeft, 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 _factory.MakeSequence(loweredRight, loweredLeft);
}
if (loweredRight.IsDefaultValue())
{
return _factory.MakeSequence(loweredLeft, 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);
}