private void CheckDynamic(BoundUnaryOperator node) { if (_inExpressionLambda && node.OperatorKind.IsDynamic()) { Error(ErrorCode.ERR_ExpressionTreeContainsDynamicOperation, node); } }
/// <summary> /// This rewriter lowers pre-/post- increment/decrement operations (initially represented as /// unary operators). We use BoundSequenceExpressions because we need to capture the RHS of the /// assignment in a temp variable. /// </summary> /// <remarks> /// This rewriter assumes that it will be run before decimal rewriting (so that it does not have /// to lower decimal constants and operations) and call rewriting (so that it does not have to /// lower property accesses). /// </remarks> public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { switch (node.OperatorKind.Operator()) { case UnaryOperatorKind.PrefixDecrement: case UnaryOperatorKind.PrefixIncrement: case UnaryOperatorKind.PostfixDecrement: case UnaryOperatorKind.PostfixIncrement: Debug.Assert(false); // these should have been represented as a BoundIncrementOperator return base.VisitUnaryOperator(node); } // TODO(tomat): We need to pass a parent operator kind into binary operator visitor. // We circumvent logic in VisitExpression. The extra logic doesn't apply under these conditions so we are ok. // This is a bit fragile however. Consider refactoring VisitExpression. if (node.Operand.Kind == BoundKind.BinaryOperator) { // Optimization: // Binary operator lowering combines the binary operator with IsTrue/IsFalse more efficiently than we can do here. var binaryOperator = (BoundBinaryOperator)node.Operand; if (node.OperatorKind == UnaryOperatorKind.DynamicTrue && binaryOperator.OperatorKind == BinaryOperatorKind.DynamicLogicalOr || node.OperatorKind == UnaryOperatorKind.DynamicFalse && binaryOperator.OperatorKind == BinaryOperatorKind.DynamicLogicalAnd) { return VisitBinaryOperator(binaryOperator, applyParentUnaryOperator: node); } } BoundExpression loweredOperand = VisitExpression(node.Operand); return MakeUnaryOperator(node, node.OperatorKind, node.Syntax, node.MethodOpt, loweredOperand, node.Type); }
public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { BoundSpillSequenceBuilder builder = null; BoundExpression operand = VisitExpression(ref builder, node.Operand); return(UpdateExpression(builder, node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, node.Type))); }
public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { CheckUnsafeType(node); CheckLiftedUnaryOp(node); CheckDynamic(node); return(base.VisitUnaryOperator(node)); }
/// <summary> /// This rewriter lowers pre-/post- increment/decrement operations (initially represented as /// unary operators). We use BoundSequenceExpressions because we need to capture the RHS of the /// assignment in a temp variable. /// </summary> /// <remarks> /// This rewriter assumes that it will be run before decimal rewriting (so that it does not have /// to lower decimal constants and operations) and call rewriting (so that it does not have to /// lower property accesses). /// </remarks> public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { switch (node.OperatorKind.Operator()) { case UnaryOperatorKind.PrefixDecrement: case UnaryOperatorKind.PrefixIncrement: case UnaryOperatorKind.PostfixDecrement: case UnaryOperatorKind.PostfixIncrement: Debug.Assert(false); // these should have been represented as a BoundIncrementOperator return(base.VisitUnaryOperator(node)); } // TODO(tomat): We need to pass a parent operator kind into binary operator visitor. // We circumvent logic in VisitExpression. The extra logic doesn't apply under these conditions so we are ok. // This is a bit fragile however. Consider refactoring VisitExpression. if (node.Operand.Kind == BoundKind.BinaryOperator) { // Optimization: // Binary operator lowering combines the binary operator with IsTrue/IsFalse more efficiently than we can do here. var binaryOperator = (BoundBinaryOperator)node.Operand; if (node.OperatorKind == UnaryOperatorKind.DynamicTrue && binaryOperator.OperatorKind == BinaryOperatorKind.DynamicLogicalOr || node.OperatorKind == UnaryOperatorKind.DynamicFalse && binaryOperator.OperatorKind == BinaryOperatorKind.DynamicLogicalAnd) { return(VisitBinaryOperator(binaryOperator, applyParentUnaryOperator: node)); } } BoundExpression loweredOperand = VisitExpression(node.Operand); return(MakeUnaryOperator(node, node.OperatorKind, node.Syntax, node.MethodOpt, loweredOperand, node.Type)); }
public BoundExpression VisitBinaryOperator(BoundBinaryOperator node, BoundUnaryOperator applyParentUnaryOperator = null) { // In machine-generated code we frequently end up with binary operator trees that are deep on the left, // such as a + b + c + d ... // To avoid blowing the call stack, we make an explicit stack of the binary operators to the left, // and then lower by traversing the explicit stack. var stack = ArrayBuilder<BoundBinaryOperator>.GetInstance(); for (BoundBinaryOperator current = node; current != null; current = current.Left as BoundBinaryOperator) { stack.Push(current); } BoundExpression loweredLeft = VisitExpression(stack.Peek().Left); while (stack.Count > 0) { BoundBinaryOperator original = stack.Pop(); BoundExpression loweredRight = VisitExpression(original.Right); loweredLeft = MakeBinaryOperator(original, original.Syntax, original.OperatorKind, loweredLeft, loweredRight, original.Type, original.MethodOpt, applyParentUnaryOperator: (stack.Count == 0) ? applyParentUnaryOperator : null); } stack.Free(); return loweredLeft; }
private BoundExpression MakeBinaryOperator( CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type, MethodSymbol method, bool isPointerElementAccess = false, bool isCompoundAssignment = false, BoundUnaryOperator applyParentUnaryOperator = null) { return MakeBinaryOperator(null, syntax, operatorKind, loweredLeft, loweredRight, type, method, isPointerElementAccess, isCompoundAssignment, applyParentUnaryOperator); }
private void CheckLiftedUnaryOp(BoundUnaryOperator node) { Debug.Assert(node != null); if (!node.OperatorKind.IsLifted()) { return; } // CS0458: The result of the expression is always 'null' of type '{0}' if (node.Operand.NullableNeverHasValue()) { Error(ErrorCode.WRN_AlwaysNull, node, node.Type); } }
private BoundExpression VisitUnaryOperator(BoundUnaryOperator node) { var arg = node.Operand; var loweredArg = Visit(arg); var opKind = node.OperatorKind; var op = opKind & UnaryOperatorKind.OpMask; var isChecked = (opKind & UnaryOperatorKind.Checked) != 0; string opname; switch (op) { case UnaryOperatorKind.UnaryPlus: if ((object)node.MethodOpt == null) { return(loweredArg); } opname = "UnaryPlus"; break; case UnaryOperatorKind.UnaryMinus: opname = isChecked ? "NegateChecked" : "Negate"; break; case UnaryOperatorKind.BitwiseComplement: case UnaryOperatorKind.LogicalNegation: opname = "Not"; break; default: throw ExceptionUtilities.UnexpectedValue(op); } if (node.OperatorKind.OperandTypes() == UnaryOperatorKind.Enum && (opKind & UnaryOperatorKind.Lifted) != 0) { Debug.Assert((object)node.MethodOpt == null); var promotedType = PromotedType(arg.Type.StrippedType().GetEnumUnderlyingType()); promotedType = _nullableType.Construct(promotedType); loweredArg = Convert(loweredArg, arg.Type, promotedType, isChecked, false); var result = ExprFactory(opname, loweredArg); return(Demote(result, node.Type, isChecked)); } return(((object)node.MethodOpt == null) ? ExprFactory(opname, loweredArg) : ExprFactory(opname, loweredArg, _bound.MethodInfo(node.MethodOpt))); }
public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { BoundExpression operand = (BoundExpression)this.Visit(node.Operand); TypeSymbol type = this.VisitType(node.Type); if (operand.Kind != BoundKind.SpillSequence) { return node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, type); } var spill = (BoundSpillSequence)operand; return RewriteSpillSequence(spill, node.Update( node.OperatorKind, spill.Value, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, type)); }
public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { BoundExpression operand = (BoundExpression)this.Visit(node.Operand); TypeSymbol type = this.VisitType(node.Type); if (operand.Kind != BoundKind.SpillSequence) { return(node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, type)); } var spill = (BoundSpillSequence)operand; return(RewriteSpillSequence(spill, node.Update( node.OperatorKind, spill.Value, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, type))); }
public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { BoundSpillSequence2 ss = null; BoundExpression operand = VisitExpression(ref ss, node.Operand); return UpdateExpression(ss, node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, node.Type)); }
private BoundExpression MakeUnaryOperator( BoundUnaryOperator oldNode, UnaryOperatorKind kind, CSharpSyntaxNode syntax, MethodSymbol method, BoundExpression loweredOperand, TypeSymbol type) { if (kind.IsDynamic()) { Debug.Assert(kind == UnaryOperatorKind.DynamicTrue && type.SpecialType == SpecialType.System_Boolean || type.IsDynamic()); Debug.Assert((object)method == null); // Logical operators on boxed Boolean constants: var constant = UnboxConstant(loweredOperand); if (constant == ConstantValue.True || constant == ConstantValue.False) { if (kind == UnaryOperatorKind.DynamicTrue) { return _factory.Literal(constant.BooleanValue); } else if (kind == UnaryOperatorKind.DynamicLogicalNegation) { return MakeConversionNode(_factory.Literal(!constant.BooleanValue), type, @checked: false); } } return _dynamicFactory.MakeDynamicUnaryOperator(kind, loweredOperand, type).ToExpression(); } else if (kind.IsLifted()) { if (!_inExpressionLambda) { return LowerLiftedUnaryOperator(kind, syntax, method, loweredOperand, type); } } else if (kind.IsUserDefined()) { Debug.Assert((object)method != null); Debug.Assert(type == method.ReturnType); if (!_inExpressionLambda || kind == UnaryOperatorKind.UserDefinedTrue || kind == UnaryOperatorKind.UserDefinedFalse) { return BoundCall.Synthesized(syntax, null, method, loweredOperand); } } else if (kind.Operator() == UnaryOperatorKind.UnaryPlus) { // We do not call the operator even for decimal; we simply optimize it away entirely. return loweredOperand; } if (kind == UnaryOperatorKind.EnumBitwiseComplement) { var underlyingType = loweredOperand.Type.GetEnumUnderlyingType(); var upconvertSpecialType = Binder.GetEnumPromotedType(underlyingType.SpecialType); var upconvertType = upconvertSpecialType == underlyingType.SpecialType ? underlyingType : _compilation.GetSpecialType(upconvertSpecialType); var newOperand = MakeConversionNode(loweredOperand, upconvertType, false); UnaryOperatorKind newKind = kind.Operator().WithType(upconvertSpecialType); var newNode = (oldNode != null) ? oldNode.Update( newKind, newOperand, oldNode.ConstantValueOpt, method, newOperand.ResultKind, upconvertType) : new BoundUnaryOperator( syntax, newKind, newOperand, null, method, LookupResultKind.Viable, upconvertType); return MakeConversionNode(newNode.Syntax, newNode, Conversion.ExplicitEnumeration, type, @checked: false); } if (kind == UnaryOperatorKind.DecimalUnaryMinus) { method = (MethodSymbol)_compilation.Assembly.GetSpecialTypeMember(SpecialMember.System_Decimal__op_UnaryNegation); if (!_inExpressionLambda) { return BoundCall.Synthesized(syntax, null, method, loweredOperand); } } return (oldNode != null) ? oldNode.Update(kind, loweredOperand, oldNode.ConstantValueOpt, method, oldNode.ResultKind, type) : new BoundUnaryOperator(syntax, kind, loweredOperand, null, method, LookupResultKind.Viable, type); }
private BoundExpression MakeUnaryOperator( BoundUnaryOperator oldNode, UnaryOperatorKind kind, CSharpSyntaxNode syntax, MethodSymbol method, BoundExpression loweredOperand, TypeSymbol type) { if (kind.IsDynamic()) { Debug.Assert(kind == UnaryOperatorKind.DynamicTrue && type.SpecialType == SpecialType.System_Boolean || type.IsDynamic()); Debug.Assert((object)method == null); // Logical operators on boxed Boolean constants: var constant = UnboxConstant(loweredOperand); if (constant == ConstantValue.True || constant == ConstantValue.False) { if (kind == UnaryOperatorKind.DynamicTrue) { return(_factory.Literal(constant.BooleanValue)); } else if (kind == UnaryOperatorKind.DynamicLogicalNegation) { return(MakeConversionNode(_factory.Literal(!constant.BooleanValue), type, @checked: false)); } } return(_dynamicFactory.MakeDynamicUnaryOperator(kind, loweredOperand, type).ToExpression()); } else if (kind.IsLifted()) { if (!_inExpressionLambda) { return(LowerLiftedUnaryOperator(kind, syntax, method, loweredOperand, type)); } } else if (kind.IsUserDefined()) { Debug.Assert((object)method != null); Debug.Assert(type == method.ReturnType); if (!_inExpressionLambda || kind == UnaryOperatorKind.UserDefinedTrue || kind == UnaryOperatorKind.UserDefinedFalse) { // @t-mawind // As usual, concept accesses need to be rewritten down to their // default() form. // Is this correct? It's mostly a copy over from the binary case, // but the unary case is different enough to make me nervous. if (method is SynthesizedWitnessMethodSymbol) { return(BoundCall.Synthesized(syntax, SynthesizeWitnessInvocationReceiver(syntax, ((SynthesizedWitnessMethodSymbol)method).Parent), method, loweredOperand)); } return(BoundCall.Synthesized(syntax, null, method, loweredOperand)); } } else if (kind.Operator() == UnaryOperatorKind.UnaryPlus) { // We do not call the operator even for decimal; we simply optimize it away entirely. return(loweredOperand); } if (kind == UnaryOperatorKind.EnumBitwiseComplement) { var underlyingType = loweredOperand.Type.GetEnumUnderlyingType(); var upconvertSpecialType = Binder.GetEnumPromotedType(underlyingType.SpecialType); var upconvertType = upconvertSpecialType == underlyingType.SpecialType ? underlyingType : _compilation.GetSpecialType(upconvertSpecialType); var newOperand = MakeConversionNode(loweredOperand, upconvertType, false); UnaryOperatorKind newKind = kind.Operator().WithType(upconvertSpecialType); var newNode = (oldNode != null) ? oldNode.Update( newKind, newOperand, oldNode.ConstantValueOpt, method, newOperand.ResultKind, upconvertType) : new BoundUnaryOperator( syntax, newKind, newOperand, null, method, LookupResultKind.Viable, upconvertType); return(MakeConversionNode(newNode.Syntax, newNode, Conversion.ExplicitEnumeration, type, @checked: false)); } if (kind == UnaryOperatorKind.DecimalUnaryMinus) { method = (MethodSymbol)_compilation.Assembly.GetSpecialTypeMember(SpecialMember.System_Decimal__op_UnaryNegation); if (!_inExpressionLambda) { return(BoundCall.Synthesized(syntax, null, method, loweredOperand)); } } return((oldNode != null) ? oldNode.Update(kind, loweredOperand, oldNode.ConstantValueOpt, method, oldNode.ResultKind, type) : new BoundUnaryOperator(syntax, kind, loweredOperand, null, method, LookupResultKind.Viable, type)); }
private static void GetSymbolsAndResultKind(BoundUnaryOperator unaryOperator, out bool isDynamic, ref LookupResultKind resultKind, ref ImmutableArray<Symbol> symbols) { UnaryOperatorKind operandType = unaryOperator.OperatorKind.OperandTypes(); isDynamic = unaryOperator.OperatorKind.IsDynamic(); if (operandType == 0 || operandType == UnaryOperatorKind.UserDefined || unaryOperator.ResultKind != LookupResultKind.Viable) { if (!isDynamic) { GetSymbolsAndResultKind(unaryOperator, unaryOperator.MethodOpt, unaryOperator.OriginalUserDefinedOperatorsOpt, out symbols, out resultKind); } } else { Debug.Assert((object)unaryOperator.MethodOpt == null && unaryOperator.OriginalUserDefinedOperatorsOpt.IsDefaultOrEmpty); UnaryOperatorKind op = unaryOperator.OperatorKind.Operator(); symbols = ImmutableArray.Create<Symbol>(new SynthesizedIntrinsicOperatorSymbol(unaryOperator.Operand.Type.StrippedType(), OperatorFacts.UnaryOperatorNameFromOperatorKind(op), unaryOperator.Type.StrippedType(), unaryOperator.OperatorKind.IsChecked())); resultKind = unaryOperator.ResultKind; } }
private static bool IsUserDefinedTrueOrFalse(BoundUnaryOperator @operator) { UnaryOperatorKind operatorKind = @operator.OperatorKind; return operatorKind == UnaryOperatorKind.UserDefinedTrue || operatorKind == UnaryOperatorKind.UserDefinedFalse; }
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 VisitUnaryOperator(BoundUnaryOperator node) { var arg = node.Operand; var loweredArg = Visit(arg); var opKind = node.OperatorKind; var op = opKind & UnaryOperatorKind.OpMask; var isChecked = (opKind & UnaryOperatorKind.Checked) != 0; string opname; switch (op) { case UnaryOperatorKind.UnaryPlus: if ((object)node.MethodOpt == null) { return loweredArg; } opname = "UnaryPlus"; break; case UnaryOperatorKind.UnaryMinus: opname = isChecked ? "NegateChecked" : "Negate"; break; case UnaryOperatorKind.BitwiseComplement: case UnaryOperatorKind.LogicalNegation: opname = "Not"; break; default: throw ExceptionUtilities.UnexpectedValue(op); } if (node.OperatorKind.OperandTypes() == UnaryOperatorKind.Enum && (opKind & UnaryOperatorKind.Lifted) != 0) { Debug.Assert((object)node.MethodOpt == null); var promotedType = PromotedType(arg.Type.StrippedType().GetEnumUnderlyingType()); promotedType = _nullableType.Construct(promotedType); loweredArg = Convert(loweredArg, arg.Type, promotedType, isChecked, false); var result = ExprFactory(opname, loweredArg); return Demote(result, node.Type, isChecked); } return ((object)node.MethodOpt == null) ? ExprFactory(opname, loweredArg) : ExprFactory(opname, loweredArg, _bound.MethodInfo(node.MethodOpt)); }
private BoundExpression MakeUnaryOperator( BoundUnaryOperator oldNode, UnaryOperatorKind kind, SyntaxNode syntax, MethodSymbol method, BoundExpression loweredOperand, TypeSymbol type) { if (kind.IsDynamic()) { Debug.Assert(kind == UnaryOperatorKind.DynamicTrue && type.SpecialType == SpecialType.System_Boolean || type.IsDynamic()); Debug.Assert((object)method == null); // Logical operators on boxed Boolean constants: var constant = UnboxConstant(loweredOperand); if (constant == ConstantValue.True || constant == ConstantValue.False) { if (kind == UnaryOperatorKind.DynamicTrue) { return(_factory.Literal(constant.BooleanValue)); } else if (kind == UnaryOperatorKind.DynamicLogicalNegation) { return(MakeConversionNode(_factory.Literal(!constant.BooleanValue), type, @checked: false)); } } return(_dynamicFactory.MakeDynamicUnaryOperator(kind, loweredOperand, type).ToExpression()); } else if (kind.IsLifted()) { if (!_inExpressionLambda) { return(LowerLiftedUnaryOperator(kind, syntax, method, loweredOperand, type)); } } else if (kind.IsUserDefined()) { Debug.Assert((object)method != null); Debug.Assert(type == method.ReturnType); if (!_inExpressionLambda || kind == UnaryOperatorKind.UserDefinedTrue || kind == UnaryOperatorKind.UserDefinedFalse) { return(BoundCall.Synthesized(syntax, null, method, loweredOperand)); } } else if (kind.Operator() == UnaryOperatorKind.UnaryPlus) { // We do not call the operator even for decimal; we simply optimize it away entirely. return(loweredOperand); } if (kind == UnaryOperatorKind.EnumBitwiseComplement) { var underlyingType = loweredOperand.Type.GetEnumUnderlyingType(); var upconvertSpecialType = Binder.GetEnumPromotedType(underlyingType.SpecialType); var upconvertType = upconvertSpecialType == underlyingType.SpecialType ? underlyingType : _compilation.GetSpecialType(upconvertSpecialType); var newOperand = MakeConversionNode(loweredOperand, upconvertType, false); UnaryOperatorKind newKind = kind.Operator().WithType(upconvertSpecialType); var newNode = (oldNode != null) ? oldNode.Update( newKind, newOperand, oldNode.ConstantValueOpt, method, newOperand.ResultKind, upconvertType) : new BoundUnaryOperator( syntax, newKind, newOperand, null, method, LookupResultKind.Viable, upconvertType); return(MakeConversionNode(newNode.Syntax, newNode, Conversion.ExplicitEnumeration, type, @checked: false)); } if (kind == UnaryOperatorKind.DecimalUnaryMinus) { method = (MethodSymbol)_compilation.Assembly.GetSpecialTypeMember(SpecialMember.System_Decimal__op_UnaryNegation); if (!_inExpressionLambda) { return(BoundCall.Synthesized(syntax, null, method, loweredOperand)); } } return((oldNode != null) ? oldNode.Update(kind, loweredOperand, oldNode.ConstantValueOpt, method, oldNode.ResultKind, type) : new BoundUnaryOperator(syntax, kind, loweredOperand, null, method, LookupResultKind.Viable, type)); }
private BoundExpression MakeDynamicLogicalBinaryOperator( CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, MethodSymbol leftTruthOperator, TypeSymbol type, bool isCompoundAssignment, BoundUnaryOperator applyParentUnaryOperator) { Debug.Assert(operatorKind.Operator() == BinaryOperatorKind.And || operatorKind.Operator() == BinaryOperatorKind.Or); // Dynamic logical && and || operators are lowered as follows: // left && right -> IsFalse(left) ? left : And(left, right) // left || right -> IsTrue(left) ? left : Or(left, right) // // Optimization: If the binary AND/OR is directly contained in IsFalse/IsTrue operator (parentUnaryOperator != null) // we can avoid calling IsFalse/IsTrue twice on the same object. // IsFalse(left && right) -> IsFalse(left) || IsFalse(And(left, right)) // IsTrue(left || right) -> IsTrue(left) || IsTrue(Or(left, right)) bool isAnd = operatorKind.Operator() == BinaryOperatorKind.And; // Operator to be used to test the left operand: var testOperator = isAnd ? UnaryOperatorKind.DynamicFalse : UnaryOperatorKind.DynamicTrue; // VisitUnaryOperator ensures we are never called with parentUnaryOperator != null when we can't perform the optimization. Debug.Assert(applyParentUnaryOperator == null || applyParentUnaryOperator.OperatorKind == testOperator); ConstantValue constantLeft = loweredLeft.ConstantValue ?? UnboxConstant(loweredLeft); if (testOperator == UnaryOperatorKind.DynamicFalse && constantLeft == ConstantValue.False || testOperator == UnaryOperatorKind.DynamicTrue && constantLeft == ConstantValue.True) { Debug.Assert(leftTruthOperator == null); if (applyParentUnaryOperator != null) { // IsFalse(false && right) -> true // IsTrue(true || right) -> true return _factory.Literal(true); } else { // false && right -> box(false) // true || right -> box(true) return MakeConversionNode(loweredLeft, type, @checked: false); } } BoundExpression result; var boolean = _compilation.GetSpecialType(SpecialType.System_Boolean); // Store left to local if needed. If constant or already local we don't need a temp // since the value of left can't change until right is evaluated. BoundAssignmentOperator tempAssignment; BoundLocal temp; if (constantLeft == null && loweredLeft.Kind != BoundKind.Local && loweredLeft.Kind != BoundKind.Parameter) { BoundAssignmentOperator assignment; var local = _factory.StoreToTemp(loweredLeft, out assignment); loweredLeft = local; tempAssignment = assignment; temp = local; } else { tempAssignment = null; temp = null; } var op = _dynamicFactory.MakeDynamicBinaryOperator(operatorKind, loweredLeft, loweredRight, isCompoundAssignment, type).ToExpression(); // IsFalse(true) or IsTrue(false) are always false: bool leftTestIsConstantFalse = testOperator == UnaryOperatorKind.DynamicFalse && constantLeft == ConstantValue.True || testOperator == UnaryOperatorKind.DynamicTrue && constantLeft == ConstantValue.False; if (applyParentUnaryOperator != null) { // IsFalse(left && right) -> IsFalse(left) || IsFalse(And(left, right)) // IsTrue(left || right) -> IsTrue(left) || IsTrue(Or(left, right)) result = _dynamicFactory.MakeDynamicUnaryOperator(testOperator, op, boolean).ToExpression(); if (!leftTestIsConstantFalse) { BoundExpression leftTest = MakeTruthTestForDynamicLogicalOperator(syntax, loweredLeft, boolean, leftTruthOperator, negative: isAnd); result = _factory.Binary(BinaryOperatorKind.LogicalOr, boolean, leftTest, result); } } else { // left && right -> IsFalse(left) ? left : And(left, right) // left || right -> IsTrue(left) ? left : Or(left, right) if (leftTestIsConstantFalse) { result = op; } else { // We might need to box. BoundExpression leftTest = MakeTruthTestForDynamicLogicalOperator(syntax, loweredLeft, boolean, leftTruthOperator, negative: isAnd); var convertedLeft = MakeConversionNode(loweredLeft, type, @checked: false); result = _factory.Conditional(leftTest, convertedLeft, op, type); } } if (tempAssignment != null) { return _factory.Sequence(ImmutableArray.Create(temp.LocalSymbol), ImmutableArray.Create<BoundExpression>(tempAssignment), result); } return result; }
public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { CheckUnsafeType(node); CheckLiftedUnaryOp(node); CheckDynamic(node); return base.VisitUnaryOperator(node); }