Example #1
0
        public static bool IsValidEnumType(this TypeSymbol type)
        {
            var underlyingType = type.GetEnumUnderlyingType();

            // SpecialType will be None if the underlying type is invalid.
            return(((object)underlyingType != null) && (underlyingType.SpecialType != SpecialType.None));
        }
Example #2
0
        /// <summary>
        /// Return the default value constant for the given type,
        /// or null if the default value is not a constant.
        /// </summary>
        public static ConstantValue GetDefaultValue(this TypeSymbol type)
        {
            // SPEC:    A default-value-expression is a constant expression (§7.19) if the type
            // SPEC:    is a reference type or a type parameter that is known to be a reference type (§10.1.5).
            // SPEC:    In addition, a default-value-expression is a constant expression if the type is
            // SPEC:    one of the following value types:
            // SPEC:    sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, or any enumeration type.

            Debug.Assert((object)type != null);

            if (type.IsErrorType())
            {
                return(null);
            }

            if (type.IsReferenceType)
            {
                return(ConstantValue.Null);
            }

            if (type.IsValueType)
            {
                if (type.IsEnumType())
                {
                    type = type.GetEnumUnderlyingType();
                }

                switch (type.SpecialType)
                {
                case SpecialType.System_SByte:
                case SpecialType.System_Byte:
                case SpecialType.System_Int16:
                case SpecialType.System_UInt16:
                case SpecialType.System_Int32:
                case SpecialType.System_UInt32:
                case SpecialType.System_Int64:
                case SpecialType.System_UInt64:
                case SpecialType.System_Char:
                case SpecialType.System_Boolean:
                case SpecialType.System_Single:
                case SpecialType.System_Double:
                case SpecialType.System_Decimal:
                    return(ConstantValue.Default(type.SpecialType));
                }
            }

            return(null);
        }
        public static void EmitNumericConversion(this CodeGenerator cg, TypeSymbol from, TypeSymbol to, bool @checked = false)
        {
            if (to.IsEnumType())
            {
                to = to.GetEnumUnderlyingType();
            }

            if (from.IsEnumType())
            {
                from = from.GetEnumUnderlyingType();
            }

            var fromcode = from.PrimitiveTypeCode;
            var tocode   = to.PrimitiveTypeCode;

            if (tocode == Microsoft.Cci.PrimitiveTypeCode.Boolean)
            {
                switch (fromcode)
                {
                case Microsoft.Cci.PrimitiveTypeCode.Float32:
                    // Template: !(STACK == 0.0f)
                    cg.Builder.EmitSingleConstant(0.0f);
                    cg.Builder.EmitOpCode(ILOpCode.Ceq);
                    cg.EmitLogicNegation();
                    return;

                case Microsoft.Cci.PrimitiveTypeCode.Float64:
                    // Template: !(STACK == 0.0)
                    cg.Builder.EmitDoubleConstant(0.0);
                    cg.Builder.EmitOpCode(ILOpCode.Ceq);
                    cg.EmitLogicNegation();
                    return;
                }

                // otherwise,
                // treat boolean as to int32 conversion
                tocode = Microsoft.Cci.PrimitiveTypeCode.Int32;
            }

            if (fromcode == Microsoft.Cci.PrimitiveTypeCode.Boolean)
            {
                fromcode = Microsoft.Cci.PrimitiveTypeCode.Int32;
            }

            //
            cg.Builder.EmitNumericConversion(fromcode, tocode, @checked);
        }
Example #4
0
        /// <summary>
        /// Returns true if the type is a valid switch expression type.
        /// </summary>
        internal static bool IsValidSwitchGoverningType(this TypeSymbol type, bool isTargetTypeOfUserDefinedOp = false)
        {
            // SPEC:    The governing type of a switch statement is established by the switch expression.
            // SPEC:    1) If the type of the switch expression is sbyte, byte, short, ushort, int, uint,
            // SPEC:       long, ulong, bool, char, string, or an enum-type, or if it is the nullable type
            // SPEC:       corresponding to one of these types, then that is the governing type of the switch statement.
            // SPEC:    2) Otherwise, exactly one user-defined implicit conversion (§6.4) must exist from the
            // SPEC:       type of the switch expression to one of the following possible governing types:
            // SPEC:       sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or, a nullable type
            // SPEC:       corresponding to one of those types

            Debug.Assert((object)type != null);
            if (type.IsNullableType())
            {
                type = type.GetNullableUnderlyingType();
            }

            // User-defined implicit conversion with target type as Enum type is not valid.
            if (!isTargetTypeOfUserDefinedOp && type.IsEnumType())
            {
                type = type.GetEnumUnderlyingType();
            }

            switch (type.SpecialType)
            {
            case SpecialType.System_SByte:
            case SpecialType.System_Byte:
            case SpecialType.System_Int16:
            case SpecialType.System_UInt16:
            case SpecialType.System_Int32:
            case SpecialType.System_UInt32:
            case SpecialType.System_Int64:
            case SpecialType.System_UInt64:
            case SpecialType.System_Char:
            case SpecialType.System_String:
                return(true);

            case SpecialType.System_Boolean:
                // User-defined implicit conversion with target type as bool type is not valid.
                return(!isTargetTypeOfUserDefinedOp);
            }

            return(false);
        }
Example #5
0
        static (bool floating, bool signed, int size) ClassifyNumericType(TypeSymbol type)
        {
            switch (type.SpecialType)
            {
            case SpecialType.System_Boolean: return(false, false, 1);      // we classsify boolean as a number as well!

            case SpecialType.System_Char: return(false, false, 8);

            case SpecialType.System_SByte: return(false, true, 8);

            case SpecialType.System_Byte: return(false, false, 8);

            case SpecialType.System_Int16: return(false, true, 16);

            case SpecialType.System_UInt16: return(false, false, 16);

            case SpecialType.System_Int32: return(false, true, 32);

            case SpecialType.System_UInt32: return(false, false, 32);

            case SpecialType.System_Int64: return(false, true, 64);

            case SpecialType.System_UInt64: return(false, false, 64);

            //case SpecialType.System_IntPtr: return (false, true, 64);
            //case SpecialType.System_UIntPtr: return (false, false, 64);
            case SpecialType.System_Single: return(true, true, 32);

            case SpecialType.System_Double: return(true, true, 64);

            case SpecialType.System_Decimal: return(true, true, 128);

            default:

                if (type.IsEnumType())
                {
                    return(ClassifyNumericType(type.GetEnumUnderlyingType()));
                }

                return(default);
            }
        }
        private void GetEnumOperation(BinaryOperatorKind kind, TypeSymbol enumType, BoundExpression left, BoundExpression right, ArrayBuilder<BinaryOperatorSignature> operators)
        {
            Debug.Assert((object)enumType != null);
            AssertNotChecked(kind);

            if (!enumType.IsValidEnumType())
            {
                return;
            }

            var underlying = enumType.GetEnumUnderlyingType();
            Debug.Assert((object)underlying != null);
            Debug.Assert(underlying.SpecialType != SpecialType.None);

            NamedTypeSymbol nullableEnum = null;
            NamedTypeSymbol nullableUnderlying = null;

            // PERF: avoid instantiating nullable types in common simple cases.
            var leftType = left.Type;
            var rightType = right.Type;
            var simpleCase = leftType?.IsValueType == true &&
                             rightType?.IsValueType == true &&
                             leftType.IsNullableType() == false &&
                             rightType.IsNullableType() == false;

            if (!simpleCase)
            {
                var nullable = Compilation.GetSpecialType(SpecialType.System_Nullable_T);
                nullableEnum = nullable.Construct(enumType);
                nullableUnderlying = nullable.Construct(underlying);
            }

            switch (kind)
            {
                case BinaryOperatorKind.Addition:
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumAndUnderlyingAddition, enumType, underlying, enumType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.UnderlyingAndEnumAddition, underlying, enumType, enumType));
                    if (!simpleCase)
                    {
                        operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumAndUnderlyingAddition, nullableEnum, nullableUnderlying, nullableEnum));
                        operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedUnderlyingAndEnumAddition, nullableUnderlying, nullableEnum, nullableEnum));
                    }
                    break;
                case BinaryOperatorKind.Subtraction:
                    if (Strict)
                    {
                        operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumSubtraction, enumType, enumType, underlying));
                        operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumAndUnderlyingSubtraction, enumType, underlying, enumType));
                        if (!simpleCase)
                        {
                            operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumSubtraction, nullableEnum, nullableEnum, nullableUnderlying));
                            operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumAndUnderlyingSubtraction, nullableEnum, nullableUnderlying, nullableEnum));
                        }
                    }
                    else
                    {
                        // SPEC VIOLATION:
                        // The native compiler has bugs in overload resolution involving binary operator- for enums,
                        // which we duplicate by hardcoding Priority values among the operators. When present on both
                        // methods being compared during overload resolution, Priority values are used to decide between
                        // two candidates (instead of the usual language-specified rules).
                        bool isExactSubtraction = right.Type?.StrippedType() == underlying;
                        operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumSubtraction, enumType, enumType, underlying)
                        { Priority = 2 });
                        operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumAndUnderlyingSubtraction, enumType, underlying, enumType)
                        { Priority = isExactSubtraction ? 1 : 3 });
                        if (!simpleCase)
                        {
                            operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumSubtraction, nullableEnum, nullableEnum, nullableUnderlying)
                            { Priority = 12 });
                            operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumAndUnderlyingSubtraction, nullableEnum, nullableUnderlying, nullableEnum)
                            { Priority = isExactSubtraction ? 11 : 13 });
                        }

                        // Due to a bug, the native compiler allows "underlying - enum", so Roslyn does as well.
                        operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.UnderlyingAndEnumSubtraction, underlying, enumType, enumType)
                        { Priority = 4 });
                        if (!simpleCase)
                        {
                            operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedUnderlyingAndEnumSubtraction, nullableUnderlying, nullableEnum, nullableEnum)
                            { Priority = 14 });
                        }
                    }
                    break;
                case BinaryOperatorKind.Equal:
                case BinaryOperatorKind.NotEqual:
                case BinaryOperatorKind.GreaterThan:
                case BinaryOperatorKind.LessThan:
                case BinaryOperatorKind.GreaterThanOrEqual:
                case BinaryOperatorKind.LessThanOrEqual:
                    var boolean = Compilation.GetSpecialType(SpecialType.System_Boolean);
                    operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Enum, enumType, enumType, boolean));
                    if (!simpleCase)
                    {
                        operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Lifted | BinaryOperatorKind.Enum, nullableEnum, nullableEnum, boolean));
                    }
                    break;
                case BinaryOperatorKind.And:
                case BinaryOperatorKind.Or:
                case BinaryOperatorKind.Xor:
                    operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Enum, enumType, enumType, enumType));
                    if (!simpleCase)
                    {
                        operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Lifted | BinaryOperatorKind.Enum, nullableEnum, nullableEnum, nullableEnum));
                    }
                    break;
            }
        }
Example #7
0
        internal override int GetTargetAttributeSignatureIndex(Symbol targetSymbol, AttributeDescription description)
        {
            if (!IsTargetAttribute(description.Namespace, description.Name))
            {
                return(-1);
            }

            var ctor = this.AttributeConstructor;

            // Ensure that the attribute data really has a constructor before comparing the signature.
            if (ctor is null)
            {
                return(-1);
            }

            // Lazily loaded System.Type type symbol
            TypeSymbol?lazySystemType = null;

            ImmutableArray <ParameterSymbol> parameters = ctor.Parameters;
            bool foundMatch = false;

            for (int i = 0; i < description.Signatures.Length; i++)
            {
                byte[] targetSignature = description.Signatures[i];
                if (targetSignature[0] != (byte)SignatureAttributes.Instance)
                {
                    continue;
                }

                byte parameterCount = targetSignature[1];
                if (parameterCount != parameters.Length)
                {
                    continue;
                }

                if ((SignatureTypeCode)targetSignature[2] != SignatureTypeCode.Void)
                {
                    continue;
                }

                foundMatch = (targetSignature.Length == 3);
                int k = 0;
                for (int j = 3; j < targetSignature.Length; j++)
                {
                    if (k >= parameters.Length)
                    {
                        break;
                    }

                    TypeSymbol  parameterType = parameters[k].Type;
                    SpecialType specType      = parameterType.SpecialType;
                    byte        targetType    = targetSignature[j];

                    if (targetType == (byte)SignatureTypeCode.TypeHandle)
                    {
                        j++;

                        if (parameterType.Kind != SymbolKind.NamedType && parameterType.Kind != SymbolKind.ErrorType)
                        {
                            foundMatch = false;
                            break;
                        }

                        var namedType = (NamedTypeSymbol)parameterType;
                        AttributeDescription.TypeHandleTargetInfo targetInfo = AttributeDescription.TypeHandleTargets[targetSignature[j]];

                        // Compare name and containing symbol name. Uses HasNameQualifier
                        // extension method to avoid string allocations.
                        if (!string.Equals(namedType.MetadataName, targetInfo.Name, System.StringComparison.Ordinal) ||
                            !namedType.HasNameQualifier(targetInfo.Namespace))
                        {
                            foundMatch = false;
                            break;
                        }

                        targetType = (byte)targetInfo.Underlying;

                        if (parameterType.IsEnumType())
                        {
                            specType = parameterType.GetEnumUnderlyingType() !.SpecialType;
                        }
                    }
                    else if (parameterType.IsArray())
                    {
                        specType = ((ArrayTypeSymbol)parameterType).ElementType.SpecialType;
                    }

                    switch (targetType)
                    {
                    case (byte)SignatureTypeCode.Boolean:
                        foundMatch = specType == SpecialType.System_Boolean;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Char:
                        foundMatch = specType == SpecialType.System_Char;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.SByte:
                        foundMatch = specType == SpecialType.System_SByte;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Byte:
                        foundMatch = specType == SpecialType.System_Byte;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Int16:
                        foundMatch = specType == SpecialType.System_Int16;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt16:
                        foundMatch = specType == SpecialType.System_UInt16;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Int32:
                        foundMatch = specType == SpecialType.System_Int32;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt32:
                        foundMatch = specType == SpecialType.System_UInt32;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Int64:
                        foundMatch = specType == SpecialType.System_Int64;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt64:
                        foundMatch = specType == SpecialType.System_UInt64;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Single:
                        foundMatch = specType == SpecialType.System_Single;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Double:
                        foundMatch = specType == SpecialType.System_Double;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.String:
                        foundMatch = specType == SpecialType.System_String;
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.Object:
                        foundMatch = specType == SpecialType.System_Object;
                        k         += 1;
                        break;

                    case (byte)SerializationTypeCode.Type:
                        if (lazySystemType is null)
                        {
                            lazySystemType = GetSystemType(targetSymbol);
                        }

                        foundMatch = TypeSymbol.Equals(parameterType, lazySystemType, TypeCompareKind.ConsiderEverything2);
                        k         += 1;
                        break;

                    case (byte)SignatureTypeCode.SZArray:
                        // Skip over and check the next byte
                        foundMatch = parameterType.IsArray();
                        break;

                    default:
                        return(-1);
                    }

                    if (!foundMatch)
                    {
                        break;
                    }
                }

                if (foundMatch)
                {
                    return(i);
                }
            }

            Debug.Assert(!foundMatch);
            return(-1);
        }
        private void GetEnumOperation(BinaryOperatorKind kind, TypeSymbol enumType, ArrayBuilder<BinaryOperatorSignature> operators)
        {
            Debug.Assert(enumType != null);

            if (!enumType.IsValidEnumType())
            {
                return;
            }

            var underlying = enumType.GetEnumUnderlyingType();
            Debug.Assert(underlying != null);
            Debug.Assert(underlying.SpecialType != SpecialType.None);

            var nullable = Compilation.GetSpecialType(SpecialType.System_Nullable_T);
            var nullableEnum = nullable.Construct(enumType);
            var nullableUnderlying = nullable.Construct(underlying);

            switch (kind)
            {
                case BinaryOperatorKind.Addition:
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumAndUnderlyingAddition, enumType, underlying, enumType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.UnderlyingAndEnumAddition, underlying, enumType, enumType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumAndUnderlyingAddition, nullableEnum, nullableUnderlying, nullableEnum));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedUnderlyingAndEnumAddition, nullableUnderlying, nullableEnum, nullableEnum));
                    break;
                case BinaryOperatorKind.Subtraction:
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumSubtraction, enumType, enumType, underlying));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumAndUnderlyingSubtraction, enumType, underlying, enumType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumSubtraction, nullableEnum, nullableEnum, nullableUnderlying));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumAndUnderlyingSubtraction, nullableEnum, nullableUnderlying, nullableEnum));
                    break;
                case BinaryOperatorKind.Equal:
                case BinaryOperatorKind.NotEqual:
                case BinaryOperatorKind.GreaterThan:
                case BinaryOperatorKind.LessThan:
                case BinaryOperatorKind.GreaterThanOrEqual:
                case BinaryOperatorKind.LessThanOrEqual:
                    var boolean = Compilation.GetSpecialType(SpecialType.System_Boolean);
                    operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Enum, enumType, enumType, boolean));
                    operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Lifted | BinaryOperatorKind.Enum, nullableEnum, nullableEnum, boolean));
                    break;
                case BinaryOperatorKind.And:
                case BinaryOperatorKind.Or:
                case BinaryOperatorKind.Xor:
                    operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Enum, enumType, enumType, enumType));
                    operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Lifted | BinaryOperatorKind.Enum, nullableEnum, nullableEnum, nullableEnum));
                    break;
            }
        }
        /// <summary>
        /// Helper method to generate a lowered conversion.
        /// </summary>
        private BoundExpression MakeConversion(
            BoundConversion oldNode,
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenOperand,
            ConversionKind conversionKind,
            MethodSymbol symbolOpt,
            bool @checked,
            bool explicitCastInCode,
            bool isExtensionMethod,
            bool isArrayIndex,
            ConstantValue constantValueOpt,
            TypeSymbol rewrittenType)
        {
            Debug.Assert(oldNode == null || oldNode.Syntax == syntax);
            Debug.Assert((object)rewrittenType != null);
            @checked = @checked &&
                (inExpressionLambda && (explicitCastInCode || DistinctSpecialTypes(rewrittenOperand.Type, rewrittenType)) ||
                NeedsChecked(rewrittenOperand.Type, rewrittenType));

            switch (conversionKind)
            {
                case ConversionKind.Identity:

                    // Spec 6.1.1:
                    //   An identity conversion converts from any type to the same type. 
                    //   This conversion exists such that an entity that already has a required type can be said to be convertible to that type.
                    //   Because object and dynamic are considered equivalent there is an identity conversion between object and dynamic, 
                    //   and between constructed types that are the same when replacing all occurrences of dynamic with object.

                    // Why ignoreDynamic: false?
                    // Lowering phase treats object and dynamic as equivalent types. So we don't need to produce any conversion here,
                    // but we need to change the Type property on the resulting BoundExpression to match the rewrittenType.
                    // This is necessary so that subsequent lowering transformations see that the expression is dynamic.

                    if (inExpressionLambda || !rewrittenOperand.Type.Equals(rewrittenType, ignoreCustomModifiers: false, ignoreDynamic: false))
                    {
                        break;
                    }

                    // 4.1.6 C# spec: To force a value of a floating point type to the exact precision of its type, an explicit cast can be used.
                    // If this is not an identity conversion of a float with unknown precision, strip away the identity conversion.
                    if (!(explicitCastInCode && IsFloatPointExpressionOfUnknownPrecision(rewrittenOperand)))
                    {
                        return rewrittenOperand;
                    }

                    break;

                case ConversionKind.ExplicitUserDefined:
                case ConversionKind.ImplicitUserDefined:
                    return RewriteUserDefinedConversion(
                        syntax: syntax,
                        rewrittenOperand: rewrittenOperand,
                        method: symbolOpt,
                        rewrittenType: rewrittenType,
                        conversionKind: conversionKind);

                case ConversionKind.IntPtr:
                    return RewriteIntPtrConversion(oldNode, syntax, rewrittenOperand, conversionKind, symbolOpt, @checked,
                        explicitCastInCode, isExtensionMethod, isArrayIndex, constantValueOpt, rewrittenType);

                case ConversionKind.ImplicitNullable:
                case ConversionKind.ExplicitNullable:
                    return RewriteNullableConversion(
                        syntax: syntax,
                        rewrittenOperand: rewrittenOperand,
                        conversionKind: conversionKind,
                        @checked: @checked,
                        explicitCastInCode: explicitCastInCode,
                        rewrittenType: rewrittenType);

                case ConversionKind.Boxing:

                    if (!inExpressionLambda)
                    {
                        // We can perform some optimizations if we have a nullable value type
                        // as the operand and we know its nullability:

                        // * (object)new int?() is the same as (object)null
                        // * (object)new int?(123) is the same as (object)123

                        if (NullableNeverHasValue(rewrittenOperand))
                        {
                            return new BoundDefaultOperator(syntax, rewrittenType);
                        }

                        BoundExpression nullableValue = NullableAlwaysHasValue(rewrittenOperand);
                        if (nullableValue != null)
                        {
                            // Recurse, eliminating the unnecessary ctor.
                            return MakeConversion(oldNode, syntax, nullableValue, conversionKind,
                                symbolOpt, @checked, explicitCastInCode, isExtensionMethod, isArrayIndex,
                                constantValueOpt, rewrittenType);
                        }
                    }
                    break;

                case ConversionKind.NullLiteral:
                    if (!inExpressionLambda || !explicitCastInCode)
                    {
                        return new BoundDefaultOperator(syntax, rewrittenType);
                    }

                    break;

                case ConversionKind.ImplicitReference:
                case ConversionKind.ExplicitReference:
                    if (rewrittenOperand.IsDefaultValue() && (!inExpressionLambda || !explicitCastInCode))
                    {
                        return new BoundDefaultOperator(syntax, rewrittenType);
                    }

                    break;

                case ConversionKind.ImplicitNumeric:
                case ConversionKind.ExplicitNumeric:
                    if (rewrittenOperand.IsDefaultValue() && (!inExpressionLambda || !explicitCastInCode))
                    {
                        return new BoundDefaultOperator(syntax, rewrittenType);
                    }

                    if (rewrittenType.SpecialType == SpecialType.System_Decimal || rewrittenOperand.Type.SpecialType == SpecialType.System_Decimal)
                    {
                        return RewriteDecimalConversion(oldNode, syntax, rewrittenOperand, rewrittenOperand.Type, rewrittenType);
                    }
                    break;

                case ConversionKind.ImplicitEnumeration:
                    // A conversion from constant zero to nullable is actually classified as an 
                    // implicit enumeration conversion, not an implicit nullable conversion. 
                    // Lower it to (E?)(E)0.
                    if (rewrittenType.IsNullableType())
                    {
                        var operand = MakeConversion(
                            oldNode,
                            syntax,
                            rewrittenOperand,
                            ConversionKind.ImplicitEnumeration,
                            symbolOpt,
                            @checked,
                            explicitCastInCode,
                            isExtensionMethod,
                            false,
                            constantValueOpt,
                            rewrittenType.GetNullableUnderlyingType());

                        return MakeConversion(
                            oldNode,
                            syntax,
                            operand,
                            ConversionKind.ImplicitNullable,
                            symbolOpt,
                            @checked,
                            explicitCastInCode,
                            isExtensionMethod,
                            isArrayIndex,
                            constantValueOpt,
                            rewrittenType);
                    }

                    goto case ConversionKind.ExplicitEnumeration;

                case ConversionKind.ExplicitEnumeration:
                    if (!rewrittenType.IsNullableType() &&
                        rewrittenOperand.IsDefaultValue() &&
                        (!inExpressionLambda || !explicitCastInCode))
                    {
                        return new BoundDefaultOperator(syntax, rewrittenType);
                    }

                    if (rewrittenType.SpecialType == SpecialType.System_Decimal)
                    {
                        Debug.Assert(rewrittenOperand.Type.IsEnumType());
                        var underlyingTypeFrom = rewrittenOperand.Type.GetEnumUnderlyingType();
                        rewrittenOperand = MakeConversion(rewrittenOperand, underlyingTypeFrom, false);
                        return RewriteDecimalConversion(oldNode, syntax, rewrittenOperand, underlyingTypeFrom, rewrittenType);
                    }
                    else if (rewrittenOperand.Type.SpecialType == SpecialType.System_Decimal)
                    {
                        // This is where we handle conversion from Decimal to Enum: e.g., E e = (E) d;
                        // where 'e' is of type Enum E and 'd' is of type Decimal.
                        // Conversion can be simply done by applying its underlying numeric type to RewriteDecimalConversion(). 

                        Debug.Assert(rewrittenType.IsEnumType());
                        var underlyingTypeTo = rewrittenType.GetEnumUnderlyingType();
                        var rewrittenNode = RewriteDecimalConversion(oldNode, syntax, rewrittenOperand, rewrittenOperand.Type, underlyingTypeTo);

                        // However, the type of the rewritten node becomes underlying numeric type, not Enum type,
                        // which violates the overall constraint saying the type cannot be changed during rewriting (see LocalRewriter.cs).

                        // Instead of loosening this constraint, we return BoundConversion from underlying numeric type to Enum type,
                        // which will be eliminated during emitting (see EmitEnumConversion): e.g., E e = (E)(int) d;

                        return new BoundConversion(
                            syntax,
                            rewrittenNode,
                            conversionKind,
                            LookupResultKind.Viable,
                            isBaseConversion: false,
                            symbolOpt: symbolOpt,
                            @checked: false,
                            explicitCastInCode: explicitCastInCode,
                            isExtensionMethod: isExtensionMethod,
                            isArrayIndex: false,
                            constantValueOpt: constantValueOpt,
                            type: rewrittenType);
                    }

                    break;

                case ConversionKind.ImplicitDynamic:
                case ConversionKind.ExplicitDynamic:
                    Debug.Assert((object)symbolOpt == null);
                    Debug.Assert(!isExtensionMethod);
                    Debug.Assert(constantValueOpt == null);
                    return dynamicFactory.MakeDynamicConversion(rewrittenOperand, explicitCastInCode || conversionKind == ConversionKind.ExplicitDynamic, isArrayIndex, @checked, rewrittenType).ToExpression();

                default:
                    break;
            }

            return oldNode != null ?
                oldNode.Update(
                    rewrittenOperand,
                    conversionKind,
                    oldNode.ResultKind,
                    isBaseConversion: oldNode.IsBaseConversion,
                    symbolOpt: symbolOpt,
                    @checked: @checked,
                    explicitCastInCode: explicitCastInCode,
                    isExtensionMethod: isExtensionMethod,
                    isArrayIndex: isArrayIndex,
                    constantValueOpt: constantValueOpt,
                    type: rewrittenType) :
                new BoundConversion(
                    syntax,
                    rewrittenOperand,
                    conversionKind,
                    LookupResultKind.Viable,
                    isBaseConversion: false,
                    symbolOpt: symbolOpt,
                    @checked: @checked,
                    explicitCastInCode: explicitCastInCode,
                    isExtensionMethod: isExtensionMethod,
                    isArrayIndex: isArrayIndex,
                    constantValueOpt: constantValueOpt,
                    type: rewrittenType);
        }
 private Conversion MakeConversion(CSharpSyntaxNode syntax, Conversion conversion, TypeSymbol fromType, TypeSymbol toType)
 {
     switch (conversion.Kind)
     {
         case ConversionKind.ExplicitUserDefined:
         case ConversionKind.ImplicitUserDefined:
             {
                 var meth = conversion.Method;
                 Conversion fromConversion = MakeConversion(syntax, conversion.UserDefinedFromConversion, fromType, meth.Parameters[0].Type);
                 Conversion toConversion = MakeConversion(syntax, conversion.UserDefinedToConversion, meth.ReturnType, toType);
                 if (fromConversion == conversion.UserDefinedFromConversion && toConversion == conversion.UserDefinedToConversion)
                 {
                     return conversion;
                 }
                 else
                 {
                     // TODO: how do we distinguish from normal and lifted conversions here?
                     var analysis = UserDefinedConversionAnalysis.Normal(meth, fromConversion, toConversion, fromType, toType);
                     var result = UserDefinedConversionResult.Valid(ImmutableArray.Create<UserDefinedConversionAnalysis>(analysis), 0);
                     return new Conversion(result, conversion.IsImplicit);
                 }
             }
         case ConversionKind.IntPtr:
             {
                 SpecialMember member = GetIntPtrConversionMethod(fromType, toType);
                 MethodSymbol method = GetSpecialTypeMethod(syntax, member);
                 return MakeUserDefinedConversion(syntax, method, fromType, toType, conversion.IsImplicit);
             }
         case ConversionKind.ImplicitNumeric:
         case ConversionKind.ExplicitNumeric:
             // TODO: what about nullable?
             if (fromType.SpecialType == SpecialType.System_Decimal || toType.SpecialType == SpecialType.System_Decimal)
             {
                 SpecialMember member = DecimalConversionMethod(fromType, toType);
                 MethodSymbol method = GetSpecialTypeMethod(syntax, member);
                 return MakeUserDefinedConversion(syntax, method, fromType, toType, conversion.IsImplicit);
             }
             return conversion;
         case ConversionKind.ImplicitEnumeration:
         case ConversionKind.ExplicitEnumeration:
             // TODO: what about nullable?
             if (fromType.SpecialType == SpecialType.System_Decimal)
             {
                 SpecialMember member = DecimalConversionMethod(fromType, toType.GetEnumUnderlyingType());
                 MethodSymbol method = GetSpecialTypeMethod(syntax, member);
                 return MakeUserDefinedConversion(syntax, method, fromType, toType, conversion.IsImplicit);
             }
             else if (toType.SpecialType == SpecialType.System_Decimal)
             {
                 SpecialMember member = DecimalConversionMethod(fromType.GetEnumUnderlyingType(), toType);
                 MethodSymbol method = GetSpecialTypeMethod(syntax, member);
                 return MakeUserDefinedConversion(syntax, method, fromType, toType, conversion.IsImplicit);
             }
             return conversion;
         default:
             return conversion;
     }
 }
        public static void EmitNumericConversion(this CodeGenerator cg, TypeSymbol from, TypeSymbol to, bool @checked = false)
        {
            if (to.IsEnumType())
            {
                to = to.GetEnumUnderlyingType();
            }

            if (from.IsEnumType())
            {
                from = from.GetEnumUnderlyingType();
            }

            if (from.SpecialType == SpecialType.System_Decimal)
            {
                // explicit numeric conversion, treating decimal as double

                // (double)System.Decimal
                cg.EmitCall(
                    ILOpCode.Call,
                    (MethodSymbol)cg.DeclaringCompilation.GetSpecialTypeMember(SpecialMember.System_Decimal__op_Explicit_ToDouble));
                cg.Builder.EmitOpCode(ILOpCode.Conv_r8);

                //
                from = cg.CoreTypes.Double;
            }

            if (to.SpecialType == SpecialType.System_Decimal)
            {
                EmitNumericConversionToDecimal(cg, from, @checked);
                return;
            }

            var fromcode = from.PrimitiveTypeCode;
            var tocode   = to.PrimitiveTypeCode;

            if (fromcode == tocode)
            {
                return;
            }

            if (tocode == Microsoft.Cci.PrimitiveTypeCode.Boolean)
            {
                switch (fromcode)
                {
                case Microsoft.Cci.PrimitiveTypeCode.Float32:
                    // Template: !(STACK == 0.0f)
                    cg.Builder.EmitSingleConstant(0.0f);
                    cg.Builder.EmitOpCode(ILOpCode.Ceq);
                    cg.EmitLogicNegation();
                    return;

                case Microsoft.Cci.PrimitiveTypeCode.Float64:
                    // Template: !(STACK == 0.0)
                    cg.Builder.EmitDoubleConstant(0.0);
                    cg.Builder.EmitOpCode(ILOpCode.Ceq);
                    cg.EmitLogicNegation();
                    return;
                }

                // otherwise,
                // treat boolean as to int32 conversion
                tocode = Microsoft.Cci.PrimitiveTypeCode.Int32;
            }

            if (fromcode == Microsoft.Cci.PrimitiveTypeCode.Boolean)
            {
                fromcode = Microsoft.Cci.PrimitiveTypeCode.Int32;
            }

            //
            cg.Builder.EmitNumericConversion(fromcode, tocode, @checked);
        }
Example #12
0
        /// <summary>
        /// Gets the typed constant kind for the given attribute parameter type.
        /// </summary>
        /// <param name="type">Type to validated</param>
        /// <param name="compilation">compilation</param>
        /// <returns>TypedConstantKind for the attribute parameter type.</returns>
        public static TypedConstantKind GetAttributeParameterTypedConstantKind(this TypeSymbol type, CSharpCompilation compilation)
        {
            // Spec (17.1.3)
            // The types of positional and named parameters for an attribute class are limited to the attribute parameter types, which are:
            //  1) One of the following types: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
            //     2) The type object.
            //     3) The type System.Type.
            //     4) An enum type, provided it has public accessibility and the types in which it is nested (if any) also have public accessibility.
            //     5) Single-dimensional arrays of the above types.
            // A constructor argument or public field which does not have one of these types, cannot be used as a positional
            // or named parameter in an attribute specification.

            TypedConstantKind kind = TypedConstantKind.Error;

            if ((object)type == null)
            {
                return(TypedConstantKind.Error);
            }

            if (type.Kind == SymbolKind.ArrayType)
            {
                var arrayType = (ArrayTypeSymbol)type;
                if (arrayType.Rank != 1)
                {
                    return(TypedConstantKind.Error);
                }

                kind = TypedConstantKind.Array;
                type = arrayType.ElementType;
            }

            // enum or enum[]
            if (type.IsEnumType())
            {
                // SPEC VIOLATION: Dev11 doesn't enforce either the Enum type or its enclosing types (if any) to have public accessibility.
                // We will be consistent with Dev11 behavior.

                if (kind == TypedConstantKind.Error)
                {
                    // set only if kind is not already set (i.e. its not an array of enum)
                    kind = TypedConstantKind.Enum;
                }

                type = type.GetEnumUnderlyingType();
            }

            var typedConstantKind = TypedConstant.GetTypedConstantKind(type, compilation);

            switch (typedConstantKind)
            {
            case TypedConstantKind.Array:
            case TypedConstantKind.Enum:
            case TypedConstantKind.Error:
                return(TypedConstantKind.Error);

            default:
                if (kind == TypedConstantKind.Array || kind == TypedConstantKind.Enum)
                {
                    // Array/Enum type with valid element/underlying type
                    return(kind);
                }

                return(typedConstantKind);
            }
        }
Example #13
0
        internal TypeSymbol GetVOGlobalType(CSharpCompilation compilation, TypeSyntax typeSyntax, Binder binder, ConsList <FieldSymbol> fieldsBeingBound)
        {
            var xNode = this.SyntaxNode.XNode;

            if (compilation.Options.HasOption(CompilerOption.ResolveTypedFunctionPointersToPtr, this.SyntaxNode))
            {
                if (xNode is XP.ClassvarContext &&
                    xNode.Parent is XP.ClassVarListContext)
                {
                    var cvl = xNode.Parent as XP.ClassVarListContext;
                    var dt  = cvl.DataType;
                    if (dt is XP.PtrDatatypeContext)
                    {
                        // So we have a global as typed ptr
                        // change the type from typed ptr to just ptr
                        var ptrdtc = dt as XP.PtrDatatypeContext;
                        if (ptrdtc.TypeName.Name != null)           // User Define Typename PTR
                        {
                            string name = ptrdtc.TypeName.Name.GetText();
                            // Lookup name ?
                            return(compilation.GetSpecialType(SpecialType.System_IntPtr));
                        }
                    }
                }
                if (xNode is XP.VostructmemberContext smc)
                {
                    var dt = smc.DataType;
                    if (dt is XP.PtrDatatypeContext)
                    {
                        // So we have a global as typed ptr
                        // change the type from typed ptr to just ptr
                        var ptrdtc = dt as XP.PtrDatatypeContext;
                        if (ptrdtc.TypeName.Name != null)           // User Define Typename PTR
                        {
                            string name = ptrdtc.TypeName.Name.GetText();
                            // Lookup name ?
                            return(compilation.GetSpecialType(SpecialType.System_IntPtr));
                        }
                    }
                }
            }
            TypeSymbol type = null;

            if (xNode is XP.VodefineContext && !this.IsConst)
            {
                var           vodef       = xNode as XP.VodefineContext;
                DiagnosticBag diagnostics = DiagnosticBag.GetInstance();
                type = binder.BindType(typeSyntax, diagnostics);
                // parser could not determine the type
                fieldsBeingBound = new ConsList <FieldSymbol>(this, fieldsBeingBound);
                var declarator        = (VariableDeclaratorSyntax)this.DeclaringSyntaxReferences.AsSingleton().GetSyntax();
                var initializerBinder = new ImplicitlyTypedFieldBinder(binder, fieldsBeingBound);
                var initializerOpt    = initializerBinder.BindInferredVariableInitializer(diagnostics, RefKind.None, declarator.Initializer, declarator);
                if (initializerOpt != null && !type.IsPsz())
                {
                    if ((object)initializerOpt.Type != null && !initializerOpt.Type.IsErrorType())
                    {
                        type = initializerOpt.Type;

                        if (!type.IsVoidPointer() && initializerOpt.ConstantValue != null && !this.IsConst)
                        {
                            this._modifiers |= DeclarationModifiers.Const;
                            this._modifiers |= DeclarationModifiers.Static;
                            this._modifiers &= ~DeclarationModifiers.ReadOnly;
                        }
                        if (type.IsEnumType())
                        {
                            type = type.GetEnumUnderlyingType();
                        }
                    }
                }
                if (type == null)
                {
                    type = compilation.GetSpecialType(SpecialType.System_Object);
                }
                //System.Diagnostics.Debug.WriteLine($"Looking for type of define {vodef.Name.ToString()}, found {type.ToString()}, const: {IsConst}");

                return(type);
            }
            return(null);
        }
Example #14
0
        internal override int GetTargetAttributeSignatureIndex(Symbol targetSymbol, AttributeDescription description)
        {
            if (!IsTargetAttribute(description.Namespace, description.Name))
            {
                return(-1);
            }

            var ctor = this.AttributeConstructor;

            // Ensure that the attribute data really has a constructor before comparing the signature.
            if (ctor is null)
            {
                return(-1);
            }

            // Lazily loaded System.Type type symbol
            TypeSymbol?lazySystemType = null;

            ImmutableArray <ParameterSymbol> parameters = ctor.Parameters;

            for (int signatureIndex = 0; signatureIndex < description.Signatures.Length; signatureIndex++)
            {
                byte[] targetSignature = description.Signatures[signatureIndex];

                if (matches(targetSignature, parameters, ref lazySystemType))
                {
                    return(signatureIndex);
                }
            }

            return(-1);

            bool matches(byte[] targetSignature, ImmutableArray <ParameterSymbol> parameters, ref TypeSymbol?lazySystemType)
            {
                if (targetSignature[0] != (byte)SignatureAttributes.Instance)
                {
                    return(false);
                }

                byte parameterCount = targetSignature[1];

                if (parameterCount != parameters.Length)
                {
                    return(false);
                }

                if ((SignatureTypeCode)targetSignature[2] != SignatureTypeCode.Void)
                {
                    return(false);
                }

                int parameterIndex = 0;

                for (int signatureByteIndex = 3; signatureByteIndex < targetSignature.Length; signatureByteIndex++)
                {
                    if (parameterIndex >= parameters.Length)
                    {
                        return(false);
                    }

                    TypeSymbol  parameterType = parameters[parameterIndex].Type;
                    SpecialType specType      = parameterType.SpecialType;
                    byte        targetType    = targetSignature[signatureByteIndex];

                    if (targetType == (byte)SignatureTypeCode.TypeHandle)
                    {
                        signatureByteIndex++;

                        if (parameterType.Kind != SymbolKind.NamedType && parameterType.Kind != SymbolKind.ErrorType)
                        {
                            return(false);
                        }

                        var namedType = (NamedTypeSymbol)parameterType;
                        AttributeDescription.TypeHandleTargetInfo targetInfo = AttributeDescription.TypeHandleTargets[targetSignature[signatureByteIndex]];

                        // Compare name and containing symbol name. Uses HasNameQualifier
                        // extension method to avoid string allocations.
                        if (!string.Equals(namedType.MetadataName, targetInfo.Name, System.StringComparison.Ordinal) ||
                            !namedType.HasNameQualifier(targetInfo.Namespace))
                        {
                            return(false);
                        }

                        targetType = (byte)targetInfo.Underlying;

                        if (parameterType.IsEnumType())
                        {
                            specType = parameterType.GetEnumUnderlyingType() !.SpecialType;
                        }
                    }
                    else if (targetType != (byte)SignatureTypeCode.SZArray && parameterType.IsArray())
                    {
                        if (targetSignature[signatureByteIndex - 1] != (byte)SignatureTypeCode.SZArray)
                        {
                            return(false);
                        }

                        specType = ((ArrayTypeSymbol)parameterType).ElementType.SpecialType;
                    }

                    switch (targetType)
                    {
                    case (byte)SignatureTypeCode.Boolean:
                        if (specType != SpecialType.System_Boolean)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Char:
                        if (specType != SpecialType.System_Char)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.SByte:
                        if (specType != SpecialType.System_SByte)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Byte:
                        if (specType != SpecialType.System_Byte)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Int16:
                        if (specType != SpecialType.System_Int16)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt16:
                        if (specType != SpecialType.System_UInt16)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Int32:
                        if (specType != SpecialType.System_Int32)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt32:
                        if (specType != SpecialType.System_UInt32)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Int64:
                        if (specType != SpecialType.System_Int64)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.UInt64:
                        if (specType != SpecialType.System_UInt64)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Single:
                        if (specType != SpecialType.System_Single)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Double:
                        if (specType != SpecialType.System_Double)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.String:
                        if (specType != SpecialType.System_String)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.Object:
                        if (specType != SpecialType.System_Object)
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SerializationTypeCode.Type:
                        lazySystemType ??= GetSystemType(targetSymbol);

                        if (!TypeSymbol.Equals(parameterType, lazySystemType, TypeCompareKind.ConsiderEverything))
                        {
                            return(false);
                        }
                        parameterIndex += 1;
                        break;

                    case (byte)SignatureTypeCode.SZArray:
                        // Skip over and check the next byte
                        if (!parameterType.IsArray())
                        {
                            return(false);
                        }
                        break;

                    default:
                        return(false);
                    }
                }

                return(true);
            }
        }
Example #15
0
        // resolve implicit conversion
        string[] ImplicitConversionOpNames(TypeSymbol target)
        {
            switch (target.SpecialType)
            {
            case SpecialType.System_Char: return(new[] { "AsChar", "ToChar" });

            case SpecialType.System_Boolean: return(new[] { WellKnownMemberNames.ImplicitConversionName, "AsBoolean", "ToBoolean" });

            case SpecialType.System_Byte:
            case SpecialType.System_SByte:
            case SpecialType.System_Int32: return(new[] { WellKnownMemberNames.ImplicitConversionName, "AsInt", "ToInt", "ToLong" });

            case SpecialType.System_Int64: return(new[] { WellKnownMemberNames.ImplicitConversionName, "ToLong" });

            case SpecialType.System_Single:
            case SpecialType.System_Double: return(new[] { WellKnownMemberNames.ImplicitConversionName, "AsDouble", "ToDouble" });

            case SpecialType.System_Decimal: return(new[] { WellKnownMemberNames.ImplicitConversionName, "ToDecimal" });

            case SpecialType.System_String: return(new[] { WellKnownMemberNames.ImplicitConversionName, "AsString", WellKnownMemberNames.ObjectToString });

            case SpecialType.System_Object: return(new[] { "AsObject" });    // implicit conversion to object is not possible

            default:

                // AsPhpArray

                // ToNumber
                if (target == _compilation.CoreTypes.PhpNumber.Symbol)
                {
                    return new[] { WellKnownMemberNames.ImplicitConversionName, "ToNumber" }
                }
                ;

                // ToPhpString
                if (target == _compilation.CoreTypes.PhpString.Symbol)
                {
                    return new[] { WellKnownMemberNames.ImplicitConversionName, "ToPhpString" }
                }
                ;

                // AsResource
                // AsObject
                // AsPhpValue
                if (target == _compilation.CoreTypes.PhpValue.Symbol)
                {
                    return new[] { WellKnownMemberNames.ImplicitConversionName }
                }
                ;

                // AsPhpAlias
                if (target == _compilation.CoreTypes.PhpAlias.Symbol)
                {
                    return new[] { WellKnownMemberNames.ImplicitConversionName, "AsPhpAlias" }
                }
                ;

                // enum
                if (target.IsEnumType())
                {
                    return(ImplicitConversionOpNames(target.GetEnumUnderlyingType()));
                }

                //
                return(new[] { WellKnownMemberNames.ImplicitConversionName });
            }
        }

        string[] ExplicitConversionOpNames(TypeSymbol target)
        {
            switch (target.SpecialType)
            {
            case SpecialType.System_Boolean: return(new[] { WellKnownMemberNames.ExplicitConversionName, "ToBoolean" });

            case SpecialType.System_Int32: return(new[] { WellKnownMemberNames.ExplicitConversionName, "ToInt", "ToLong" });

            case SpecialType.System_Int64: return(new[] { WellKnownMemberNames.ExplicitConversionName, "ToLong" });

            case SpecialType.System_Double: return(new[] { WellKnownMemberNames.ExplicitConversionName, "ToDouble" });

            case SpecialType.System_String: return(new[] { WellKnownMemberNames.ExplicitConversionName, WellKnownMemberNames.ObjectToString });

            case SpecialType.System_Object: return(new[] { "ToObject" });       // implicit conversion to object is not possible

            default:

                // AsPhpArray
                if (target == _compilation.CoreTypes.PhpArray.Symbol)
                {
                    return new[] { WellKnownMemberNames.ExplicitConversionName, "ToArray" }
                }
                ;

                // ToNumber
                if (target == _compilation.CoreTypes.PhpNumber.Symbol)
                {
                    return new[] { WellKnownMemberNames.ExplicitConversionName, "ToNumber" }
                }
                ;

                // ToPhpString
                if (target == _compilation.CoreTypes.PhpString.Symbol)
                {
                    return new[] { WellKnownMemberNames.ExplicitConversionName, "ToPhpString" }
                }
                ;

                // ToPhpValue
                // ToPhpAlias

                // ToBytes
                if (target.IsSZArray() && ((ArrayTypeSymbol)target).ElementType.SpecialType == SpecialType.System_Byte)
                {
                    return(new[] { WellKnownMemberNames.ExplicitConversionName, "ToBytes" });
                }

                return(new[] { WellKnownMemberNames.ExplicitConversionName });
            }
        }

        /// <summary>
        /// Checks the type is a reference type (derived from <c>System.Object</c>) but it has a special meaning in PHP's semantics.
        /// Such a type cannot be converted to Object by simple casting.
        /// Includes: string, resource, array, alias.
        /// </summary>
        public static bool IsSpecialReferenceType(TypeSymbol t)
Example #16
0
 public static TypeSymbol EnumUnderlyingType(this TypeSymbol type)
 {
     return(type.IsEnumType() ? type.GetEnumUnderlyingType() : type);
 }
Example #17
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);
        }
        private void GetEnumOperation(BinaryOperatorKind kind, TypeSymbol enumType, ArrayBuilder<BinaryOperatorSignature> operators)
        {
            Debug.Assert((object)enumType != null);
            AssertNotChecked(kind);

            if (!enumType.IsValidEnumType())
            {
                return;
            }

            var underlying = enumType.GetEnumUnderlyingType();
            Debug.Assert((object)underlying != null);
            Debug.Assert(underlying.SpecialType != SpecialType.None);

            var nullable = Compilation.GetSpecialType(SpecialType.System_Nullable_T);
            var nullableEnum = nullable.Construct(enumType);
            var nullableUnderlying = nullable.Construct(underlying);

            switch (kind)
            {
                case BinaryOperatorKind.Addition:
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumAndUnderlyingAddition, enumType, underlying, enumType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.UnderlyingAndEnumAddition, underlying, enumType, enumType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumAndUnderlyingAddition, nullableEnum, nullableUnderlying, nullableEnum));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedUnderlyingAndEnumAddition, nullableUnderlying, nullableEnum, nullableEnum));
                    break;
                case BinaryOperatorKind.Subtraction:
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumSubtraction, enumType, enumType, underlying));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.EnumAndUnderlyingSubtraction, enumType, underlying, enumType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumSubtraction, nullableEnum, nullableEnum, nullableUnderlying));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedEnumAndUnderlyingSubtraction, nullableEnum, nullableUnderlying, nullableEnum));

                    // Due to a bug, the native compiler allows "underlying - enum", so Roslyn does as well.
                    // (In the native compiler codebase look at GetEnumBinOpSigs; the last call to method
                    // "ValidForEnumAndUnderlyingType" is wrong; it should be a call to "ValidForUnderlyingTypeAndEnum".
                    // The net result of the bug is that everything that is supposed to work is fine, and we accidentally
                    // allow underlying - enum because enum - underlying is valid.)

                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.UnderlyingAndEnumSubtraction, underlying, enumType, enumType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LiftedUnderlyingAndEnumSubtraction, nullableUnderlying, nullableEnum, nullableEnum));
                    break;
                case BinaryOperatorKind.Equal:
                case BinaryOperatorKind.NotEqual:
                case BinaryOperatorKind.GreaterThan:
                case BinaryOperatorKind.LessThan:
                case BinaryOperatorKind.GreaterThanOrEqual:
                case BinaryOperatorKind.LessThanOrEqual:
                    var boolean = Compilation.GetSpecialType(SpecialType.System_Boolean);
                    operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Enum, enumType, enumType, boolean));
                    operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Lifted | BinaryOperatorKind.Enum, nullableEnum, nullableEnum, boolean));
                    break;
                case BinaryOperatorKind.And:
                case BinaryOperatorKind.Or:
                case BinaryOperatorKind.Xor:
                    operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Enum, enumType, enumType, enumType));
                    operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Lifted | BinaryOperatorKind.Enum, nullableEnum, nullableEnum, nullableEnum));
                    break;
            }
        }