public BoundUnaryExpression(SyntaxNode syntax, BoundExpression expression, UnaryOperatorKind operatorKind, TypeSymbol expressionType) : base(BoundNodeKind.UnaryExpression, syntax) { Expression = expression; OperatorKind = operatorKind; Type = expressionType; }
public UnaryOperatorSignature(UnaryOperatorKind kind, TypeSymbol operandType, TypeSymbol returnType, MethodSymbol method = null) { this.Kind = kind; this.OperandType = operandType; this.ReturnType = returnType; this.Method = method; }
/// <summary> /// Create a new UnaryOperatorQueryToken given the operator and operand /// </summary> /// <param name="operatorKind">The operator represented by this node.</param> /// <param name="operand">The operand.</param> public UnaryOperatorQueryToken(UnaryOperatorKind operatorKind, QueryToken operand) { ExceptionUtils.CheckArgumentNotNull(operand, "operand"); this.operatorKind = operatorKind; this.operand = operand; }
public BoundUnaryExpression(UnaryOperatorKind operatorKind, BoundExpression expression, OverloadResolutionResult<UnaryOperatorSignature> result) : base(BoundNodeKind.UnaryExpression) { OperatorKind = operatorKind; Expression = expression; Result = result; }
public static AndConstraint<UnaryOperatorToken> ShouldBeUnaryOperatorQueryToken(this QueryToken token, UnaryOperatorKind expectedOperatorKind) { token.Should().BeOfType<UnaryOperatorToken>(); var propertyAccessQueryToken = token.As<UnaryOperatorToken>(); propertyAccessQueryToken.Kind.Should().Be(QueryTokenKind.UnaryOperator); propertyAccessQueryToken.OperatorKind.Should().Be(expectedOperatorKind); return new AndConstraint<UnaryOperatorToken>(propertyAccessQueryToken); }
private static OverloadResolutionResult<UnaryOperatorSignature> ResolveOverloads(UnaryOperatorKind kind, TypeSymbol operandType) { var builtInSignatures = GetBuiltInSignatures(kind); if (TypeBuiltIn(operandType)) return OverloadResolution.Perform(builtInSignatures, operandType); return OverloadResolutionResult<UnaryOperatorSignature>.None; }
private BoundExpression MakeUnaryOperator( UnaryOperatorKind kind, CSharpSyntaxNode syntax, MethodSymbol method, BoundExpression loweredOperand, TypeSymbol type) { return MakeUnaryOperator(null, kind, syntax, method, loweredOperand, type); }
/// <summary> /// Get the promoted type reference of the operand /// </summary> /// <param name="operand">the operand</param> /// <param name="unaryOperatorKind">the operator kind</param> /// <returns>the type reference of the operand</returns> private static IEdmTypeReference PromoteOperandType(SingleValueNode operand, UnaryOperatorKind unaryOperatorKind) { IEdmTypeReference typeReference = operand.TypeReference; if (!TypePromotionUtils.PromoteOperandType(unaryOperatorKind, ref typeReference)) { string typeName = operand.TypeReference == null ? "<null>" : operand.TypeReference.ODataFullName(); throw new ODataException(ODataErrorStrings.MetadataBinder_IncompatibleOperandError(typeName, unaryOperatorKind)); } return typeReference; }
public void UnaryOperatorOverloadResolution(UnaryOperatorKind kind, BoundExpression operand, UnaryOperatorOverloadResolutionResult result, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(operand != null); Debug.Assert(result.Results.Count == 0); // We can do a table lookup for well-known problems in overload resolution. UnaryOperatorEasyOut(kind, operand, result); if (result.Results.Count > 0) { return; } // @t-mawind // Here, we add in the possibility of having access to a concept // witness defining the unary operator. bool hadConceptCandidate = GetUnaryWitnessOperators(kind, operand, result.Results, ref useSiteDiagnostics); // SPEC: An operation of the form op x or x op, where op is an overloadable unary operator, // SPEC: and x is an expression of type X, is processed as follows: // SPEC: The set of candidate user-defined operators provided by X for the operation operator // SPEC: op(x) is determined using the rules of 7.3.5. bool hadUserDefinedCandidate = hadConceptCandidate || GetUserDefinedOperators(kind, operand, result.Results, ref useSiteDiagnostics); // SPEC: If the set of candidate user-defined operators is not empty, then this becomes the // SPEC: set of candidate operators for the operation. Otherwise, the predefined unary operator // SPEC: implementations, including their lifted forms, become the set of candidate operators // SPEC: for the operation. if (!hadUserDefinedCandidate) { result.Results.Clear(); GetAllBuiltInOperators(kind, operand, result.Results, ref useSiteDiagnostics); } // SPEC: The overload resolution rules of 7.5.3 are applied to the set of candidate operators // SPEC: to select the best operator with respect to the argument list (x), and this operator // SPEC: becomes the result of the overload resolution process. If overload resolution fails // SPEC: to select a single best operator, a binding-time error occurs. UnaryOperatorOverloadResolution(operand, result, ref useSiteDiagnostics); }
internal static bool IsChecked(UnaryOperatorKind kind) { if (0 == (kind & UnaryOperatorKind.Checked)) { return(false); } switch (kind & UnaryOperatorKind.OpMask) { case UnaryOperatorKind.PrefixIncrement: case UnaryOperatorKind.PostfixIncrement: case UnaryOperatorKind.PrefixDecrement: case UnaryOperatorKind.PostfixDecrement: case UnaryOperatorKind.UnaryMinus: return(true); } return(false); }
/// <summary> /// Populates a list of unary operator results with those from any /// witness in scope at the operator site. /// </summary> /// <param name="kind"> /// The unary operator kind of the expression. /// </param> /// <param name="operand"> /// The operand expression. /// </param> /// <param name="results"> /// The results list to populate. /// </param> /// <param name="useSiteDiagnostics"> /// The set of diagnostics to populate with any errors. /// </param> /// <returns> /// True if we managed to find candidate operators from the concept /// witnesses in scope; false otherwise. /// </returns> private bool GetUnaryWitnessOperators(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder <UnaryOperatorAnalysisResult> results, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(operand != null); string name = OperatorFacts.UnaryOperatorNameFromOperatorKind(kind); var operators = ArrayBuilder <UnaryOperatorSignature> .GetInstance(); foreach (var method in GetWitnessOperators(name, 1, ref useSiteDiagnostics)) { // TODO: nullability operators.Add(new UnaryOperatorSignature(UnaryOperatorKind.UserDefined | kind, method.ParameterTypes[0], method.ReturnType, method)); } bool hasCandidates = CandidateOperators(operators, operand, results, ref useSiteDiagnostics); operators.Free(); return(hasCandidates); }
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 void GetUserDefinedUnaryOperatorsFromType( TypeSymbol constrainedToTypeOpt, NamedTypeSymbol type, UnaryOperatorKind kind, bool isChecked, ArrayBuilder <UnaryOperatorSignature> operators) { Debug.Assert(operators.Count == 0); string name1 = OperatorFacts.UnaryOperatorNameFromOperatorKind(kind, isChecked); getDeclaredOperators(constrainedToTypeOpt, type, kind, name1, operators); if (isChecked && SyntaxFacts.IsCheckedOperator(name1)) { string name2 = OperatorFacts.UnaryOperatorNameFromOperatorKind(kind, isChecked: false); var operators2 = ArrayBuilder <UnaryOperatorSignature> .GetInstance(); // Add regular operators as well. getDeclaredOperators(constrainedToTypeOpt, type, kind, name2, operators2); // Drop operators that have a match among the checked ones. if (operators.Count != 0) { for (int i = operators2.Count - 1; i >= 0; i--) { foreach (UnaryOperatorSignature signature1 in operators) { if (SourceMemberContainerTypeSymbol.DoOperatorsPair(signature1.Method, operators2[i].Method)) { operators2.RemoveAt(i); break; } } } } operators.AddRange(operators2); operators2.Free(); } addLiftedOperators(constrainedToTypeOpt, kind, operators);
public static bool IsIntegral(this UnaryOperatorKind kind) { switch (kind.OperandTypes()) { case UnaryOperatorKind.Int8: case UnaryOperatorKind.UInt8: case UnaryOperatorKind.Int16: case UnaryOperatorKind.UShort: case UnaryOperatorKind.Int32: case UnaryOperatorKind.UInt32: case UnaryOperatorKind.Int64: case UnaryOperatorKind.UInt64: case UnaryOperatorKind.Char: case UnaryOperatorKind.Enum: case UnaryOperatorKind.Pointer: return(true); } return(false); }
internal static string ToDisplayName(this UnaryOperatorKind operatorKind) { switch (operatorKind) { case UnaryOperatorKind.Identity: return(SyntaxKind.PlusToken.GetText()); case UnaryOperatorKind.Negation: return(SyntaxKind.MinusToken.GetText()); case UnaryOperatorKind.Complement: return(SyntaxKind.BitwiseNotToken.GetText()); case UnaryOperatorKind.LogicalNot: return(SyntaxKind.NotKeyword.GetText()); default: throw ExceptionBuilder.UnexpectedValue(operatorKind); } }
private static string GetOperatorMethodName(UnaryOperatorKind kind) { switch (kind) { case UnaryOperatorKind.Identity: return(@"op_UnaryPlus"); case UnaryOperatorKind.Negation: return(@"op_UnaryNegation"); case UnaryOperatorKind.Complement: return(@"op_OnesComplement"); case UnaryOperatorKind.LogicalNot: return(@"op_LogicalNot"); default: throw ExceptionBuilder.UnexpectedValue(kind); } }
private static IEnumerable <UnaryOperatorSignature> GetBuiltInSignatures(UnaryOperatorKind kind) { switch (kind) { case UnaryOperatorKind.Identity: return(BuiltInIdentitySignatures); case UnaryOperatorKind.Negation: return(BuiltInNegationSignatures); case UnaryOperatorKind.Complement: return(BuiltInComplementSignatures); case UnaryOperatorKind.LogicalNot: return(BuiltInLogicalNotSignatures); default: throw ExceptionBuilder.UnexpectedValue(kind); } }
public static bool IsIntegral(this UnaryOperatorKind kind) { switch (kind.OperandTypes()) { case UnaryOperatorKind.SByte: case UnaryOperatorKind.Byte: case UnaryOperatorKind.Short: case UnaryOperatorKind.UShort: case UnaryOperatorKind.Int: case UnaryOperatorKind.UInt: case UnaryOperatorKind.Long: case UnaryOperatorKind.ULong: case UnaryOperatorKind.Char: case UnaryOperatorKind.Enum: case UnaryOperatorKind.Pointer: return(true); } return(false); }
public static UnaryOperatorKind WithType(this UnaryOperatorKind kind, SpecialType type) { Debug.Assert(kind == (kind & ~UnaryOperatorKind.TypeMask)); switch (type) { case SpecialType.System_Int32: return(kind | UnaryOperatorKind.Int); case SpecialType.System_UInt32: return(kind | UnaryOperatorKind.UInt); case SpecialType.System_Int64: return(kind | UnaryOperatorKind.Long); case SpecialType.System_UInt64: return(kind | UnaryOperatorKind.ULong); default: throw ExceptionUtilities.UnexpectedValue(type); } }
public static SyntaxNode UnaryOperator(UnaryOperatorKind kind, SyntaxNode reference) { if (reference == null) { return(SyntaxFactory.EmptyStatement()); } SyntaxNode statement; var operatorKind = kind.ToSyntaxKind(); if (kind == UnaryOperatorKind.PostDecrement || kind == UnaryOperatorKind.PostIncrement) { statement = SyntaxFactory.PostfixUnaryExpression(operatorKind, reference as ExpressionSyntax); } else { statement = SyntaxFactory.PrefixUnaryExpression(operatorKind, reference as ExpressionSyntax); } return(statement); }
private BoundExpression GetLiftedUnaryOperatorConsequence(UnaryOperatorKind kind, SyntaxNode syntax, MethodSymbol method, TypeSymbol type, BoundExpression nonNullOperand) { MethodSymbol ctor = UnsafeGetNullableMethod(syntax, type, SpecialMember.System_Nullable_T__ctor); // OP(temp.GetValueOrDefault()) BoundExpression unliftedOp = MakeUnaryOperator( oldNode: null, kind: kind.Unlifted(), syntax: syntax, method: method, loweredOperand: nonNullOperand, type: type.GetNullableUnderlyingType()); // new R?(OP(temp.GetValueOrDefault())) BoundExpression consequence = new BoundObjectCreationExpression( syntax, ctor, unliftedOp); return(consequence); }
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 void GetAllBuiltInOperators( UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder <UnaryOperatorAnalysisResult> results, ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo ) { // The spec states that overload resolution is performed upon the infinite set of // operators defined on enumerated types, pointers and delegates. Clearly we cannot // construct the infinite set; we have to pare it down. Previous implementations of C# // implement a much stricter rule; they only add the special operators to the candidate // set if one of the operands is of the relevant type. This means that operands // involving user-defined implicit conversions from class or struct types to enum, // pointer and delegate types do not cause the right candidates to participate in // overload resolution. It also presents numerous problems involving delegate variance // and conversions from lambdas to delegate types. // // It is onerous to require the actually specified behavior. We should change the // specification to match the previous implementation. var operators = ArrayBuilder <UnaryOperatorSignature> .GetInstance(); this.Compilation.builtInOperators.GetSimpleBuiltInOperators( kind, operators, skipNativeIntegerOperators: !operand.Type.IsNativeIntegerOrNullableNativeIntegerType() ); GetEnumOperations(kind, operand, operators); var pointerOperator = GetPointerOperation(kind, operand); if (pointerOperator != null) { operators.Add(pointerOperator.Value); } CandidateOperators(operators, operand, results, ref useSiteInfo); operators.Free(); }
internal static UnaryOperatorSymbol UnaryOperation(UnaryOperatorKind kind, ref Expr expr, BindOptions options) { var sym = UnaryOperatorEasyOut.ClassifyOperation(kind, expr.Datatype); if (sym != null) { Convert(ref expr, sym.Type, options); return(sym); } // User-defined operators { var op = UserDefinedUnaryOperator(kind, ref expr, options); if (op != null) { return(op); } } // Dynamic with usual if (options.HasFlag(BindOptions.AllowDynamic)) { var op = DynamicUnaryOperator(kind, ref expr, options); if (op != null) { return(op); } } // Enum operations { var op = EnumUnaryOperator(kind, ref expr, options); if (op != null) { return(op); } } return(null); }
public static UnaryOperatorKind WithType(this UnaryOperatorKind kind, SpecialType type) { Debug.Assert(kind == (kind & ~UnaryOperatorKind.TypeMask)); switch (type) { case SpecialType.System_Int32: return(kind | UnaryOperatorKind.Int); case SpecialType.System_UInt32: return(kind | UnaryOperatorKind.UInt); case SpecialType.System_Int64: return(kind | UnaryOperatorKind.Long); case SpecialType.System_UInt64: return(kind | UnaryOperatorKind.ULong); default: Debug.Assert(false, "Unexpected unary operator type."); return(kind); } }
internal static OverloadResolutionResult <UnaryOperatorSignature> Resolve(UnaryOperatorKind kind, Type type) { var builtInSignatures = GetBuiltInSignatures(kind); // If the type is built-in, we can simply perform the overload resolution // against the built-in signatures only. if (TypeBuiltIn(type)) { return(OverloadResolution.Perform(builtInSignatures, type)); } // Otherwise, we need to consider user defined signatures. // // NOTE: We generally want to perform an overload resolution against the unified // set of both, built-in signatures as well as user defined signatures. // However, if the type provides an operator that is applicable, we want to // to hide the built-in operators. In other words, in those cases the user // defined operators shadows the built-in operators. // Please note that we don't ask whether the overload resolution found a // best match -- we just check if it has an applicable operator. This makes // sure that any any ambiguity errors will not include built-in operators // in the output. var userDefinedSignatures = GetUserDefinedSignatures(kind, type); if (userDefinedSignatures.Any()) { var userDefinedResult = OverloadResolution.Perform(userDefinedSignatures, type); if (userDefinedResult.Candidates.Any(c => c.IsApplicable)) { return(userDefinedResult); } } var signatures = builtInSignatures.Concat(userDefinedSignatures); return(OverloadResolution.Perform(signatures, type)); }
internal BoundUnaryOperator( SyntaxNode syntax, UnaryOperatorKind operatorKind, BoundExpression operand, ConstantValue constantValueOpt, MethodSymbol methodOpt, LookupResultKind resultKind, ImmutableArray <MethodSymbol> originalUserDefinedOperatorsOpt, TypeSymbol type, bool hasErrors = false) : this( syntax, operatorKind, operand, constantValueOpt, methodOpt, resultKind, type, hasErrors) { this.OriginalUserDefinedOperatorsOpt = originalUserDefinedOperatorsOpt; }
public void UnaryOperatorOverloadResolution(UnaryOperatorKind kind, BoundExpression operand, UnaryOperatorOverloadResolutionResult result, ref HashSet<DiagnosticInfo> useSiteDiagnostics) { Debug.Assert(operand != null); Debug.Assert(result.Results.Count == 0); // We can do a table lookup for well-known problems in overload resolution. UnaryOperatorEasyOut(kind, operand, result); if (result.Results.Count > 0) { return; } // SPEC: An operation of the form op x or x op, where op is an overloadable unary operator, // SPEC: and x is an expression of type X, is processed as follows: // SPEC: The set of candidate user-defined operators provided by X for the operation operator // SPEC: op(x) is determined using the rules of 7.3.5. bool hadUserDefinedCandidate = GetUserDefinedOperators(kind, operand, result.Results, ref useSiteDiagnostics); // SPEC: If the set of candidate user-defined operators is not empty, then this becomes the // SPEC: set of candidate operators for the operation. Otherwise, the predefined unary operator // SPEC: implementations, including their lifted forms, become the set of candidate operators // SPEC: for the operation. if (!hadUserDefinedCandidate) { result.Results.Clear(); GetAllBuiltInOperators(kind, operand, result.Results, ref useSiteDiagnostics); } // SPEC: The overload resolution rules of 7.5.3 are applied to the set of candidate operators // SPEC: to select the best operator with respect to the argument list (x), and this operator // SPEC: becomes the result of the overload resolution process. If overload resolution fails // SPEC: to select a single best operator, a binding-time error occurs. UnaryOperatorOverloadResolution(operand, result, ref useSiteDiagnostics); }
/// <summary>Checks that the operands (possibly promoted) are valid for the specified operation.</summary> /// <param name="operatorKind">The operator kind to promote the operand types for.</param> /// <param name="typeReference">Type of the operand.</param> /// <returns>True if the type could be promoted; otherwise false.</returns> internal static bool PromoteOperandType(UnaryOperatorKind operatorKind, ref IEdmTypeReference typeReference) { // The type for the operands can be null // if it (a) represents the null literal or (b) represents an open type/property. // If argument type is null we lack type information and cannot promote the argument type. if (typeReference == null) { // if we find a null literal or open property we cannot promote; the result type will also be null return true; } FunctionSignature[] signatures = GetFunctionSignatures(operatorKind); IEdmTypeReference[] argumentTypes = new IEdmTypeReference[] { typeReference }; bool success = FindBestSignature(signatures, new SingleValueNode[] { null }, argumentTypes) == 1; if (success) { typeReference = argumentTypes[0]; } return success; }
private static IEnumerable<UnaryOperatorSignature> GetBuiltInSignatures(UnaryOperatorKind kind) { switch (kind) { case UnaryOperatorKind.Plus: return BuiltInIdentitySignatures; case UnaryOperatorKind.Minus: return BuiltInNegationSignatures; case UnaryOperatorKind.BitwiseNot: return BuiltInBitwiseNotSignatures; case UnaryOperatorKind.LogicalNot: return BuiltInLogicalNotSignatures; case UnaryOperatorKind.PostDecrement: return BuiltInPostDecrementSignatures; case UnaryOperatorKind.PostIncrement: return BuiltInPostIncrementSignatures; case UnaryOperatorKind.PreDecrement: return BuiltInPreDecrementSignatures; case UnaryOperatorKind.PreIncrement: return BuiltInPreIncrementSignatures; default: throw new ArgumentOutOfRangeException(nameof(kind), kind.ToString()); } }
public BoundIncrementOperator( SyntaxNode syntax, UnaryOperatorKind operatorKind, BoundExpression operand, MethodSymbol methodOpt, Conversion operandConversion, Conversion resultConversion, LookupResultKind resultKind, ImmutableArray <MethodSymbol> originalUserDefinedOperatorsOpt, TypeSymbol type, bool hasErrors = false) : this( syntax, operatorKind, operand, methodOpt, operandConversion, resultConversion, resultKind, type, hasErrors) { this.OriginalUserDefinedOperatorsOpt = originalUserDefinedOperatorsOpt; }
private static UnaryOperatorSignature?GetPointerOperation(UnaryOperatorKind kind, BoundExpression operand) { Debug.Assert(operand != null); var pointerType = operand.Type as PointerTypeSymbol; if ((object)pointerType == null) { return(null); } UnaryOperatorSignature?op = null; switch (kind) { case UnaryOperatorKind.PostfixIncrement: case UnaryOperatorKind.PostfixDecrement: case UnaryOperatorKind.PrefixIncrement: case UnaryOperatorKind.PrefixDecrement: op = new UnaryOperatorSignature(kind | UnaryOperatorKind.Pointer, pointerType, pointerType); break; } return(op); }
internal LoweredDynamicOperation MakeDynamicUnaryOperator( UnaryOperatorKind operatorKind, BoundExpression loweredOperand, TypeSymbol resultType) { Debug.Assert(operatorKind.IsDynamic()); _factory.Syntax = loweredOperand.Syntax; CSharpBinderFlags binderFlags = 0; if (operatorKind.IsChecked()) { binderFlags |= CSharpBinderFlags.CheckedContext; } var loweredArguments = ImmutableArray.Create(loweredOperand); MethodSymbol argumentInfoFactory = GetArgumentInfoFactory(); var binderConstruction = ((object)argumentInfoFactory != null) ? MakeBinderConstruction(WellKnownMember.Microsoft_CSharp_RuntimeBinder_Binder__UnaryOperation, new[] { // flags: _factory.Literal((int)binderFlags), // expression type: _factory.Literal((int)operatorKind.ToExpressionType()), // context: _factory.TypeofDynamicOperationContextType(), // argument infos: MakeCallSiteArgumentInfos(argumentInfoFactory, loweredArguments) }) : null; return(MakeDynamicOperation(binderConstruction, null, RefKind.None, loweredArguments, default(ImmutableArray <RefKind>), null, resultType)); }
private void UnaryOperatorEasyOut(UnaryOperatorKind kind, BoundExpression operand, UnaryOperatorOverloadResolutionResult result) { var operandType = operand.Type; if ((object)operandType == null) { return; } var easyOut = UnopEasyOut.OpKind(kind, operandType); if (easyOut == UnaryOperatorKind.Error) { return; } UnaryOperatorSignature signature = this.Compilation.builtInOperators.GetSignature(easyOut); Conversion?conversion = Conversions.FastClassifyConversion(operandType, signature.OperandType); Debug.Assert(conversion.HasValue && conversion.Value.IsImplicit); result.Results.Add(UnaryOperatorAnalysisResult.Applicable(signature, conversion.Value)); }
private static object FoldCheckedIntegralUnaryOperator(UnaryOperatorKind kind, ConstantValue value) { checked { switch (kind) { case UnaryOperatorKind.LongUnaryMinus: return -value.Int64Value; case UnaryOperatorKind.IntUnaryMinus: return -value.Int32Value; } } return null; }
private static object FoldNeverOverflowUnaryOperator(UnaryOperatorKind kind, ConstantValue value) { // Note that we do operations on single-precision floats as double-precision. switch (kind) { case UnaryOperatorKind.DecimalUnaryMinus: return -value.DecimalValue; case UnaryOperatorKind.DoubleUnaryMinus: case UnaryOperatorKind.FloatUnaryMinus: return -value.DoubleValue; case UnaryOperatorKind.DecimalUnaryPlus: return +value.DecimalValue; case UnaryOperatorKind.FloatUnaryPlus: case UnaryOperatorKind.DoubleUnaryPlus: return +value.DoubleValue; case UnaryOperatorKind.LongUnaryPlus: return +value.Int64Value; case UnaryOperatorKind.ULongUnaryPlus: return +value.UInt64Value; case UnaryOperatorKind.IntUnaryPlus: return +value.Int32Value; case UnaryOperatorKind.UIntUnaryPlus: return +value.UInt32Value; case UnaryOperatorKind.BoolLogicalNegation: return !value.BooleanValue; case UnaryOperatorKind.IntBitwiseComplement: return ~value.Int32Value; case UnaryOperatorKind.LongBitwiseComplement: return ~value.Int64Value; case UnaryOperatorKind.UIntBitwiseComplement: return ~value.UInt32Value; case UnaryOperatorKind.ULongBitwiseComplement: return ~value.UInt64Value; } return null; }
private BoundExpression LowerLiftedUnaryOperator( UnaryOperatorKind kind, CSharpSyntaxNode syntax, MethodSymbol method, BoundExpression loweredOperand, TypeSymbol type) { // First, an optimization. If we know that the operand is always null then // we can simply lower to the alternative. BoundExpression optimized = OptimizeLiftedUnaryOperator(kind, syntax, method, loweredOperand, type); if (optimized != null) { return optimized; } // We do not know whether the operand is null or non-null, so we generate: // // S? temp = operand; // R? r = temp.HasValue ? // new R?(OP(temp.GetValueOrDefault())) : // default(R?); BoundAssignmentOperator tempAssignment; BoundLocal boundTemp = _factory.StoreToTemp(loweredOperand, out tempAssignment); MethodSymbol getValueOrDefault = GetNullableMethod(syntax, boundTemp.Type, SpecialMember.System_Nullable_T_GetValueOrDefault); // temp.HasValue BoundExpression condition = MakeNullableHasValue(syntax, boundTemp); // temp.GetValueOrDefault() BoundExpression call_GetValueOrDefault = BoundCall.Synthesized(syntax, boundTemp, getValueOrDefault); // new R?(temp.GetValueOrDefault()) BoundExpression consequence = GetLiftedUnaryOperatorConsequence(kind, syntax, method, type, call_GetValueOrDefault); // default(R?) BoundExpression alternative = new BoundDefaultOperator(syntax, null, type); // temp.HasValue ? // new R?(OP(temp.GetValueOrDefault())) : // default(R?); BoundExpression conditionalExpression = RewriteConditionalOperator( syntax: syntax, rewrittenCondition: condition, rewrittenConsequence: consequence, rewrittenAlternative: alternative, constantValueOpt: null, rewrittenType: type); // temp = operand; // temp.HasValue ? // new R?(OP(temp.GetValueOrDefault())) : // default(R?); return new BoundSequence( syntax: syntax, locals: ImmutableArray.Create<LocalSymbol>(boundTemp.LocalSymbol), sideEffects: ImmutableArray.Create<BoundExpression>(tempAssignment), value: conditionalExpression, type: type); }
private void UnaryOperatorEasyOut(UnaryOperatorKind kind, BoundExpression operand, UnaryOperatorOverloadResolutionResult result) { var operandType = operand.Type; if (operandType == null) { return; } var easyOut = UnopEasyOut.OpKind(kind, operandType); if (easyOut == UnaryOperatorKind.Error) { return; } UnaryOperatorSignature signature = this.Compilation.builtInOperators.GetSignature(easyOut); Conversion? conversion = Conversions.FastClassifyConversion(operandType, signature.OperandType); Debug.Assert(conversion.HasValue && conversion.Value.IsImplicit); result.Results.Add(UnaryOperatorAnalysisResult.Applicable(signature, conversion.Value)); }
internal UnaryOperatorSymbol BindUnaryOperation(UnaryExpr expr, UnaryOperatorKind kind) { return(BindUnaryOperation(expr, kind, Options.Binding)); }
// There are ++ and -- operators defined on sbyte, byte, short, ushort, int, // uint, long, ulong, char, float, double, decimal and any enum type. // Given a built-in increment operator, get the associated type. Note // that this need not be the result type or the operand type of the node! // We could have a user-defined conversion from the type of the operand // to short, and a user-defined conversion from short to the result // type. private TypeSymbol GetUnaryOperatorType(BoundIncrementOperator node) { UnaryOperatorKind kind = node.OperatorKind.OperandTypes(); // If overload resolution chose an enum operator then the operand // type and the return type really are an enum; we are not in a user- // defined conversion scenario. if (kind == UnaryOperatorKind.Enum) { return(node.Type); } SpecialType specialType; switch (kind) { case UnaryOperatorKind.Int: specialType = SpecialType.System_Int32; break; case UnaryOperatorKind.SByte: specialType = SpecialType.System_SByte; break; case UnaryOperatorKind.Short: specialType = SpecialType.System_Int16; break; case UnaryOperatorKind.Byte: specialType = SpecialType.System_Byte; break; case UnaryOperatorKind.UShort: specialType = SpecialType.System_UInt16; break; case UnaryOperatorKind.Char: specialType = SpecialType.System_Char; break; case UnaryOperatorKind.UInt: specialType = SpecialType.System_UInt32; break; case UnaryOperatorKind.Long: specialType = SpecialType.System_Int64; break; case UnaryOperatorKind.ULong: specialType = SpecialType.System_UInt64; break; case UnaryOperatorKind.Float: specialType = SpecialType.System_Single; break; case UnaryOperatorKind.Double: specialType = SpecialType.System_Double; break; case UnaryOperatorKind.Decimal: specialType = SpecialType.System_Decimal; break; case UnaryOperatorKind.Pointer: return(node.Type); case UnaryOperatorKind.UserDefined: case UnaryOperatorKind.Bool: default: throw ExceptionUtilities.UnexpectedValue(kind); } NamedTypeSymbol type = _compilation.GetSpecialType(specialType); if (node.OperatorKind.IsLifted()) { type = _compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(type); } return(type); }
private void GetUserDefinedOperators(UnaryOperatorKind kind, TypeSymbol type, BoundExpression operand, ArrayBuilder<UnaryOperatorAnalysisResult> results) { // UNDONE: Quote spec var underlyingType = TypeOrUnderlyingType(type); for (var t = underlyingType; t != null; t = t.BaseType) { // UNDONE: Quote spec } }
private BoundExpression LowerLiftedUnaryOperator( UnaryOperatorKind kind, SyntaxNode syntax, MethodSymbol method, BoundExpression loweredOperand, TypeSymbol type) { // First, an optimization. If we know that the operand is always null then // we can simply lower to the alternative. BoundExpression optimized = OptimizeLiftedUnaryOperator(kind, syntax, method, loweredOperand, type); if (optimized != null) { return(optimized); } // We do not know whether the operand is null or non-null, so we generate: // // S? temp = operand; // R? r = temp.HasValue ? // new R?(OP(temp.GetValueOrDefault())) : // default(R?); BoundAssignmentOperator tempAssignment; BoundLocal boundTemp = _factory.StoreToTemp(loweredOperand, out tempAssignment); MethodSymbol getValueOrDefault = UnsafeGetNullableMethod(syntax, boundTemp.Type, SpecialMember.System_Nullable_T_GetValueOrDefault); // temp.HasValue BoundExpression condition = MakeNullableHasValue(syntax, boundTemp); // temp.GetValueOrDefault() BoundExpression call_GetValueOrDefault = BoundCall.Synthesized(syntax, boundTemp, getValueOrDefault); // new R?(temp.GetValueOrDefault()) BoundExpression consequence = GetLiftedUnaryOperatorConsequence(kind, syntax, method, type, call_GetValueOrDefault); // default(R?) BoundExpression alternative = new BoundDefaultOperator(syntax, null, type); // temp.HasValue ? // new R?(OP(temp.GetValueOrDefault())) : // default(R?); BoundExpression conditionalExpression = RewriteConditionalOperator( syntax: syntax, rewrittenCondition: condition, rewrittenConsequence: consequence, rewrittenAlternative: alternative, constantValueOpt: null, rewrittenType: type); // temp = operand; // temp.HasValue ? // new R?(OP(temp.GetValueOrDefault())) : // default(R?); return(new BoundSequence( syntax: syntax, locals: ImmutableArray.Create <LocalSymbol>(boundTemp.LocalSymbol), sideEffects: ImmutableArray.Create <BoundExpression>(tempAssignment), value: conditionalExpression, type: type)); }
private void GetAllBuiltInOperators(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder<UnaryOperatorAnalysisResult> results) { // The spec states that overload resolution is performed upon the infinite set of // operators defined on enumerated types, pointers and delegates. Clearly we cannot // construct the infinite set; we have to pare it down. Previous implementations of C# // implement a much stricter rule; they only add the special operators to the candidate // set if one of the operands is of the relevant type. This means that operands // involving user-defined implicit conversions from class or struct types to enum, // pointer and delegate types do not cause the right candidates to participate in // overload resolution. It also presents numerous problems involving delegate variance // and conversions from lambdas to delegate types. // // It is onerous to require the actually specified behavior. We should change the // specification to match the previous implementation. var operators = ArrayBuilder<UnaryOperatorSignature>.GetInstance(); this.Compilation.builtInOperators.GetSimpleBuiltInOperators(kind, operators); GetEnumOperations(kind, operand, operators); var pointerOperator = GetPointerOperation(kind, operand); if (pointerOperator != null) { operators.Add(pointerOperator.Value); } CandidateOperators(operators, operand, results); operators.Free(); }
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 void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<UnaryOperatorSignature> operators) { if (builtInUnaryOperators == null) { var allOperators = new ImmutableArray<UnaryOperatorSignature>[] { (new [] { GetSignature(UnaryOperatorKind.SBytePostfixIncrement), GetSignature(UnaryOperatorKind.BytePostfixIncrement), GetSignature(UnaryOperatorKind.ShortPostfixIncrement), GetSignature(UnaryOperatorKind.UShortPostfixIncrement), GetSignature(UnaryOperatorKind.IntPostfixIncrement), GetSignature(UnaryOperatorKind.UIntPostfixIncrement), GetSignature(UnaryOperatorKind.LongPostfixIncrement), GetSignature(UnaryOperatorKind.ULongPostfixIncrement), GetSignature(UnaryOperatorKind.CharPostfixIncrement), GetSignature(UnaryOperatorKind.FloatPostfixIncrement), GetSignature(UnaryOperatorKind.DoublePostfixIncrement), GetSignature(UnaryOperatorKind.DecimalPostfixIncrement), GetSignature(UnaryOperatorKind.LiftedSBytePostfixIncrement), GetSignature(UnaryOperatorKind.LiftedBytePostfixIncrement), GetSignature(UnaryOperatorKind.LiftedShortPostfixIncrement), GetSignature(UnaryOperatorKind.LiftedUShortPostfixIncrement), GetSignature(UnaryOperatorKind.LiftedIntPostfixIncrement), GetSignature(UnaryOperatorKind.LiftedUIntPostfixIncrement), GetSignature(UnaryOperatorKind.LiftedLongPostfixIncrement), GetSignature(UnaryOperatorKind.LiftedULongPostfixIncrement), GetSignature(UnaryOperatorKind.LiftedCharPostfixIncrement), GetSignature(UnaryOperatorKind.LiftedFloatPostfixIncrement), GetSignature(UnaryOperatorKind.LiftedDoublePostfixIncrement), GetSignature(UnaryOperatorKind.LiftedDecimalPostfixIncrement), }).AsImmutableOrNull(), (new [] { GetSignature(UnaryOperatorKind.SBytePostfixDecrement), GetSignature(UnaryOperatorKind.BytePostfixDecrement), GetSignature(UnaryOperatorKind.ShortPostfixDecrement), GetSignature(UnaryOperatorKind.UShortPostfixDecrement), GetSignature(UnaryOperatorKind.IntPostfixDecrement), GetSignature(UnaryOperatorKind.UIntPostfixDecrement), GetSignature(UnaryOperatorKind.LongPostfixDecrement), GetSignature(UnaryOperatorKind.ULongPostfixDecrement), GetSignature(UnaryOperatorKind.CharPostfixDecrement), GetSignature(UnaryOperatorKind.FloatPostfixDecrement), GetSignature(UnaryOperatorKind.DoublePostfixDecrement), GetSignature(UnaryOperatorKind.DecimalPostfixDecrement), GetSignature(UnaryOperatorKind.LiftedSBytePostfixDecrement), GetSignature(UnaryOperatorKind.LiftedBytePostfixDecrement), GetSignature(UnaryOperatorKind.LiftedShortPostfixDecrement), GetSignature(UnaryOperatorKind.LiftedUShortPostfixDecrement), GetSignature(UnaryOperatorKind.LiftedIntPostfixDecrement), GetSignature(UnaryOperatorKind.LiftedUIntPostfixDecrement), GetSignature(UnaryOperatorKind.LiftedLongPostfixDecrement), GetSignature(UnaryOperatorKind.LiftedULongPostfixDecrement), GetSignature(UnaryOperatorKind.LiftedCharPostfixDecrement), GetSignature(UnaryOperatorKind.LiftedFloatPostfixDecrement), GetSignature(UnaryOperatorKind.LiftedDoublePostfixDecrement), GetSignature(UnaryOperatorKind.LiftedDecimalPostfixDecrement), }).AsImmutableOrNull(), (new [] { GetSignature(UnaryOperatorKind.SBytePrefixIncrement), GetSignature(UnaryOperatorKind.BytePrefixIncrement), GetSignature(UnaryOperatorKind.ShortPrefixIncrement), GetSignature(UnaryOperatorKind.UShortPrefixIncrement), GetSignature(UnaryOperatorKind.IntPrefixIncrement), GetSignature(UnaryOperatorKind.UIntPrefixIncrement), GetSignature(UnaryOperatorKind.LongPrefixIncrement), GetSignature(UnaryOperatorKind.ULongPrefixIncrement), GetSignature(UnaryOperatorKind.CharPrefixIncrement), GetSignature(UnaryOperatorKind.FloatPrefixIncrement), GetSignature(UnaryOperatorKind.DoublePrefixIncrement), GetSignature(UnaryOperatorKind.DecimalPrefixIncrement), GetSignature(UnaryOperatorKind.LiftedSBytePrefixIncrement), GetSignature(UnaryOperatorKind.LiftedBytePrefixIncrement), GetSignature(UnaryOperatorKind.LiftedShortPrefixIncrement), GetSignature(UnaryOperatorKind.LiftedUShortPrefixIncrement), GetSignature(UnaryOperatorKind.LiftedIntPrefixIncrement), GetSignature(UnaryOperatorKind.LiftedUIntPrefixIncrement), GetSignature(UnaryOperatorKind.LiftedLongPrefixIncrement), GetSignature(UnaryOperatorKind.LiftedULongPrefixIncrement), GetSignature(UnaryOperatorKind.LiftedCharPrefixIncrement), GetSignature(UnaryOperatorKind.LiftedFloatPrefixIncrement), GetSignature(UnaryOperatorKind.LiftedDoublePrefixIncrement), GetSignature(UnaryOperatorKind.LiftedDecimalPrefixIncrement), }).AsImmutableOrNull(), (new [] { GetSignature(UnaryOperatorKind.SBytePrefixDecrement), GetSignature(UnaryOperatorKind.BytePrefixDecrement), GetSignature(UnaryOperatorKind.ShortPrefixDecrement), GetSignature(UnaryOperatorKind.UShortPrefixDecrement), GetSignature(UnaryOperatorKind.IntPrefixDecrement), GetSignature(UnaryOperatorKind.UIntPrefixDecrement), GetSignature(UnaryOperatorKind.LongPrefixDecrement), GetSignature(UnaryOperatorKind.ULongPrefixDecrement), GetSignature(UnaryOperatorKind.CharPrefixDecrement), GetSignature(UnaryOperatorKind.FloatPrefixDecrement), GetSignature(UnaryOperatorKind.DoublePrefixDecrement), GetSignature(UnaryOperatorKind.DecimalPrefixDecrement), GetSignature(UnaryOperatorKind.LiftedSBytePrefixDecrement), GetSignature(UnaryOperatorKind.LiftedBytePrefixDecrement), GetSignature(UnaryOperatorKind.LiftedShortPrefixDecrement), GetSignature(UnaryOperatorKind.LiftedUShortPrefixDecrement), GetSignature(UnaryOperatorKind.LiftedIntPrefixDecrement), GetSignature(UnaryOperatorKind.LiftedUIntPrefixDecrement), GetSignature(UnaryOperatorKind.LiftedLongPrefixDecrement), GetSignature(UnaryOperatorKind.LiftedULongPrefixDecrement), GetSignature(UnaryOperatorKind.LiftedCharPrefixDecrement), GetSignature(UnaryOperatorKind.LiftedFloatPrefixDecrement), GetSignature(UnaryOperatorKind.LiftedDoublePrefixDecrement), GetSignature(UnaryOperatorKind.LiftedDecimalPrefixDecrement), }).AsImmutableOrNull(), (new [] { GetSignature(UnaryOperatorKind.IntUnaryPlus), GetSignature(UnaryOperatorKind.UIntUnaryPlus), GetSignature(UnaryOperatorKind.LongUnaryPlus), GetSignature(UnaryOperatorKind.ULongUnaryPlus), GetSignature(UnaryOperatorKind.FloatUnaryPlus), GetSignature(UnaryOperatorKind.DoubleUnaryPlus), GetSignature(UnaryOperatorKind.DecimalUnaryPlus), GetSignature(UnaryOperatorKind.LiftedIntUnaryPlus), GetSignature(UnaryOperatorKind.LiftedUIntUnaryPlus), GetSignature(UnaryOperatorKind.LiftedLongUnaryPlus), GetSignature(UnaryOperatorKind.LiftedULongUnaryPlus), GetSignature(UnaryOperatorKind.LiftedFloatUnaryPlus), GetSignature(UnaryOperatorKind.LiftedDoubleUnaryPlus), GetSignature(UnaryOperatorKind.LiftedDecimalUnaryPlus), }).AsImmutableOrNull(), (new [] { GetSignature(UnaryOperatorKind.IntUnaryMinus), GetSignature(UnaryOperatorKind.LongUnaryMinus), GetSignature(UnaryOperatorKind.FloatUnaryMinus), GetSignature(UnaryOperatorKind.DoubleUnaryMinus), GetSignature(UnaryOperatorKind.DecimalUnaryMinus), GetSignature(UnaryOperatorKind.LiftedIntUnaryMinus), GetSignature(UnaryOperatorKind.LiftedLongUnaryMinus), GetSignature(UnaryOperatorKind.LiftedFloatUnaryMinus), GetSignature(UnaryOperatorKind.LiftedDoubleUnaryMinus), GetSignature(UnaryOperatorKind.LiftedDecimalUnaryMinus), }).AsImmutableOrNull(), (new [] { GetSignature(UnaryOperatorKind.BoolLogicalNegation), GetSignature(UnaryOperatorKind.LiftedBoolLogicalNegation), }).AsImmutableOrNull(), (new [] { GetSignature(UnaryOperatorKind.IntBitwiseComplement), GetSignature(UnaryOperatorKind.UIntBitwiseComplement), GetSignature(UnaryOperatorKind.LongBitwiseComplement), GetSignature(UnaryOperatorKind.ULongBitwiseComplement), GetSignature(UnaryOperatorKind.LiftedIntBitwiseComplement), GetSignature(UnaryOperatorKind.LiftedUIntBitwiseComplement), GetSignature(UnaryOperatorKind.LiftedLongBitwiseComplement), GetSignature(UnaryOperatorKind.LiftedULongBitwiseComplement), }).AsImmutableOrNull(), // No built-in operator true or operator false (new UnaryOperatorSignature [0]).AsImmutableOrNull(), (new UnaryOperatorSignature [0]).AsImmutableOrNull(), }; Interlocked.CompareExchange(ref builtInUnaryOperators, allOperators, null); } operators.AddRange(builtInUnaryOperators[kind.OperatorIndex()]); }
private BoundExpression GetLiftedUnaryOperatorConsequence(UnaryOperatorKind kind, CSharpSyntaxNode syntax, MethodSymbol method, TypeSymbol type, BoundExpression nonNullOperand) { MethodSymbol ctor = GetNullableMethod(syntax, type, SpecialMember.System_Nullable_T__ctor); // OP(temp.GetValueOrDefault()) BoundExpression unliftedOp = MakeUnaryOperator( oldNode: null, kind: kind.Unlifted(), syntax: syntax, method: method, loweredOperand: nonNullOperand, type: type.GetNullableUnderlyingType()); // new R?(OP(temp.GetValueOrDefault())) BoundExpression consequence = new BoundObjectCreationExpression( syntax, ctor, unliftedOp); return consequence; }
private BoundExpression OptimizeLiftedUnaryOperator( UnaryOperatorKind operatorKind, CSharpSyntaxNode syntax, MethodSymbol method, BoundExpression loweredOperand, TypeSymbol type) { if (NullableNeverHasValue(loweredOperand)) { return new BoundDefaultOperator(syntax, null, type); } // Second, another simple optimization. If we know that the operand is never null // then we can obtain the non-null value and skip generating the temporary. That is, // "~(new int?(M()))" is the same as "new int?(~M())". BoundExpression neverNull = NullableAlwaysHasValue(loweredOperand); if (neverNull != null) { return GetLiftedUnaryOperatorConsequence(operatorKind, syntax, method, type, neverNull); } var conditionalLeft = loweredOperand as BoundLoweredConditionalAccess; // NOTE: we could in theory handle side-effecting loweredRight here too // by including it as a part of whenNull, but there is a concern // that it can lead to code duplication var optimize = conditionalLeft != null && (conditionalLeft.WhenNullOpt == null || conditionalLeft.WhenNullOpt.IsDefaultValue()); if (optimize) { var result = LowerLiftedUnaryOperator(operatorKind, syntax, method, conditionalLeft.WhenNotNull, type); return conditionalLeft.Update( conditionalLeft.Receiver, conditionalLeft.HasValueMethodOpt, whenNotNull: result, whenNullOpt: null, id: conditionalLeft.Id, type: result.Type ); } // This optimization is analogous to DistributeLiftedConversionIntoLiftedOperand. // Suppose we have a lifted unary conversion whose operand is itself a lifted operation. // That is, we have something like: // // int? r = - (M() + N()); // // where M() and N() return nullable ints. We would simply codegen this as first // creating the nullable int result of M() + N(), then checking it for nullity, // and then doing the unary minus. That is: // // int? m = M(); // int? n = N(); // int? t = m.HasValue && n.HasValue ? new int?(m.Value + n.Value) : new int?(); // int? r = t.HasValue ? new int?(-t.Value) : new int?(); // // However, we also observe that we can distribute the unary minus into both branches of // the conditional: // // int? m = M(); // int? n = N(); // int? r = m.HasValue && n.HasValue ? - (new int?(m.Value + n.Value))) : - new int?(); // // And we already optimize those! So we could reduce this to: // // int? m = M(); // int? n = N(); // int? r = m.HasValue && n.HasValue ? new int?(- (m.Value + n.Value)) : new int?()); // // which avoids entirely the creation of the unnecessary nullable int and the unnecessary // extra null check. if (loweredOperand.Kind == BoundKind.Sequence) { BoundSequence seq = (BoundSequence)loweredOperand; if (seq.Value.Kind == BoundKind.ConditionalOperator) { BoundConditionalOperator conditional = (BoundConditionalOperator)seq.Value; Debug.Assert(seq.Type == conditional.Type); Debug.Assert(conditional.Type == conditional.Consequence.Type); Debug.Assert(conditional.Type == conditional.Alternative.Type); if (NullableAlwaysHasValue(conditional.Consequence) != null && NullableNeverHasValue(conditional.Alternative)) { return new BoundSequence( syntax, seq.Locals, seq.SideEffects, RewriteConditionalOperator( syntax, conditional.Condition, MakeUnaryOperator(operatorKind, syntax, method, conditional.Consequence, type), MakeUnaryOperator(operatorKind, syntax, method, conditional.Alternative, type), ConstantValue.NotAvailable, type), type); } } } return null; }
public static UnaryOperatorKind OpKind(UnaryOperatorKind kind, TypeSymbol operand) { int? index = TypeToIndex(operand); if (index == null) { return UnaryOperatorKind.Error; } var result = opkind[kind.OperatorIndex()][index.Value]; return result == UnaryOperatorKind.Error ? result : result | kind; }
private UnaryOperatorSignature? GetPointerOperation(UnaryOperatorKind kind, BoundExpression operand) { Debug.Assert(operand != null); var pointerType = operand.Type as PointerTypeSymbol; if (pointerType == null) { return null; } UnaryOperatorSignature? op = null; switch (kind) { case UnaryOperatorKind.PostfixIncrement: case UnaryOperatorKind.PostfixDecrement: case UnaryOperatorKind.PrefixIncrement: case UnaryOperatorKind.PrefixDecrement: op = new UnaryOperatorSignature(kind | UnaryOperatorKind.Pointer, pointerType, pointerType); break; } return op; }
private BoundExpression OptimizeLiftedUnaryOperator( UnaryOperatorKind operatorKind, SyntaxNode syntax, MethodSymbol method, BoundExpression loweredOperand, TypeSymbol type) { if (NullableNeverHasValue(loweredOperand)) { return(new BoundDefaultOperator(syntax, null, type)); } // Second, another simple optimization. If we know that the operand is never null // then we can obtain the non-null value and skip generating the temporary. That is, // "~(new int?(M()))" is the same as "new int?(~M())". BoundExpression neverNull = NullableAlwaysHasValue(loweredOperand); if (neverNull != null) { return(GetLiftedUnaryOperatorConsequence(operatorKind, syntax, method, type, neverNull)); } var conditionalLeft = loweredOperand as BoundLoweredConditionalAccess; // NOTE: we could in theory handle side-effecting loweredRight here too // by including it as a part of whenNull, but there is a concern // that it can lead to code duplication var optimize = conditionalLeft != null && (conditionalLeft.WhenNullOpt == null || conditionalLeft.WhenNullOpt.IsDefaultValue()); if (optimize) { var result = LowerLiftedUnaryOperator(operatorKind, syntax, method, conditionalLeft.WhenNotNull, type); return(conditionalLeft.Update( conditionalLeft.Receiver, conditionalLeft.HasValueMethodOpt, whenNotNull: result, whenNullOpt: null, id: conditionalLeft.Id, type: result.Type )); } // This optimization is analogous to DistributeLiftedConversionIntoLiftedOperand. // Suppose we have a lifted unary conversion whose operand is itself a lifted operation. // That is, we have something like: // // int? r = - (M() + N()); // // where M() and N() return nullable ints. We would simply codegen this as first // creating the nullable int result of M() + N(), then checking it for nullity, // and then doing the unary minus. That is: // // int? m = M(); // int? n = N(); // int? t = m.HasValue && n.HasValue ? new int?(m.Value + n.Value) : new int?(); // int? r = t.HasValue ? new int?(-t.Value) : new int?(); // // However, we also observe that we can distribute the unary minus into both branches of // the conditional: // // int? m = M(); // int? n = N(); // int? r = m.HasValue && n.HasValue ? - (new int?(m.Value + n.Value))) : - new int?(); // // And we already optimize those! So we could reduce this to: // // int? m = M(); // int? n = N(); // int? r = m.HasValue && n.HasValue ? new int?(- (m.Value + n.Value)) : new int?()); // // which avoids entirely the creation of the unnecessary nullable int and the unnecessary // extra null check. if (loweredOperand.Kind == BoundKind.Sequence) { BoundSequence seq = (BoundSequence)loweredOperand; if (seq.Value.Kind == BoundKind.ConditionalOperator) { BoundConditionalOperator conditional = (BoundConditionalOperator)seq.Value; Debug.Assert(seq.Type == conditional.Type); Debug.Assert(conditional.Type == conditional.Consequence.Type); Debug.Assert(conditional.Type == conditional.Alternative.Type); if (NullableAlwaysHasValue(conditional.Consequence) != null && NullableNeverHasValue(conditional.Alternative)) { return(new BoundSequence( syntax, seq.Locals, seq.SideEffects, RewriteConditionalOperator( syntax, conditional.Condition, MakeUnaryOperator(operatorKind, syntax, method, conditional.Consequence, type), MakeUnaryOperator(operatorKind, syntax, method, conditional.Alternative, type), ConstantValue.NotAvailable, type), type)); } } } return(null); }
private void GetEnumOperations(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder<UnaryOperatorSignature> operators) { Debug.Assert(operand != null); var enumType = operand.Type; if (enumType == null) { return; } enumType = TypeOrUnderlyingType(enumType); if (!enumType.IsValidEnumType()) { return; } var nullableEnum = Compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(enumType); switch (kind) { case UnaryOperatorKind.PostfixIncrement: case UnaryOperatorKind.PostfixDecrement: case UnaryOperatorKind.PrefixIncrement: case UnaryOperatorKind.PrefixDecrement: case UnaryOperatorKind.BitwiseComplement: operators.Add(new UnaryOperatorSignature(kind | UnaryOperatorKind.Enum, enumType, enumType)); operators.Add(new UnaryOperatorSignature(kind | UnaryOperatorKind.Lifted | UnaryOperatorKind.Enum, nullableEnum, nullableEnum)); break; } }
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 UnaryOperatorAnalysisResult UnaryOperatorOverloadResolution( UnaryOperatorKind kind, BoundExpression operand, CSharpSyntaxNode node, DiagnosticBag diagnostics, out LookupResultKind resultKind, out ImmutableArray<MethodSymbol> originalUserDefinedOperators) { var result = UnaryOperatorOverloadResolutionResult.GetInstance(); HashSet<DiagnosticInfo> useSiteDiagnostics = null; this.OverloadResolution.UnaryOperatorOverloadResolution(kind, operand, result, ref useSiteDiagnostics); diagnostics.Add(node, useSiteDiagnostics); var possiblyBest = result.Best; if (result.Results.Any()) { var builder = ArrayBuilder<MethodSymbol>.GetInstance(); foreach (var analysisResult in result.Results) { MethodSymbol method = analysisResult.Signature.Method; if ((object)method != null) { builder.Add(method); } } originalUserDefinedOperators = builder.ToImmutableAndFree(); if (possiblyBest.HasValue) { resultKind = LookupResultKind.Viable; } else if (result.AnyValid()) { // Special case: If we have the unary minus operator applied to a ulong, technically that should be // an ambiguity. The ulong could be implicitly converted to float, double or decimal, and then // the unary minus operator could be applied to the result. But though float is better than double, // float is neither better nor worse than decimal. However it seems odd to give an ambiguity error // when trying to do something such as applying a unary minus operator to an unsigned long. if (kind == UnaryOperatorKind.UnaryMinus && (object)operand.Type != null && operand.Type.SpecialType == SpecialType.System_UInt64) { resultKind = LookupResultKind.OverloadResolutionFailure; } else { resultKind = LookupResultKind.Ambiguous; } } else { resultKind = LookupResultKind.OverloadResolutionFailure; } } else { originalUserDefinedOperators = ImmutableArray<MethodSymbol>.Empty; resultKind = possiblyBest.HasValue ? LookupResultKind.Viable : LookupResultKind.Empty; } if (possiblyBest.HasValue && (object)possiblyBest.Signature.Method != null) { Symbol symbol = possiblyBest.Signature.Method; ReportDiagnosticsIfObsolete(diagnostics, symbol, node, hasBaseReceiver: false); } result.Free(); return possiblyBest; }
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 ConstantValue FoldEnumUnaryOperator( CSharpSyntaxNode syntax, UnaryOperatorKind kind, BoundExpression operand, DiagnosticBag diagnostics) { var underlyingType = operand.Type.GetEnumUnderlyingType(); BoundExpression newOperand = CreateConversion(operand, underlyingType, diagnostics); // We may have to upconvert the type if it is a byte, sbyte, short, ushort // or nullable of those, because there is no ~ operator var upconvertSpecialType = GetEnumPromotedType(underlyingType.SpecialType); var upconvertType = upconvertSpecialType == underlyingType.SpecialType ? underlyingType : GetSpecialType(upconvertSpecialType, diagnostics, syntax); newOperand = CreateConversion(newOperand, upconvertType, diagnostics); UnaryOperatorKind newKind = kind.Operator().WithType(upconvertSpecialType); var constantValue = FoldUnaryOperator(syntax, newKind, operand, upconvertType.SpecialType, diagnostics); // Convert back to the underlying type if (!constantValue.IsBad) { // Do an unchecked conversion if bitwise complement var binder = kind.Operator() == UnaryOperatorKind.BitwiseComplement ? this.WithCheckedOrUncheckedRegion(@checked: false) : this; return binder.FoldConstantNumericConversion(syntax, constantValue, underlyingType, diagnostics); } return constantValue; }
// Returns an analysis of every matching user-defined binary operator, including whether the // operator is applicable or not. private void GetUserDefinedOperators(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder<UnaryOperatorAnalysisResult> results) { Debug.Assert(operand != null); // UNDONE: Quote spec; // UNDONE: Make effiecient var operandType = operand.Type; if (operandType != null) { GetUserDefinedOperators(kind, operandType, operand, results); } }
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 BoundUnaryOperator( CSharpSyntaxNode syntax, UnaryOperatorKind operatorKind, BoundExpression operand, ConstantValue constantValueOpt, MethodSymbol methodOpt, LookupResultKind resultKind, ImmutableArray<MethodSymbol> originalUserDefinedOperatorsOpt, TypeSymbol type, bool hasErrors = false) : this( syntax, operatorKind, operand, constantValueOpt, methodOpt, resultKind, type, hasErrors) { this.OriginalUserDefinedOperatorsOpt = originalUserDefinedOperatorsOpt; }
public BoundIncrementOperator( CSharpSyntaxNode syntax, UnaryOperatorKind operatorKind, BoundExpression operand, MethodSymbol methodOpt, Conversion operandConversion, Conversion resultConversion, LookupResultKind resultKind, ImmutableArray<MethodSymbol> originalUserDefinedOperatorsOpt, TypeSymbol type, bool hasErrors = false) : this( syntax, operatorKind, operand, methodOpt, operandConversion, resultConversion, resultKind, type, hasErrors) { this.OriginalUserDefinedOperatorsOpt = originalUserDefinedOperatorsOpt; }