private BoundExpression MakeUnaryOperator( BoundUnaryOperator oldNode, UnaryOperatorKind kind, SyntaxNode syntax, MethodSymbol method, BoundExpression loweredOperand, TypeSymbol type) { if (kind.IsLifted()) { return(LowerLiftedUnaryOperator(kind, syntax, method, loweredOperand, type)); } else if (kind.IsUserDefined()) { Debug.Assert((object)method != null); Debug.Assert(TypeSymbol.Equals(type, method.ReturnType.TypeSymbol, TypeCompareKind.ConsiderEverything2)); 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)); } return((oldNode != null) ? oldNode.Update(kind, loweredOperand, oldNode.ConstantValueOpt, method, oldNode.ResultKind, type) : new BoundUnaryOperator(syntax, kind, loweredOperand, null, method, LookupResultKind.Viable, type)); }
internal UnaryOperatorSignature GetSignature(UnaryOperatorKind kind) { TypeSymbol opType; switch (kind.OperandTypes()) { case UnaryOperatorKind.Int8: opType = _compilation.GetSpecialType(SpecialType.System_Int8); break; case UnaryOperatorKind.UInt8: opType = _compilation.GetSpecialType(SpecialType.System_UInt8); break; case UnaryOperatorKind.Int16: opType = _compilation.GetSpecialType(SpecialType.System_Int16); break; case UnaryOperatorKind.UShort: opType = _compilation.GetSpecialType(SpecialType.System_UInt16); break; case UnaryOperatorKind.Int32: opType = _compilation.GetSpecialType(SpecialType.System_Int32); break; case UnaryOperatorKind.UInt32: opType = _compilation.GetSpecialType(SpecialType.System_UInt32); break; case UnaryOperatorKind.Int64: opType = _compilation.GetSpecialType(SpecialType.System_Int64); break; case UnaryOperatorKind.UInt64: opType = _compilation.GetSpecialType(SpecialType.System_UInt64); break; case UnaryOperatorKind.Rune: opType = _compilation.GetSpecialType(SpecialType.System_Rune); break; case UnaryOperatorKind.Float32: opType = _compilation.GetSpecialType(SpecialType.System_Float32); break; case UnaryOperatorKind.Float64: opType = _compilation.GetSpecialType(SpecialType.System_Float64); break; case UnaryOperatorKind.Bool: opType = _compilation.GetSpecialType(SpecialType.System_Boolean); break; case UnaryOperatorKind.Int: opType = _compilation.GetSpecialType(SpecialType.System_Int); break; case UnaryOperatorKind.UInt: opType = _compilation.GetSpecialType(SpecialType.System_UInt); break; default: throw ExceptionUtilities.UnexpectedValue(kind.OperandTypes()); } if (kind.IsLifted()) { opType = _compilation.GetSpecialType(SpecialType.core_Option_T).Construct(opType); } return(new UnaryOperatorSignature(kind, opType, opType)); }
internal UnaryOperatorSignature GetSignature(UnaryOperatorKind kind) { TypeSymbol opType; switch (kind.OperandTypes()) { case UnaryOperatorKind.SByte: opType = _compilation.GetSpecialType(SpecialType.System_SByte); break; case UnaryOperatorKind.Byte: opType = _compilation.GetSpecialType(SpecialType.System_Byte); break; case UnaryOperatorKind.Short: opType = _compilation.GetSpecialType(SpecialType.System_Int16); break; case UnaryOperatorKind.UShort: opType = _compilation.GetSpecialType(SpecialType.System_UInt16); break; case UnaryOperatorKind.Int: opType = _compilation.GetSpecialType(SpecialType.System_Int32); break; case UnaryOperatorKind.UInt: opType = _compilation.GetSpecialType(SpecialType.System_UInt32); break; case UnaryOperatorKind.Long: opType = _compilation.GetSpecialType(SpecialType.System_Int64); break; case UnaryOperatorKind.ULong: opType = _compilation.GetSpecialType(SpecialType.System_UInt64); break; case UnaryOperatorKind.Char: opType = _compilation.GetSpecialType(SpecialType.System_Char); break; case UnaryOperatorKind.Float: opType = _compilation.GetSpecialType(SpecialType.System_Single); break; case UnaryOperatorKind.Double: opType = _compilation.GetSpecialType(SpecialType.System_Double); break; case UnaryOperatorKind.Decimal: opType = _compilation.GetSpecialType(SpecialType.System_Decimal); break; case UnaryOperatorKind.Bool: opType = _compilation.GetSpecialType(SpecialType.System_Boolean); break; default: throw ExceptionUtilities.UnexpectedValue(kind.OperandTypes()); } if (kind.IsLifted()) { opType = _compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(opType); } return(new UnaryOperatorSignature(kind, opType, opType)); }
private BoundExpression MakeUnaryOperator( BoundUnaryOperator?oldNode, UnaryOperatorKind kind, SyntaxNode syntax, MethodSymbol?method, BoundExpression loweredOperand, TypeSymbol type) { if (kind.IsDynamic()) { Debug.Assert((kind == UnaryOperatorKind.DynamicTrue || kind == UnaryOperatorKind.DynamicFalse) && type.SpecialType == SpecialType.System_Boolean || type.IsDynamic()); Debug.Assert(method is null); // Logical operators on boxed Boolean constants: var constant = UnboxConstant(loweredOperand); if (constant == ConstantValue.True || constant == ConstantValue.False) { switch (kind) { case UnaryOperatorKind.DynamicTrue: return(_factory.Literal(constant.BooleanValue)); case 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(method is { });
private static BinaryOperatorKind GetCorrespondingBinaryOperator(BoundIncrementOperator node) { // We need to create expressions that have the semantics of incrementing or decrementing: // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal and // any enum. However, the binary addition operators we have at our disposal are just // int, uint, long, ulong, float, double and decimal. UnaryOperatorKind unaryOperatorKind = node.OperatorKind; BinaryOperatorKind result; switch (unaryOperatorKind.OperandTypes()) { case UnaryOperatorKind.Int: case UnaryOperatorKind.SByte: case UnaryOperatorKind.Short: result = BinaryOperatorKind.Int; break; case UnaryOperatorKind.Byte: case UnaryOperatorKind.UShort: case UnaryOperatorKind.Char: case UnaryOperatorKind.UInt: result = BinaryOperatorKind.UInt; break; case UnaryOperatorKind.Long: result = BinaryOperatorKind.Long; break; case UnaryOperatorKind.ULong: result = BinaryOperatorKind.ULong; break; case UnaryOperatorKind.Float: result = BinaryOperatorKind.Float; break; case UnaryOperatorKind.Double: result = BinaryOperatorKind.Double; break; case UnaryOperatorKind.Decimal: //Dev10 special cased this, but we'll let DecimalRewriter handle it result = BinaryOperatorKind.Decimal; break; case UnaryOperatorKind.Enum: { TypeSymbol underlyingType = node.Type; if (underlyingType.IsNullableType()) { underlyingType = underlyingType.GetNullableUnderlyingType(); } Debug.Assert(underlyingType.IsEnumType()); underlyingType = underlyingType.GetEnumUnderlyingType(); // Operator overload resolution will not have chosen the enumerated type // unless the operand actually is of the enumerated type (or nullable enum type.) switch (underlyingType.SpecialType) { case SpecialType.System_SByte: case SpecialType.System_Int16: case SpecialType.System_Int32: result = BinaryOperatorKind.Int; break; case SpecialType.System_Byte: case SpecialType.System_UInt16: case SpecialType.System_UInt32: result = BinaryOperatorKind.UInt; break; case SpecialType.System_Int64: result = BinaryOperatorKind.Long; break; case SpecialType.System_UInt64: result = BinaryOperatorKind.ULong; break; default: throw ExceptionUtilities.UnexpectedValue(underlyingType.SpecialType); } } break; case UnaryOperatorKind.Pointer: result = BinaryOperatorKind.PointerAndInt; break; case UnaryOperatorKind.UserDefined: case UnaryOperatorKind.Bool: default: throw ExceptionUtilities.UnexpectedValue(unaryOperatorKind.OperandTypes()); } switch (result) { case BinaryOperatorKind.UInt: case BinaryOperatorKind.Int: case BinaryOperatorKind.ULong: case BinaryOperatorKind.Long: case BinaryOperatorKind.PointerAndInt: result |= (BinaryOperatorKind)unaryOperatorKind.OverflowChecks(); break; } if (unaryOperatorKind.IsLifted()) { result |= BinaryOperatorKind.Lifted; } return(result); }
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 ConstantValue FoldUnaryOperator( CSharpSyntaxNode syntax, UnaryOperatorKind kind, BoundExpression operand, SpecialType resultType, DiagnosticBag diagnostics) { Debug.Assert(operand != null); // UNDONE: report errors when in a checked context. if (operand.HasAnyErrors) { return null; } var value = operand.ConstantValue; if (value == null || value.IsBad) { return value; } if (kind.IsEnum() && !kind.IsLifted()) { return FoldEnumUnaryOperator(syntax, kind, operand, diagnostics); } var newValue = FoldNeverOverflowUnaryOperator(kind, value); if (newValue != null) { return ConstantValue.Create(newValue, resultType); } if (CheckOverflowAtCompileTime) { try { newValue = FoldCheckedIntegralUnaryOperator(kind, value); } catch (OverflowException) { Error(diagnostics, ErrorCode.ERR_CheckedOverflow, syntax); return ConstantValue.Bad; } } else { newValue = FoldUncheckedIntegralUnaryOperator(kind, value); } if (newValue != null) { return ConstantValue.Create(newValue, resultType); } return null; }
internal UnaryOperatorSignature GetSignature(UnaryOperatorKind kind) { TypeSymbol opType = null; if (kind.IsLifted()) { var nullable = Compilation.GetSpecialType(SpecialType.System_Nullable_T); switch (kind.OperandTypes()) { case UnaryOperatorKind.SByte: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_SByte)); break; case UnaryOperatorKind.Byte: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Byte)); break; case UnaryOperatorKind.Short: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Int16)); break; case UnaryOperatorKind.UShort: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_UInt16)); break; case UnaryOperatorKind.Int: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Int32)); break; case UnaryOperatorKind.UInt: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_UInt32)); break; case UnaryOperatorKind.Long: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Int64)); break; case UnaryOperatorKind.ULong: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_UInt64)); break; case UnaryOperatorKind.Char: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Char)); break; case UnaryOperatorKind.Float: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Single)); break; case UnaryOperatorKind.Double: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Double)); break; case UnaryOperatorKind.Decimal: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Decimal)); break; case UnaryOperatorKind.Bool: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Boolean)); break; } } else { switch (kind.OperandTypes()) { case UnaryOperatorKind.SByte: opType = Compilation.GetSpecialType(SpecialType.System_SByte); break; case UnaryOperatorKind.Byte: opType = Compilation.GetSpecialType(SpecialType.System_Byte); break; case UnaryOperatorKind.Short: opType = Compilation.GetSpecialType(SpecialType.System_Int16); break; case UnaryOperatorKind.UShort: opType = Compilation.GetSpecialType(SpecialType.System_UInt16); break; case UnaryOperatorKind.Int: opType = Compilation.GetSpecialType(SpecialType.System_Int32); break; case UnaryOperatorKind.UInt: opType = Compilation.GetSpecialType(SpecialType.System_UInt32); break; case UnaryOperatorKind.Long: opType = Compilation.GetSpecialType(SpecialType.System_Int64); break; case UnaryOperatorKind.ULong: opType = Compilation.GetSpecialType(SpecialType.System_UInt64); break; case UnaryOperatorKind.Char: opType = Compilation.GetSpecialType(SpecialType.System_Char); break; case UnaryOperatorKind.Float: opType = Compilation.GetSpecialType(SpecialType.System_Single); break; case UnaryOperatorKind.Double: opType = Compilation.GetSpecialType(SpecialType.System_Double); break; case UnaryOperatorKind.Decimal: opType = Compilation.GetSpecialType(SpecialType.System_Decimal); break; case UnaryOperatorKind.Bool: opType = Compilation.GetSpecialType(SpecialType.System_Boolean); break; } } Debug.Assert((object)opType != null); return(new UnaryOperatorSignature(kind, opType, opType)); }
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); }
internal UnaryOperatorSignature GetSignature(UnaryOperatorKind kind) { TypeSymbol opType = null; if (kind.IsLifted()) { var nullable = Compilation.GetSpecialType(SpecialType.System_Nullable_T); switch (kind.OperandTypes()) { case UnaryOperatorKind.SByte: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_SByte)); break; case UnaryOperatorKind.Byte: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Byte)); break; case UnaryOperatorKind.Short: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Int16)); break; case UnaryOperatorKind.UShort: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_UInt16)); break; case UnaryOperatorKind.Int: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Int32)); break; case UnaryOperatorKind.UInt: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_UInt32)); break; case UnaryOperatorKind.Long: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Int64)); break; case UnaryOperatorKind.ULong: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_UInt64)); break; case UnaryOperatorKind.Char: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Char)); break; case UnaryOperatorKind.Float: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Single)); break; case UnaryOperatorKind.Double: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Double)); break; case UnaryOperatorKind.Decimal: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Decimal)); break; case UnaryOperatorKind.Bool: opType = nullable.Construct(Compilation.GetSpecialType(SpecialType.System_Boolean)); break; } } else { switch (kind.OperandTypes()) { case UnaryOperatorKind.SByte: opType = Compilation.GetSpecialType(SpecialType.System_SByte); break; case UnaryOperatorKind.Byte: opType = Compilation.GetSpecialType(SpecialType.System_Byte); break; case UnaryOperatorKind.Short: opType = Compilation.GetSpecialType(SpecialType.System_Int16); break; case UnaryOperatorKind.UShort: opType = Compilation.GetSpecialType(SpecialType.System_UInt16); break; case UnaryOperatorKind.Int: opType = Compilation.GetSpecialType(SpecialType.System_Int32); break; case UnaryOperatorKind.UInt: opType = Compilation.GetSpecialType(SpecialType.System_UInt32); break; case UnaryOperatorKind.Long: opType = Compilation.GetSpecialType(SpecialType.System_Int64); break; case UnaryOperatorKind.ULong: opType = Compilation.GetSpecialType(SpecialType.System_UInt64); break; case UnaryOperatorKind.Char: opType = Compilation.GetSpecialType(SpecialType.System_Char); break; case UnaryOperatorKind.Float: opType = Compilation.GetSpecialType(SpecialType.System_Single); break; case UnaryOperatorKind.Double: opType = Compilation.GetSpecialType(SpecialType.System_Double); break; case UnaryOperatorKind.Decimal: opType = Compilation.GetSpecialType(SpecialType.System_Decimal); break; case UnaryOperatorKind.Bool: opType = Compilation.GetSpecialType(SpecialType.System_Boolean); break; } } Debug.Assert((object)opType != null); return new UnaryOperatorSignature(kind, opType, opType); }
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)); }