private void CheckCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { BoundExpression left = node.Left; if ( !node.Operator.Kind.IsDynamic() && !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); if (_inExpressionLambda) { Error(ErrorCode.ERR_ExpressionTreeContainsAssignment, node); } }
private void CheckCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { BoundExpression left = node.Left; if (!node.Operator.Kind.IsDynamic() && node.LeftConversion is BoundConversion { Conversion : { IsIdentity : false, Exists : true } conversion })
public override BoundNode VisitCompoundAssignmentOperator( BoundCompoundAssignmentOperator node ) { CheckCompoundAssignmentOperator(node); return(base.VisitCompoundAssignmentOperator(node)); }
public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { CheckLiftedCompoundAssignment(node); if (_inExpressionLambda) { Error(ErrorCode.ERR_ExpressionTreeContainsAssignment, node); } return(base.VisitCompoundAssignmentOperator(node)); }
private void CheckCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { CheckForBitwiseOrSignExtend(node, node.Operator.Kind, node.Left, node.Right); CheckLiftedCompoundAssignment(node); if (_inExpressionLambda) { Error(ErrorCode.ERR_ExpressionTreeContainsAssignment, node); } }
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 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); Debug.Assert(rewrittenAssignment.Type is { });
public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { CheckLiftedCompoundAssignment(node); if (inExpressionLambda) { Error(ErrorCode.ERR_ExpressionTreeContainsAssignment, node); } return base.VisitCompoundAssignmentOperator(node); }
private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node, bool used) { Debug.Assert(node.Right.Type == node.Operator.RightType); 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(); // if LHS is a member access and the operation is += or -=, we need to check at runtime if the LHS is an event. // We rewrite dyn.Member op= RHS to the following: // // IsEvent("Member", dyn) ? InvokeMember("{add|remove}_Member", dyn, RHS) : SetMember(BinaryOperation("op=", GetMember("Member", dyn)), RHS) // bool isPossibleEventHandlerOperation = node.Left.Kind == BoundKind.DynamicMemberAccess && (binaryOperator == BinaryOperatorKind.Addition || binaryOperator == BinaryOperatorKind.Subtraction); // save RHS to a temp, we need to use it twice: if (isPossibleEventHandlerOperation && CanChangeValueBetweenReads(loweredRight)) { BoundAssignmentOperator assignmentToTemp; var temp = _factory.StoreToTemp(loweredRight, out assignmentToTemp); loweredRight = temp; stores.Add(assignmentToTemp); temps.Add(temp.LocalSymbol); } // 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); 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.) var lhsRead = MakeRValue(transformedLHS); BoundExpression opLHS = isDynamic ? lhsRead : MakeConversionNode( syntax: syntax, rewrittenOperand: lhsRead, 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); BoundExpression rewrittenAssignment = MakeAssignmentOperator(syntax, transformedLHS, opFinal, node.Left.Type, used: used, isChecked: isChecked, isCompoundAssignment: true); // OK, at this point we have: // // * temps evaluating and storing portions of the LHS that must be evaluated only once. // * the "transformed" left hand side, rebuilt to use temps where necessary // * the assignment "xlhs = (FINAL)((LEFT)xlhs op (RIGHT)rhs)" // // Notice that we have recursively rewritten the bound nodes that are things stored in // the temps, and by calling the "Make" methods we have rewritten the conversions and // assignments too, if necessary. if (isPossibleEventHandlerOperation) { // IsEvent("Foo", dyn) ? InvokeMember("{add|remove}_Foo", dyn, RHS) : rewrittenAssignment var memberAccess = (BoundDynamicMemberAccess)transformedLHS; var isEventCondition = _dynamicFactory.MakeDynamicIsEventTest(memberAccess.Name, memberAccess.Receiver); var invokeEventAccessor = _dynamicFactory.MakeDynamicEventAccessorInvocation( (binaryOperator == BinaryOperatorKind.Addition ? "add_" : "remove_") + memberAccess.Name, memberAccess.Receiver, loweredRight); rewrittenAssignment = _factory.Conditional(isEventCondition.ToExpression(), invokeEventAccessor.ToExpression(), rewrittenAssignment, rewrittenAssignment.Type); } BoundExpression result = (temps.Count == 0 && stores.Count == 0) ? rewrittenAssignment : new BoundSequence( syntax, temps.ToImmutable(), stores.ToImmutable(), rewrittenAssignment, rewrittenAssignment.Type); temps.Free(); stores.Free(); return(result); }
public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { return(VisitCompoundAssignmentOperator(node, true)); }
private static void GetSymbolsAndResultKind(BoundCompoundAssignmentOperator compoundAssignment, out bool isDynamic, ref LookupResultKind resultKind, ref ImmutableArray<Symbol> symbols) { BinaryOperatorKind operandType = compoundAssignment.Operator.Kind.OperandTypes(); BinaryOperatorKind op = compoundAssignment.Operator.Kind.Operator(); isDynamic = compoundAssignment.Operator.Kind.IsDynamic(); if (operandType == 0 || operandType == BinaryOperatorKind.UserDefined || compoundAssignment.ResultKind != LookupResultKind.Viable) { if (!isDynamic) { GetSymbolsAndResultKind(compoundAssignment, compoundAssignment.Operator.Method, compoundAssignment.OriginalUserDefinedOperatorsOpt, out symbols, out resultKind); } } else { Debug.Assert((object)compoundAssignment.Operator.Method == null && compoundAssignment.OriginalUserDefinedOperatorsOpt.IsDefaultOrEmpty); symbols = ImmutableArray.Create(GetIntrinsicOperatorSymbol(op, isDynamic, compoundAssignment.Operator.LeftType, compoundAssignment.Operator.RightType, compoundAssignment.Operator.ReturnType, compoundAssignment.Operator.Kind.IsChecked())); resultKind = compoundAssignment.ResultKind; } }
public override BoundNode?VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { _mightAssignSomething = true; return(null); }
public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { CheckCompoundAssignmentOperator(node); return base.VisitCompoundAssignmentOperator(node); }
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 void CheckCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { CheckForBitwiseOrSignExtend(node, node.Operator.Kind, node.Left, node.Right); CheckLiftedCompoundAssignment(node); if (_inExpressionLambda) { Error(ErrorCode.ERR_ExpressionTreeContainsAssignment, node); } }
private void CheckCompoundAssignmentOperator(BoundCompoundAssignmentOperator node) { BoundExpression left = node.Left; if (!node.Operator.Kind.IsDynamic() && !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, constantValueOpt: null, type: node.Operator.LeftType); } CheckForBitwiseOrSignExtend(node, node.Operator.Kind, left, node.Right); CheckLiftedCompoundAssignment(node); if (_inExpressionLambda) { Error(ErrorCode.ERR_ExpressionTreeContainsAssignment, node); } }
private BoundExpression VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node, bool used) { Debug.Assert(node.Right.Type == node.Operator.RightType); 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(); // if LHS is a member access and the operation is += or -=, we need to check at runtime if the LHS is an event. // We rewrite dyn.Member op= RHS to the following: // // IsEvent("Member", dyn) ? InvokeMember("{add|remove}_Member", dyn, RHS) : SetMember(BinaryOperation("op=", GetMember("Member", dyn)), RHS) // bool isPossibleEventHandlerOperation = node.Left.Kind == BoundKind.DynamicMemberAccess && (binaryOperator == BinaryOperatorKind.Addition || binaryOperator == BinaryOperatorKind.Subtraction); // save RHS to a temp, we need to use it twice: if (isPossibleEventHandlerOperation && NeedsTemp(loweredRight, localsMayBeAssigned: false)) { BoundAssignmentOperator assignmentToTemp; var temp = this.factory.StoreToTemp(loweredRight, out assignmentToTemp); loweredRight = temp; stores.Add(assignmentToTemp); temps.Add(temp.LocalSymbol); } // 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); CSharpSyntaxNode 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.) var lhsRead = MakeRValue(transformedLHS); BoundExpression opLHS = isDynamic ? lhsRead : MakeConversion( syntax: syntax, rewrittenOperand: lhsRead, 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 = MakeConversion( syntax: syntax, rewrittenOperand: operand, conversion: node.FinalConversion, rewrittenType: node.Left.Type, explicitCastInCode: isDynamic, @checked: isChecked); BoundExpression rewrittenAssignment = MakeAssignmentOperator(syntax, transformedLHS, opFinal, node.Left.Type, used: used, isChecked: isChecked, isCompoundAssignment: true); // OK, at this point we have: // // * temps evaluating and storing portions of the LHS that must be evaluated only once. // * the "transformed" left hand side, rebuilt to use temps where necessary // * the assignment "xlhs = (FINAL)((LEFT)xlhs op (RIGHT)rhs)" // // Notice that we have recursively rewritten the bound nodes that are things stored in // the temps, and by calling the "Make" methods we have rewritten the conversions and // assignments too, if necessary. if (isPossibleEventHandlerOperation) { // IsEvent("Foo", dyn) ? InvokeMember("{add|remove}_Foo", dyn, RHS) : rewrittenAssignment var memberAccess = (BoundDynamicMemberAccess)transformedLHS; var isEventCondition = dynamicFactory.MakeDynamicIsEventTest(memberAccess.Name, memberAccess.Receiver); var invokeEventAccessor = dynamicFactory.MakeDynamicEventAccessorInvocation( (binaryOperator == BinaryOperatorKind.Addition ? "add_" : "remove_") + memberAccess.Name, memberAccess.Receiver, loweredRight); rewrittenAssignment = factory.Conditional(isEventCondition.ToExpression(), invokeEventAccessor.ToExpression(), rewrittenAssignment, rewrittenAssignment.Type); } BoundExpression result = (temps.Count == 0 && stores.Count == 0) ? rewrittenAssignment : new BoundSequence( syntax, temps.ToImmutable(), stores.ToImmutable(), rewrittenAssignment, rewrittenAssignment.Type); temps.Free(); stores.Free(); return result; }
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); } }