Ejemplo n.º 1
0
            // 13.2.2 Explicit enumeration conversions
            //
            // The explicit enumeration conversions are:
            //
            // * From sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, or
            //   decimal to any enum-type.
            //
            // * From any enum-type to sbyte, byte, short, ushort, int, uint, long, ulong, char,
            //   float, double, or decimal.
            //
            // * From any enum-type to any other enum-type.
            //
            // * An explicit enumeration conversion between two types is processed by treating any
            //   participating enum-type as the underlying type of that enum-type, and then performing
            //   an implicit or explicit numeric conversion between the resulting types.

            private AggCastResult bindExplicitConversionFromEnumToAggregate(AggregateType aggTypeDest)
            {
                Debug.Assert(_typeSrc != null);
                Debug.Assert(aggTypeDest != null);

                if (!_typeSrc.isEnumType())
                {
                    return(AggCastResult.Failure);
                }

                AggregateSymbol aggDest = aggTypeDest.getAggregate();

                if (aggDest.isPredefAgg(PredefinedType.PT_DECIMAL))
                {
                    return(bindExplicitConversionFromEnumToDecimal(aggTypeDest));
                }


                if (!aggDest.getThisType().isNumericType() &&
                    !aggDest.IsEnum() &&
                    !(aggDest.IsPredefined() && aggDest.GetPredefType() == PredefinedType.PT_CHAR))
                {
                    return(AggCastResult.Failure);
                }

                if (_exprSrc.GetConst() != null)
                {
                    ConstCastResult result = _binder.bindConstantCast(_exprSrc, _exprTypeDest, _needsExprDest, out _exprDest, true);
                    if (result == ConstCastResult.Success)
                    {
                        return(AggCastResult.Success);
                    }
                    else if (result == ConstCastResult.CheckFailure)
                    {
                        return(AggCastResult.Abort);
                    }
                }

                if (_needsExprDest)
                {
                    _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest);
                }
                return(AggCastResult.Success);
            }
Ejemplo n.º 2
0
            private bool bindImplicitConversionBetweenSimpleTypes(AggregateType aggTypeSrc)
            {
                AggregateSymbol aggSrc = aggTypeSrc.getAggregate();

                Debug.Assert(aggSrc.getThisType().isSimpleType());
                Debug.Assert(typeDest.isSimpleType());

                Debug.Assert(aggSrc.IsPredefined() && typeDest.isPredefined());
                PredefinedType ptSrc  = aggSrc.GetPredefType();
                PredefinedType ptDest = typeDest.getPredefType();
                ConvKind       convertKind;
                bool           fConstShrinkCast = false;

                Debug.Assert((int)ptSrc < NUM_SIMPLE_TYPES && (int)ptDest < NUM_SIMPLE_TYPES);

                // 13.1.7 Implicit constant expression conversions
                //
                // An implicit constant expression conversion permits the following conversions:
                // *   A constant-expression (14.16) of type int can be converted to type sbyte,  byte,  short,
                //     ushort,  uint, or ulong, provided the value of the constant-expression is within the range
                //     of the destination type.
                // *   A constant-expression of type long can be converted to type ulong, provided the value of
                //     the constant-expression is not negative.
                // Note: Don't use GetConst here since the conversion only applies to bona-fide compile time constants.
                if (exprSrc != null && exprSrc.isCONSTANT_OK() &&
                    ((ptSrc == PredefinedType.PT_INT && ptDest != PredefinedType.PT_BOOL && ptDest != PredefinedType.PT_CHAR) ||
                     (ptSrc == PredefinedType.PT_LONG && ptDest == PredefinedType.PT_ULONG)) &&
                    isConstantInRange(exprSrc.asCONSTANT(), typeDest))
                {
                    // Special case (CLR 6.1.6): if integral constant is in range, the conversion is a legal implicit conversion.
                    convertKind      = ConvKind.Implicit;
                    fConstShrinkCast = needsExprDest && (GetConvKind(ptSrc, ptDest) != ConvKind.Implicit);
                }
                else if (ptSrc == ptDest)
                {
                    // Special case: precision limiting casts to float or double
                    Debug.Assert(ptSrc == PredefinedType.PT_FLOAT || ptSrc == PredefinedType.PT_DOUBLE);
                    Debug.Assert(0 != (flags & CONVERTTYPE.ISEXPLICIT));
                    convertKind = ConvKind.Implicit;
                }
                else
                {
                    convertKind = GetConvKind(ptSrc, ptDest);
                    Debug.Assert(convertKind != ConvKind.Identity);
                    // identity conversion should have been handled at first.
                }

                if (convertKind != ConvKind.Implicit)
                {
                    return(false);
                }

                // An implicit conversion exists. Do the conversion.
                if (exprSrc.GetConst() != null)
                {
                    // Fold the constant cast if possible.
                    ConstCastResult result = binder.bindConstantCast(exprSrc, exprTypeDest, needsExprDest, out exprDest, false);
                    if (result == ConstCastResult.Success)
                    {
                        return(true);  // else, don't fold and use a regular cast, below.
                    }
                    // REVIEW: I don't think this can ever be hit.  If exprSrc is a constant then
                    // it's either a floating point number (which always succeeds), it's a numeric implicit
                    // conversion (which always succeeds), or it's a constant numeric conversion (which
                    // has already been checked by isConstantInRange, so should always succeed)
                }

                if (isUserDefinedConversion(ptSrc, ptDest))
                {
                    if (!needsExprDest)
                    {
                        return(true);
                    }
                    // According the language, this is a standard conversion, but it is implemented
                    // through a user-defined conversion. Because it's a standard conversion, we don't
                    // test the NOUDC flag here.
                    return(binder.bindUserDefinedConversion(exprSrc, aggTypeSrc, typeDest, needsExprDest, out exprDest, true));
                }
                if (needsExprDest)
                {
                    binder.bindSimpleCast(exprSrc, exprTypeDest, out exprDest);
                }
                return(true);
            }
Ejemplo n.º 3
0
        /*
          Bind an float/double operator: +, -, , /, %, <, >, <=, >=, ==, !=. If both operations are constants, the result
          will be a constant also. op2 can be null for a unary operator. The operands are assumed
          to be already converted to the correct type.
         */
        // We have an intentional divide by 0 there, so disable the warning...
#if _MSC_VER
#pragma warning( disable : 4723 )
#endif
        private EXPR bindFloatOp(ExpressionKind kind, EXPRFLAG flags, EXPR op1, EXPR op2)
        {
            //Debug.Assert(kind.isRelational() || kind.isArithmetic());
            Debug.Assert(op2 == null || op1.type == op2.type);
            Debug.Assert(op1.type.isPredefType(PredefinedType.PT_FLOAT) || op1.type.isPredefType(PredefinedType.PT_DOUBLE));

            EXPR exprRes;
            EXPR opConst1 = op1.GetConst();
            EXPR opConst2 = op2 != null ? op2.GetConst() : null;

            // Check for constants and fold them.
            if (opConst1 != null && (op2 == null || opConst2 != null))
            {
                // Get the operands
                double d1 = opConst1.asCONSTANT().getVal().doubleVal;
                double d2 = opConst2 != null ? opConst2.asCONSTANT().getVal().doubleVal : 0.0;
                double result = 0;      // if isBoolResult is false
                bool result_b = false;  // if isBoolResult is true

                // Do the operation.
                switch (kind)
                {
                    case ExpressionKind.EK_ADD:
                        result = d1 + d2;
                        break;
                    case ExpressionKind.EK_SUB:
                        result = d1 - d2;
                        break;
                    case ExpressionKind.EK_MUL:
                        result = d1 * d2;
                        break;
                    case ExpressionKind.EK_DIV:
                        result = d1 / d2;
                        break;
                    case ExpressionKind.EK_NEG:
                        result = -d1;
                        break;
                    case ExpressionKind.EK_UPLUS:
                        result = d1;
                        break;
                    case ExpressionKind.EK_MOD:
                        result = d1 % d2;
                        break;
                    case ExpressionKind.EK_EQ:
                        result_b = (d1 == d2);
                        break;
                    case ExpressionKind.EK_NE:
                        result_b = (d1 != d2);
                        break;
                    case ExpressionKind.EK_LE:
                        result_b = (d1 <= d2);
                        break;
                    case ExpressionKind.EK_LT:
                        result_b = (d1 < d2);
                        break;
                    case ExpressionKind.EK_GE:
                        result_b = (d1 >= d2);
                        break;
                    case ExpressionKind.EK_GT:
                        result_b = (d1 > d2);
                        break;
                    default:
                        Debug.Assert(false);
                        result = 0.0;  // unexpected operation.
                        break;
                }

                CType typeDest;
                CONSTVAL cv = new CONSTVAL();

                // Allocate the result node.
                if (kind.isRelational())
                {
                    cv.iVal = result_b ? 1 : 0;
                    typeDest = GetReqPDT(PredefinedType.PT_BOOL);
                }
                else
                {
                    // NaN has some implementation defined bits that differ between platforms.
                    // Normalize it to produce identical images across all platforms
                    /*
                     * How do we get here?
                    if (_isnan(result))
                    {
                        cv = ConstValFactory.GetNan();
                    }
                    else
                    {
                     * */
                    cv = GetExprConstants().Create(result);

                    typeDest = op1.type;
                }
                exprRes = GetExprFactory().CreateConstant(typeDest, cv);
            }
            else
            {
                // Allocate the result expression.
                CType typeDest = kind.isRelational() ? GetReqPDT(PredefinedType.PT_BOOL) : op1.type;

                exprRes = GetExprFactory().CreateOperator(kind, typeDest, op1, op2);
                flags = ~EXPRFLAG.EXF_CHECKOVERFLOW;
                exprRes.flags |= flags;
            }

            return exprRes;
        }
Ejemplo n.º 4
0
        public void bindSimpleCast(EXPR exprSrc, EXPRTYPEORNAMESPACE exprTypeDest, out EXPR pexprDest, EXPRFLAG exprFlags)
        {
            Debug.Assert(exprTypeDest != null);
            Debug.Assert(exprTypeDest.TypeOrNamespace != null);
            Debug.Assert(exprTypeDest.TypeOrNamespace.IsType());
            CType typeDest = exprTypeDest.TypeOrNamespace.AsType();
            pexprDest = null;
            // If the source is a constant, and cast is really simple (no change in fundamental
            // type, no flags), then create a new constant node with the new type instead of
            // creating a cast node. This allows compile-time constants to be easily recognized.
            EXPR exprConst = exprSrc.GetConst();

            // Make the cast expr anyway, and if we find that we have a constant, then set the cast expr
            // as the original tree for the constant. Otherwise, return the cast expr.

            EXPRCAST exprCast = GetExprFactory().CreateCast(exprFlags, exprTypeDest, exprSrc);
            if (Context.CheckedNormal)
            {
                exprCast.flags |= EXPRFLAG.EXF_CHECKOVERFLOW;
            }

            // Check if we have a compile time constant. If we do, create a constant for it and set the
            // original tree to the cast.

            if (exprConst != null && exprFlags == 0 &&
                exprSrc.type.fundType() == typeDest.fundType() &&
                (!exprSrc.type.isPredefType(PredefinedType.PT_STRING) || exprConst.asCONSTANT().getVal().IsNullRef()))
            {
                EXPRCONSTANT expr = GetExprFactory().CreateConstant(typeDest, exprConst.asCONSTANT().getVal());
                pexprDest = expr;
                return;
            }

            pexprDest = exprCast;
            Debug.Assert(exprCast.GetArgument() != null);
            return;
        }
Ejemplo n.º 5
0
        private EXPR FoldIntegerConstants(ExpressionKind kind, EXPRFLAG flags, EXPR op1, EXPR op2, PredefinedType ptOp)
        {
            //Debug.Assert(kind.isRelational() || kind.isArithmetic() || kind.isBitwise());
            Debug.Assert(ptOp == PredefinedType.PT_INT || ptOp == PredefinedType.PT_UINT || ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG);
            CType typeOp = GetReqPDT(ptOp);
            Debug.Assert(typeOp != null);
            Debug.Assert(op1 != null && op1.type == typeOp);
            Debug.Assert(op2 == null || op2.type == typeOp);
            Debug.Assert((op2 == null) == (kind == ExpressionKind.EK_NEG || kind == ExpressionKind.EK_UPLUS || kind == ExpressionKind.EK_BITNOT));

            EXPRCONSTANT opConst1 = op1.GetConst().asCONSTANT();
            EXPRCONSTANT opConst2 = (op2 != null) ? op2.GetConst().asCONSTANT() : null;

            // Fold operation if both args are constant.
            if (opConst1 != null && (op2 == null || opConst2 != null))
            {
                if (ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG)
                {
                    return FoldConstI8Op(kind, op1, opConst1, op2, opConst2, ptOp);
                }
                else
                {
                    return FoldConstI4Op(kind, op1, opConst1, op2, opConst2, ptOp);
                }
            }

            return null;
        }
Ejemplo n.º 6
0
        /*
            Handles boolean unary operator (!).
        */
        private EXPR BindBoolUnaOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg)
        {
            Debug.Assert(arg.type.isPredefType(PredefinedType.PT_BOOL));
            Debug.Assert(ek == ExpressionKind.EK_LOGNOT);

            // Get the result type and operand type.
            CType typeBool = GetReqPDT(PredefinedType.PT_BOOL);

            // Determine if arg has a constant value.
            // Strip off EXPRKIND.EK_SEQUENCE for constant checking.

            EXPR argConst = arg.GetConst();

            if (argConst == null)
                return GetExprFactory().CreateUnaryOp(ExpressionKind.EK_LOGNOT, typeBool, arg);

            bool fRes = argConst.asCONSTANT().getVal().iVal != 0;
            EXPR rval = GetExprFactory().CreateConstant(typeBool, ConstValFactory.GetBool(!fRes));

            return rval;
        }
Ejemplo n.º 7
0
        /*
            Bind a shift operator: <<, >>. These can have integer or long first operands,
            and second operand must be int.
        */
        private EXPR BindShiftOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2)
        {
            Debug.Assert(ek == ExpressionKind.EK_LSHIFT || ek == ExpressionKind.EK_RSHIFT);
            Debug.Assert(arg1.type.isPredefined());
            Debug.Assert(arg2.type.isPredefType(PredefinedType.PT_INT));

            PredefinedType ptOp = arg1.type.getPredefType();
            Debug.Assert(ptOp == PredefinedType.PT_INT || ptOp == PredefinedType.PT_UINT || ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG);

            // We want to check up front if we have two constants, because constant folding is supposed to
            // happen in the initial binding pass.
            EXPR argConst1 = arg1.GetConst();
            EXPR argConst2 = arg2.GetConst();

            if (argConst1 == null || argConst2 == null) // One or more aren't constants, so don't fold anything.
            {
                return GetExprFactory().CreateBinop(ek, arg1.type, arg1, arg2);
            }

            // Both constants, so fold them.
            CONSTVAL cv = new CONSTVAL();
            int cbit = (ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG) ? 0x3f : 0x1f;
            cv.iVal = argConst2.asCONSTANT().getVal().iVal & cbit;
            cbit = cv.iVal;

            // Fill in the CONSTVAL.
            if (ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG)
            {
                Debug.Assert(0 <= cbit && cbit < 0x40);
                ulong u1 = argConst1.asCONSTANT().getVal().ulongVal;
                ulong uval;

                switch (ek)
                {
                    case ExpressionKind.EK_LSHIFT:
                        uval = u1 << cbit;
                        break;
                    case ExpressionKind.EK_RSHIFT:
                        uval = (ptOp == PredefinedType.PT_LONG) ? (ulong)((long)u1 >> cbit) : (u1 >> cbit);
                        break;
                    default:
                        VSFAIL("Unknown op");
                        uval = 0;
                        break;
                }
                cv = GetExprConstants().Create(uval);
            }
            else
            {
                Debug.Assert(0 <= cbit && cbit < 0x20);
                uint u1 = argConst1.asCONSTANT().getVal().uiVal;

                switch (ek)
                {
                    case ExpressionKind.EK_LSHIFT:
                        cv.uiVal = u1 << cbit;
                        break;
                    case ExpressionKind.EK_RSHIFT:
                        cv.uiVal = (ptOp == PredefinedType.PT_INT) ? (uint)((int)u1 >> cbit) : (u1 >> cbit);
                        break;
                    default:
                        VSFAIL("Unknown op");
                        cv.uiVal = 0;
                        break;
                }
            }

            EXPR exprRes = GetExprFactory().CreateConstant(GetReqPDT(ptOp), cv);
            return exprRes;
        }
Ejemplo n.º 8
0
        /*
            Handles standard unary decimal based operators.
        */
        private EXPR BindDecUnaOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg)
        {
            Debug.Assert(arg.type.isPredefType(PredefinedType.PT_DECIMAL));
            Debug.Assert(ek == ExpressionKind.EK_NEG || ek == ExpressionKind.EK_UPLUS);

            CType typeDec = GetOptPDT(PredefinedType.PT_DECIMAL);
            Debug.Assert(typeDec != null);
            ek = ek == ExpressionKind.EK_NEG ? ExpressionKind.EK_DECIMALNEG : ExpressionKind.EK_UPLUS;

            // We want to fold if the argument is constant. Otherwise, keep the regular op.
            EXPR argConst = arg.GetConst();
            if (argConst == null) // Non-constant.
            {
                if (ek == ExpressionKind.EK_DECIMALNEG)
                {
                    PREDEFMETH predefMeth = PREDEFMETH.PM_DECIMAL_OPUNARYMINUS;
                    return CreateUnaryOpForPredefMethodCall(ek, predefMeth, typeDec, arg);
                }
                return GetExprFactory().CreateUnaryOp(ek, typeDec, arg);
            }

            // If its a uplus, just return it.
            if (ek == ExpressionKind.EK_UPLUS)
            {
                return arg;
            }

            decimal dec = argConst.asCONSTANT().getVal().decVal;
            dec = dec * -1;

            // Allocate the result node.
            CONSTVAL cv = GetExprConstants().Create(dec);

            EXPR exprRes = GetExprFactory().CreateConstant(typeDec, cv);

            return exprRes;
        }
Ejemplo n.º 9
0
        /*
            Handles standard binary decimal based operators.
            This function is called twice by the EE for every binary operator it evaluates
            Here is how it works.
        1.  The EE on finding an Expr asks the Expression binder to bind it. 
        2.  At this time the expression binder just creates a new binopexpr and returns it to the EE,
        the EE then uses the runtimesystem to find if any of the arguments of the expr can be evaluated to constants.
        3.  If so it creates new arguments and expr, aliases the original expr to the new one and passes
        it new expr to Expressionbinder to be bound. 
        4.  This time the expression binder realizes that the 2 arguments are constants and tries to fold them.
        If the folding is successful the value is used by the EE (and we have avoided a funceval)
        5.  if the constant binding fails, then the Expression binders returns the same exp as it would have 
        created for the compile case ( we func eval the same function as what would be executed at runtime).
        */
        private EXPR BindDecBinOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2)
        {
            Debug.Assert(arg1.type.isPredefType(PredefinedType.PT_DECIMAL) && arg2.type.isPredefType(PredefinedType.PT_DECIMAL));

            CType typeDec = GetOptPDT(PredefinedType.PT_DECIMAL);
            Debug.Assert(typeDec != null);

            EXPR argConst1 = arg1.GetConst();
            EXPR argConst2 = arg2.GetConst();

            CType typeRet = null;

            switch (ek)
            {
                default:
                    VSFAIL("Bad kind");
                    break;
                case ExpressionKind.EK_ADD:
                case ExpressionKind.EK_SUB:
                case ExpressionKind.EK_MUL:
                case ExpressionKind.EK_DIV:
                case ExpressionKind.EK_MOD:
                    typeRet = typeDec;
                    break;
                case ExpressionKind.EK_LT:
                case ExpressionKind.EK_LE:
                case ExpressionKind.EK_GT:
                case ExpressionKind.EK_GE:
                case ExpressionKind.EK_EQ:
                case ExpressionKind.EK_NE:
                    typeRet = GetReqPDT(PredefinedType.PT_BOOL);
                    break;
            }

#if CSEE
            // In the EE, even if we don't have two constants, we want to emit an EXPRBINOP with the
            // right EK so that when we evalsync we can just do the work ourselves instead of
            // delegating to method calls.

            if (!argConst1 || !argConst2)
            {
                // We don't have 2 constants, so just emit an EXPRBINOP...
                return GetExprFactory().CreateBinop(tree, ek, typeRet, arg1, arg2);
            }
            else
            {
                goto LBothConst;
            }

        LUserDefined:

#endif // CSEE

#if !CSEE
            if (argConst2 != null && argConst1 != null)
            {
                goto LBothConst;
            }
#endif

            // At this point, for the compiler we don't want to optimize the binop just yet. Maintain the correct tree until
            // the arithmetic optimizer pass.
            return GetExprFactory().CreateBinop(ek, typeRet, arg1, arg2);

        LBothConst:
            decimal dec1;
            decimal dec2;
            decimal decRes = 0;
            bool fRes = false;
            bool fBool = false;

            dec1 = argConst1.asCONSTANT().getVal().decVal;
            dec2 = argConst2.asCONSTANT().getVal().decVal;

            // Do the operation.
            switch (ek)
            {
                case ExpressionKind.EK_ADD:
                    decRes = dec1 + dec2;
                    break;
                case ExpressionKind.EK_SUB:
                    decRes = dec1 - dec2;
                    break;
                case ExpressionKind.EK_MUL:
                    decRes = dec1 * dec2;
                    break;
                case ExpressionKind.EK_DIV:
                    if (dec2 == 0)
                    {
                        GetErrorContext().Error(ErrorCode.ERR_IntDivByZero);
                        EXPR rval = GetExprFactory().CreateBinop(ek, typeDec, arg1, arg2);
                        rval.SetError();
                        return rval;
                    }

                    decRes = dec1 / dec2;
                    break;

                case ExpressionKind.EK_MOD:
                    {
                        /* n % d = n - d  truncate(n/d) */
                        decimal decDiv;

                        if (dec2 == 0)
                        {
                            GetErrorContext().Error(ErrorCode.ERR_IntDivByZero);
                            EXPR rval = GetExprFactory().CreateBinop(ek, typeDec, arg1, arg2);
                            rval.SetError();
                            return rval;
                        }

                        decDiv = dec1 % dec2;
                        break;
                    }

                default:
                    fBool = true;

                    switch (ek)
                    {
                        default:
                            VSFAIL("Bad ek");
                            break;
                        case ExpressionKind.EK_EQ:
                            fRes = dec1 == dec2;
                            break;
                        case ExpressionKind.EK_NE:
                            fRes = dec1 != dec2;
                            break;
                        case ExpressionKind.EK_LE:
                            fRes = dec1 <= dec2;
                            break;
                        case ExpressionKind.EK_LT:
                            fRes = dec1 < dec2;
                            break;
                        case ExpressionKind.EK_GE:
                            fRes = dec1 >= dec2;
                            break;
                        case ExpressionKind.EK_GT:
                            fRes = dec1 > dec2;
                            break;
                    }
                    break;
            }

            // Allocate the result node.
            CONSTVAL cv;
            EXPR exprRes;

            if (fBool)
            {
                cv = ConstValFactory.GetBool(fRes);
                exprRes = GetExprFactory().CreateConstant(GetReqPDT(PredefinedType.PT_BOOL), cv);
            }
            else
            {
                cv = GetExprConstants().Create(decRes);
                exprRes = GetExprFactory().CreateConstant(typeDec, cv);
            }

            return exprRes;
        }