public BoundUnaryExpression(SyntaxNode syntax, BoundExpression expression, UnaryOperatorKind operatorKind, TypeSymbol expressionType)
     : base(BoundNodeKind.UnaryExpression, syntax)
 {
     Expression = expression;
     OperatorKind = operatorKind;
     Type = expressionType;
 }
示例#2
0
 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;
        }
示例#4
0
 public BoundUnaryExpression(UnaryOperatorKind operatorKind, BoundExpression expression, OverloadResolutionResult<UnaryOperatorSignature> result)
     : base(BoundNodeKind.UnaryExpression)
 {
     OperatorKind = operatorKind;
     Expression = expression;
     Result = result;
 }
示例#5
0
 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);
 }
示例#6
0
        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;
        }
示例#9
0
        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);
        }
示例#10
0
        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);
        }
示例#11
0
        /// <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);
        }
示例#12
0
        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);
        }
示例#15
0
        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);
            }
        }
示例#16
0
        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);
            }
        }
示例#17
0
        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);
        }
示例#19
0
        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);
        }
示例#21
0
        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);
        }
示例#22
0
        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 { });
示例#23
0
        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();
        }
示例#24
0
        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);
            }
        }
示例#26
0
        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));
        }
示例#27
0
 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);
        }
示例#29
0
        /// <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;
        }
示例#30
0
 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());
     }
 }
示例#31
0
 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;
 }
示例#32
0
        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);
        }
示例#33
0
        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));
        }
示例#34
0
        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));
        }
示例#35
0
        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;
        }
示例#36
0
        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));
        }
示例#39
0
 internal UnaryOperatorSymbol BindUnaryOperation(UnaryExpr expr, UnaryOperatorKind kind)
 {
     return(BindUnaryOperation(expr, kind, Options.Binding));
 }
示例#40
0
        // 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                
            }
        }
示例#42
0
        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();
        }
示例#44
0
        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);
        }
示例#46
0
        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;
        }
示例#51
0
        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;
            }
        }
示例#53
0
        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));
        }
示例#54
0
        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;
        }
示例#55
0
        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);
        }
示例#56
0
        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);
            }
        }
示例#58
0
        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;
        }
示例#59
0
 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;
 }
示例#60
0
 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;
 }