public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) { BoundExpression left = (BoundExpression)this.Visit(node.Left); BoundExpression right = (BoundExpression)this.Visit(node.Right); TypeSymbol type = this.VisitType(node.Type); if (!RequiresSpill(left, right)) { return(node.Update(node.OperatorKind, left, right, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, type)); } var subExprs = ReadOnlyArray <BoundExpression> .CreateFrom(left, right); var spillBuilder = new SpillBuilder(); var newArgs = SpillExpressionList(spillBuilder, subExprs); Debug.Assert(newArgs.Count == 2); var newBinaryOperator = node.Update( node.OperatorKind, newArgs[0], newArgs[1], node.ConstantValueOpt, node.MethodOpt, node.ResultKind, type); return(spillBuilder.BuildSequenceAndFree(F, newBinaryOperator)); }
public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) { BoundSpillSequenceBuilder builder = null; var right = VisitExpression(ref builder, node.Right); BoundExpression left; if (builder == null) { left = VisitExpression(ref builder, node.Left); } else { var leftBuilder = new BoundSpillSequenceBuilder(); left = VisitExpression(ref leftBuilder, node.Left); left = Spill(leftBuilder, left); if (node.OperatorKind == BinaryOperatorKind.LogicalBoolOr || node.OperatorKind == BinaryOperatorKind.LogicalBoolAnd) { leftBuilder.AddStatement(_F.If( node.OperatorKind == BinaryOperatorKind.LogicalBoolAnd ? left : _F.Not(left), UpdateStatement(builder, _F.Assignment(left, right), substituteTemps: false))); return(UpdateExpression(leftBuilder, left)); } else { // if the right-hand-side has await, spill the left leftBuilder.Include(builder); builder = leftBuilder; } } return(UpdateExpression(builder, node.Update(node.OperatorKind, left, right, node.ConstantValue, node.MethodOpt, node.ResultKind, node.Type))); }
public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) { BoundSpillSequence2 ss = null; var right = VisitExpression(ref ss, node.Right); BoundExpression left; if (ss == null) { left = VisitExpression(ref ss, node.Left); } else { var ssLeft = new BoundSpillSequence2(); left = VisitExpression(ref ssLeft, node.Left); left = Spill(ssLeft, left); if (node.OperatorKind == BinaryOperatorKind.LogicalBoolOr || node.OperatorKind == BinaryOperatorKind.LogicalBoolAnd) { ssLeft.Add(F.If( node.OperatorKind == BinaryOperatorKind.LogicalBoolAnd ? left : F.Not(left), UpdateStatement(ss, F.Assignment(left, right)) )); return(UpdateExpression(ssLeft, left)); } else { // if the right-hand-side has await, spill the left ssLeft.IncludeSequence(ss); ss = ssLeft; } } return(UpdateExpression(ss, node.Update(node.OperatorKind, left, right, node.ConstantValue, node.MethodOpt, node.ResultKind, node.Type))); }
private BoundExpression TryFoldWithConditionalAccess(BoundBinaryOperator node) { var syntax = node.Syntax; var left = node.Left; var right = node.Right; BoundConditionalAccess conditionalAccess; if (!node.OperatorKind.IsLifted()) { var operatorKind = node.OperatorKind; if (operatorKind == BinaryOperatorKind.NullableNullEqual || operatorKind == BinaryOperatorKind.NullableNullNotEqual) { var leftAlwaysNull = NullableNeverHasValue(left); var rightAlwaysNull = NullableNeverHasValue(right); if (leftAlwaysNull || rightAlwaysNull) { BoundExpression maybeNull = leftAlwaysNull ? right : left; if (TryGetOptimizableNullableConditionalAccess(maybeNull, out conditionalAccess)) { BoundExpression accessExpression = conditionalAccess.AccessExpression; accessExpression = _factory.Sequence(accessExpression, MakeBooleanConstant(syntax, operatorKind == BinaryOperatorKind.NullableNullNotEqual)); conditionalAccess = conditionalAccess.Update(conditionalAccess.Receiver, accessExpression, accessExpression.Type); var whenNull = operatorKind == BinaryOperatorKind.NullableNullEqual ? MakeBooleanConstant(syntax, true) : null; return RewriteConditionalAccess(conditionalAccess, used: true, rewrittenWhenNull: whenNull); } } } } else { var unliftedOperatorKind = node.OperatorKind.Unlifted(); if (unliftedOperatorKind.IsComparison() && TryGetOptimizableNullableConditionalAccess(left, out conditionalAccess)) { var rightAlwaysHasValue = NullableAlwaysHasValue(VisitExpression(right)); // reading rightAlwaysHasValue should not have sideeffects here // otherwise we would need to read it even when we knew that LHS is null if (rightAlwaysHasValue != null && !IntroducingReadCanBeObservable(rightAlwaysHasValue)) { BoundExpression accessExpression = conditionalAccess.AccessExpression; accessExpression = node.Update(unliftedOperatorKind, accessExpression, rightAlwaysHasValue, null, node.MethodOpt, node.ResultKind, node.Type); conditionalAccess = conditionalAccess.Update(conditionalAccess.Receiver, accessExpression, accessExpression.Type); var whenNull = unliftedOperatorKind.Operator() == BinaryOperatorKind.NotEqual ? MakeBooleanConstant(syntax, true) : null; return RewriteConditionalAccess(conditionalAccess, used: true, rewrittenWhenNull: whenNull); } } } return null; }
private BoundNode VisitBinaryOperatorBase(BoundBinaryOperatorBase binaryOperator) { // Use an explicit stack to avoid blowing the managed stack when visiting deeply-recursive // binary nodes var stack = ArrayBuilder <BoundBinaryOperatorBase> .GetInstance(); BoundBinaryOperatorBase?currentBinary = binaryOperator; do { stack.Push(currentBinary); currentBinary = currentBinary.Left as BoundBinaryOperatorBase; }while (currentBinary is object); Debug.Assert(stack.Count > 0); var leftChild = (BoundExpression)Visit(stack.Peek().Left); do { currentBinary = stack.Pop(); bool foundInfo = _updatedNullabilities.TryGetValue(currentBinary, out (NullabilityInfo Info, TypeSymbol? Type)infoAndType); var right = (BoundExpression)Visit(currentBinary.Right); var type = foundInfo ? infoAndType.Type : currentBinary.Type; currentBinary = currentBinary switch { BoundBinaryOperator binary => binary.Update( binary.OperatorKind, BoundBinaryOperator.UncommonData.CreateIfNeeded(binary.ConstantValue, GetUpdatedSymbol(binary, binary.Method), binary.ConstrainedToType, binary.OriginalUserDefinedOperatorsOpt), binary.ResultKind, leftChild, right, type !), // https://github.com/dotnet/roslyn/issues/35031: We'll need to update logical.LogicalOperator BoundUserDefinedConditionalLogicalOperator logical => logical.Update(logical.OperatorKind, logical.LogicalOperator, logical.TrueOperator, logical.FalseOperator, logical.ConstrainedToTypeOpt, logical.ResultKind, logical.OriginalUserDefinedOperatorsOpt, leftChild, right, type !), _ => throw ExceptionUtilities.UnexpectedValue(currentBinary.Kind), }; if (foundInfo) { currentBinary.TopLevelNullability = infoAndType.Info; } leftChild = currentBinary; }while (stack.Count > 0); Debug.Assert(currentBinary != null); return(currentBinary !); }
private BoundNode VisitBinaryOperatorBase(BoundBinaryOperatorBase binaryOperator) { // Use an explicit stack to avoid blowing the managed stack when visiting deeply-recursive // binary nodes var stack = ArrayBuilder <BoundBinaryOperatorBase> .GetInstance(); BoundBinaryOperatorBase?currentBinary = binaryOperator; do { stack.Push(currentBinary); currentBinary = currentBinary.Left as BoundBinaryOperatorBase; }while (currentBinary is object); Debug.Assert(stack.Count > 0); var leftChild = (BoundExpression)Visit(stack.Peek().Left); do { currentBinary = stack.Pop(); bool foundInfo = _updatedNullabilities.TryGetValue(currentBinary, out (NullabilityInfo Info, TypeSymbol Type)infoAndType); var right = (BoundExpression)Visit(currentBinary.Right); var type = foundInfo ? infoAndType.Type : currentBinary.Type; #pragma warning disable IDE0055 // Fix formatting // https://github.com/dotnet/roslyn/issues/35031: We'll need to update the symbols for the internal methods/operators used in the binary operators currentBinary = currentBinary switch { BoundBinaryOperator binary => (BoundBinaryOperatorBase)binary.Update(binary.OperatorKind, binary.ConstantValueOpt, binary.MethodOpt, binary.ResultKind, leftChild, right, type), BoundUserDefinedConditionalLogicalOperator logical => logical.Update(logical.OperatorKind, logical.LogicalOperator, logical.TrueOperator, logical.FalseOperator, logical.ResultKind, leftChild, right, type), _ => throw ExceptionUtilities.UnexpectedValue(currentBinary.Kind), }; #pragma warning restore IDE0055 // Fix formatting if (foundInfo) { currentBinary.TopLevelNullability = infoAndType.Info; } leftChild = currentBinary; }while (stack.Count > 0); Debug.Assert(currentBinary != null); return(currentBinary); }
public sealed override BoundNode VisitBinaryOperator(BoundBinaryOperator node) { BoundExpression child = node.Left; if (child.Kind != BoundKind.BinaryOperator) { return(base.VisitBinaryOperator(node)); } var stack = ArrayBuilder <BoundBinaryOperator> .GetInstance(); stack.Push(node); BoundBinaryOperator binary = (BoundBinaryOperator)child; while (true) { stack.Push(binary); child = binary.Left; if (child.Kind != BoundKind.BinaryOperator) { break; } binary = (BoundBinaryOperator)child; } var left = (BoundExpression)this.Visit(child); do { binary = stack.Pop(); var right = (BoundExpression)this.Visit(binary.Right); var type = this.VisitType(binary.Type); left = binary.Update(binary.OperatorKind, binary.ConstantValueOpt, binary.MethodOpt, binary.ResultKind, binary.OriginalUserDefinedOperatorsOpt, left, right, type); }while (stack.Count > 0); Debug.Assert((object)binary == node); stack.Free(); return(left); }
/// <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); }
private BoundExpression RewriteStringEquality(BoundBinaryOperator oldNode, CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type, SpecialMember member) { if (oldNode != null && (loweredLeft.ConstantValue == ConstantValue.Null || loweredRight.ConstantValue == ConstantValue.Null)) { return oldNode.Update(operatorKind, loweredLeft, loweredRight, oldNode.ConstantValueOpt, oldNode.MethodOpt, oldNode.ResultKind, type); } var method = GetSpecialTypeMethod(syntax, member); Debug.Assert((object)method != null); return BoundCall.Synthesized(syntax, null, method, loweredLeft, loweredRight); }
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); }
public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) { BoundSpillSequence2 ss = null; var right = VisitExpression(ref ss, node.Right); BoundExpression left; if (ss == null) { left = VisitExpression(ref ss, node.Left); } else { var ssLeft = new BoundSpillSequence2(); left = VisitExpression(ref ssLeft, node.Left); left = Spill(ssLeft, left); if (node.OperatorKind == BinaryOperatorKind.LogicalBoolOr || node.OperatorKind == BinaryOperatorKind.LogicalBoolAnd) { ssLeft.Add(F.If( node.OperatorKind == BinaryOperatorKind.LogicalBoolAnd ? left : F.Not(left), UpdateStatement(ss, F.Assignment(left, right)) )); return UpdateExpression(ssLeft, left); } else { // if the right-hand-side has await, spill the left ssLeft.IncludeSequence(ss); ss = ssLeft; } } return UpdateExpression(ss, node.Update(node.OperatorKind, left, right, node.ConstantValue, node.MethodOpt, node.ResultKind, node.Type)); }
public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) { BoundExpression left = (BoundExpression)this.Visit(node.Left); BoundExpression right = (BoundExpression)this.Visit(node.Right); TypeSymbol type = this.VisitType(node.Type); if (!RequiresSpill(left, right)) { return node.Update(node.OperatorKind, left, right, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, type); } var subExprs = ReadOnlyArray<BoundExpression>.CreateFrom(left, right); var spillBuilder = new SpillBuilder(); var newArgs = SpillExpressionList(spillBuilder, subExprs); Debug.Assert(newArgs.Count == 2); var newBinaryOperator = node.Update( node.OperatorKind, newArgs[0], newArgs[1], node.ConstantValueOpt, node.MethodOpt, node.ResultKind, type); return spillBuilder.BuildSequenceAndFree(F, newBinaryOperator); }