private void CheckLiftedCompoundAssignment(BoundCompoundAssignmentOperator node) { Debug.Assert(node != null); if (!node.Operator.Kind.IsLifted()) { return; } // CS0458: The result of the expression is always 'null' of type '{0}' if (node.Right.NullableNeverHasValue()) { Error(ErrorCode.WRN_AlwaysNull, node, node.Type); } }
private void CheckCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { BoundExpression left = node.Left; if (!node.LeftConversion.IsIdentity && node.LeftConversion.Exists) { // Need to represent the implicit conversion as a node in order to be able to produce correct diagnostics. left = new BoundConversion(left.Syntax, left, node.LeftConversion, node.Operator.Kind.IsChecked(), explicitCastInCode: false, conversionGroupOpt: null, constantValueOpt: null, type: node.Operator.LeftType); } CheckForBitwiseOrSignExtend(node, node.Operator.Kind, left, node.Right); CheckLiftedCompoundAssignment(node); }
public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { CheckCompoundAssignmentOperator(node); return(base.VisitCompoundAssignmentOperator(node)); }
public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { _mightAssignSomething = true; return(null); }
private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node, bool used) { Debug.Assert(TypeSymbol.Equals(node.Right.Type, node.Operator.RightType, TypeCompareKind.ConsiderEverything2)); BoundExpression loweredRight = VisitExpression(node.Right); var temps = ArrayBuilder <LocalSymbol> .GetInstance(); var stores = ArrayBuilder <BoundExpression> .GetInstance(); var kind = node.Operator.Kind; bool isChecked = kind.IsChecked(); bool isDynamic = kind.IsDynamic(); var binaryOperator = kind.Operator(); // This will be filled in with the LHS that uses temporaries to prevent // double-evaluation of side effects. BoundExpression transformedLHS = TransformCompoundAssignmentLHS(node.Left, stores, temps, isDynamic); var lhsRead = MakeRValue(transformedLHS); BoundExpression rewrittenAssignment; if (node.Left.Kind == BoundKind.DynamicMemberAccess && (binaryOperator == BinaryOperatorKind.Addition || binaryOperator == BinaryOperatorKind.Subtraction)) { // If this could be an event assignment at runtime, we need to rewrite to the following form: // Original: // receiver.EV += handler // Rewritten: // dynamic memberAccessReceiver = receiver; // bool isEvent = Runtime.IsEvent(memberAccessReceiver, "EV"); // dynamic storeNonEvent = !isEvent ? memberAccessReceiver.EV : null; // var loweredRight = handler; // Only necessary if handler can change values, or is something like a lambda // isEvent ? add_Event(memberAccessReceiver, "EV", loweredRight) : transformedLHS = storeNonEvent + loweredRight; // // This is to ensure that if handler is something like a lambda, we evaluate fully evaluate the left // side before storing the lambda to a temp for use in both possible branches. // The first store to memberAccessReceiver has already been taken care of above by TransformCompoundAssignmentLHS var eventTemps = ArrayBuilder <LocalSymbol> .GetInstance(); var sequence = ArrayBuilder <BoundExpression> .GetInstance(); // dynamic memberAccessReceiver = receiver; var memberAccess = (BoundDynamicMemberAccess)transformedLHS; // bool isEvent = Runtime.IsEvent(memberAccessReceiver, "EV"); var isEvent = _factory.StoreToTemp(_dynamicFactory.MakeDynamicIsEventTest(memberAccess.Name, memberAccess.Receiver).ToExpression(), out BoundAssignmentOperator isEventAssignment); eventTemps.Add(isEvent.LocalSymbol); sequence.Add(isEventAssignment); // dynamic storeNonEvent = !isEvent ? memberAccessReceiver.EV : null; lhsRead = _factory.StoreToTemp(lhsRead, out BoundAssignmentOperator receiverAssignment); eventTemps.Add(((BoundLocal)lhsRead).LocalSymbol); var storeNonEvent = _factory.StoreToTemp(_factory.Conditional(_factory.Not(isEvent), receiverAssignment, _factory.Null(receiverAssignment.Type), receiverAssignment.Type), out BoundAssignmentOperator nonEventStore); eventTemps.Add(storeNonEvent.LocalSymbol); sequence.Add(nonEventStore); // var loweredRight = handler; if (CanChangeValueBetweenReads(loweredRight)) { loweredRight = _factory.StoreToTemp(loweredRight, out BoundAssignmentOperator possibleHandlerAssignment); eventTemps.Add(((BoundLocal)loweredRight).LocalSymbol); sequence.Add(possibleHandlerAssignment); } // add_Event(t1, "add_EV"); var invokeEventAccessor = _dynamicFactory.MakeDynamicEventAccessorInvocation( (binaryOperator == BinaryOperatorKind.Addition ? "add_" : "remove_") + memberAccess.Name, memberAccess.Receiver, loweredRight); // transformedLHS = storeNonEvent + loweredRight rewrittenAssignment = rewriteAssignment(lhsRead); // Final conditional var condition = _factory.Conditional(isEvent, invokeEventAccessor.ToExpression(), rewrittenAssignment, rewrittenAssignment.Type); rewrittenAssignment = new BoundSequence(node.Syntax, eventTemps.ToImmutableAndFree(), sequence.ToImmutableAndFree(), condition, condition.Type); } else { rewrittenAssignment = rewriteAssignment(lhsRead); } BoundExpression result = (temps.Count == 0 && stores.Count == 0) ? rewrittenAssignment : new BoundSequence( node.Syntax, temps.ToImmutable(), stores.ToImmutable(), rewrittenAssignment, rewrittenAssignment.Type); temps.Free(); stores.Free(); return(result); BoundExpression rewriteAssignment(BoundExpression leftRead) { SyntaxNode syntax = node.Syntax; // OK, we now have the temporary declarations, the temporary stores, and the transformed left hand side. // We need to generate // // xlhs = (FINAL)((LEFT)xlhs op rhs) // // And then wrap it up with the generated temporaries. // // (The right hand side has already been converted to the type expected by the operator.) BoundExpression opLHS = isDynamic ? leftRead : MakeConversionNode( syntax: syntax, rewrittenOperand: leftRead, conversion: node.LeftConversion, rewrittenType: node.Operator.LeftType, @checked: isChecked); BoundExpression operand = MakeBinaryOperator(syntax, node.Operator.Kind, opLHS, loweredRight, node.Operator.ReturnType, node.Operator.Method, isCompoundAssignment: true); BoundExpression opFinal = MakeConversionNode( syntax: syntax, rewrittenOperand: operand, conversion: node.FinalConversion, rewrittenType: node.Left.Type, explicitCastInCode: isDynamic, @checked: isChecked); return(MakeAssignmentOperator(syntax, transformedLHS, opFinal, node.Left.Type, used: used, isChecked: isChecked, isCompoundAssignment: true)); } }
public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { return(VisitCompoundAssignmentOperator(node, true)); }
private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node, bool used) { Debug.Assert(TypeSymbol.Equals(node.Right.Type, node.Operator.RightType, TypeCompareKind.ConsiderEverything2)); BoundExpression loweredRight = VisitExpression(node.Right); var temps = ArrayBuilder <LocalSymbol> .GetInstance(); var stores = ArrayBuilder <BoundExpression> .GetInstance(); var kind = node.Operator.Kind; bool isChecked = kind.IsChecked(); var binaryOperator = kind.Operator(); // This will be filled in with the LHS that uses temporaries to prevent // double-evaluation of side effects. BoundExpression transformedLHS = TransformCompoundAssignmentLHS(node.Left, stores, temps); var lhsRead = MakeRValue(transformedLHS); BoundExpression rewrittenAssignment; rewrittenAssignment = rewriteAssignment(lhsRead); BoundExpression result = (temps.Count == 0 && stores.Count == 0) ? rewrittenAssignment : new BoundSequence( node.Syntax, temps.ToImmutable(), stores.ToImmutable(), rewrittenAssignment, rewrittenAssignment.Type); temps.Free(); stores.Free(); return(result); BoundExpression rewriteAssignment(BoundExpression leftRead) { SyntaxNode syntax = node.Syntax; // OK, we now have the temporary declarations, the temporary stores, and the transformed left hand side. // We need to generate // // xlhs = (FINAL)((LEFT)xlhs op rhs) // // And then wrap it up with the generated temporaries. // // (The right hand side has already been converted to the type expected by the operator.) BoundExpression opLHS = MakeConversionNode( syntax: syntax, rewrittenOperand: leftRead, conversion: node.LeftConversion, rewrittenType: node.Operator.LeftType, @checked: isChecked); BoundExpression operand = MakeBinaryOperator(syntax, node.Operator.Kind, opLHS, loweredRight, node.Operator.ReturnType, node.Operator.Method, isCompoundAssignment: true); BoundExpression opFinal = MakeConversionNode( syntax: syntax, rewrittenOperand: operand, conversion: node.FinalConversion, rewrittenType: node.Left.Type, explicitCastInCode: false, @checked: isChecked); return(MakeAssignmentOperator(syntax, transformedLHS, opFinal, node.Left.Type, used: used, isChecked: isChecked, isCompoundAssignment: true)); } }