Esempio n. 1
0
        //------------------------------------------------------------
        // FUNCBREC.BindNubFetchAndFree
        //
        /// <summary>
        /// If the given slot has a temp associated with it,
        /// constructs a reverse sequence for loading the value and freeing the temp.
        /// Otherwise, just returns the value expr.
        /// </summary>
        /// <param name="treeNode"></param>
        /// <param name="nubInfo"></param>
        /// <param name="iexpr"></param>
        /// <returns></returns>
        //------------------------------------------------------------
        private EXPR BindNubFetchAndFree(BASENODE treeNode, ref NubInfo nubInfo, int iexpr)
        {
            EXPR expr = nubInfo.TmpExpr[iexpr];

            DebugUtil.Assert(expr != null);

            if (nubInfo.PostExpr[iexpr] == null)
            {
                return(expr);
            }

            return(AddSideEffects(treeNode, expr, nubInfo.PostExpr[iexpr], false, true));
        }
Esempio n. 2
0
        //------------------------------------------------------------
        // FUNCBREC.BindNubOpRes (1)
        //
        /// <summary>
        /// <para>Combine the condition and value.</para>
        /// <para>(In sscli, warOnNull has the default value false.)</para>
        /// </summary>
        /// <param name="treeNode"></param>
        /// <param name="nubSym"></param>
        /// <param name="dstTypeSym"></param>
        /// <param name="valueExpr"></param>
        /// <param name="nubInfo"></param>
        /// <param name="warnOnNull"></param>
        /// <returns></returns>
        //------------------------------------------------------------
        private EXPR BindNubOpRes(
            BASENODE treeNode,
            NUBSYM nubSym,
            TYPESYM dstTypeSym,
            EXPR valueExpr,
            ref NubInfo nubInfo,
            bool warnOnNull)    // = false
        {
            if (nubInfo.FAlwaysNull() && warnOnNull)
            {
                Compiler.Error(treeNode, CSCERRID.WRN_AlwaysNull, new ErrArg(nubSym));
            }

            return(BindNubOpRes(
                       treeNode,
                       dstTypeSym,
                       valueExpr,
                       NewExprZero(treeNode, dstTypeSym.IsNUBSYM ? dstTypeSym : nubSym),
                       ref nubInfo));
        }
Esempio n. 3
0
        //------------------------------------------------------------
        // FUNCBREC.BindNubAddTmps
        //
        /// <summary>
        /// Combines the pre and post expressions of the NubInfo with exprRes.
        /// The pre and post exprs are typically to store values to temps and free the temps.
        /// </summary>
        /// <param name="treeNode"></param>
        /// <param name="resExpr"></param>
        /// <param name="nubInfo"></param>
        /// <returns></returns>
        //------------------------------------------------------------
        private EXPR BindNubAddTmps(BASENODE treeNode, EXPR resExpr, ref NubInfo nubInfo)
        {
            if (nubInfo.PostExpr[1] != null)
            {
                resExpr = NewExprBinop(treeNode, EXPRKIND.SEQREV, resExpr.TypeSym, resExpr, nubInfo.PostExpr[1]);
            }
            if (nubInfo.PostExpr[0] != null)
            {
                resExpr = NewExprBinop(treeNode, EXPRKIND.SEQREV, resExpr.TypeSym, resExpr, nubInfo.PostExpr[0]);
            }

            if (nubInfo.PreExpr[1] != null)
            {
                resExpr = NewExprBinop(treeNode, EXPRKIND.SEQUENCE, resExpr.TypeSym, nubInfo.PreExpr[1], resExpr);
            }
            if (nubInfo.PreExpr[0] != null)
            {
                resExpr = NewExprBinop(treeNode, EXPRKIND.SEQUENCE, resExpr.TypeSym, nubInfo.PreExpr[0], resExpr);
            }

            return(resExpr);
        }
Esempio n. 4
0
        //------------------------------------------------------------
        // FUNCBREC.BindNubOpRes (2)
        //
        /// <summary>
        /// Combine the condition and value.
        /// </summary>
        /// <param name="treeNode"></param>
        /// <param name="dstTypeSym"></param>
        /// <param name="valueExpr"></param>
        /// <param name="nullExpr"></param>
        /// <param name="nubInfo"></param>
        /// <returns></returns>
        //------------------------------------------------------------
        private EXPR BindNubOpRes(
            BASENODE treeNode,
            TYPESYM dstTypeSym,
            EXPR valueExpr,
            EXPR nullExpr,
            ref NubInfo nubInfo)
        {
            EXPR resExpr;

            nullExpr  = MustConvert(nullExpr, dstTypeSym, 0);
            valueExpr = MustConvert(valueExpr, dstTypeSym, 0);

            if (nubInfo.FAlwaysNonNull())
            {
                // Don't need nullExpr and there aren't any temps.
                resExpr = valueExpr;
            }
            else if (nubInfo.FAlwaysNull())
            {
                // Don't need valueExpr but do need side effects.
                resExpr = BindNubAddTmps(treeNode, nullExpr, ref nubInfo);
            }
            else
            {
                DebugUtil.Assert(nubInfo.CombinedConditionExpr != null);
                resExpr = BindQMark(
                    treeNode,
                    nubInfo.CombinedConditionExpr,
                    MustConvert(valueExpr, dstTypeSym, 0),
                    nullExpr,
                    false);
                resExpr = BindNubAddTmps(treeNode, resExpr, ref nubInfo);
            }

            return(resExpr);
        }
Esempio n. 5
0
        //------------------------------------------------------------
        // FUNCBREC.BindNubCondValBin
        //
        /// <summary>
        /// <para>Fill in the NubInfo for a unary or binary operator lifting.</para>
        /// <para>(In sscli, liftFlags has default value LiftFlags::LiftBoth.)</para>
        /// </summary>
        /// <param name="treeNode"></param>
        /// <param name="expr1"></param>
        /// <param name="expr2"></param>
        /// <param name="nubInfo"></param>
        /// <param name="liftFlags"></param>
        //------------------------------------------------------------
        private void BindNubCondValBin(
            BASENODE treeNode,
            EXPR expr1,
            EXPR expr2,
            ref NubInfo nubInfo,
            LiftFlagsEnum liftFlags)    // = LiftFlags::LiftBoth
        {
            DebugUtil.Assert((liftFlags & (LiftFlagsEnum.Lift1 | LiftFlagsEnum.Lift2)) != 0);
            DebugUtil.Assert(expr1 != null);
            DebugUtil.Assert(expr2 != null || (liftFlags & LiftFlagsEnum.Lift1) != 0);

            nubInfo.Init();

            bool[] rgfLift = { false, false };
            rgfLift[0] = ((liftFlags & LiftFlagsEnum.Lift1) != 0);
            rgfLift[1] = expr2 != null && ((liftFlags & LiftFlagsEnum.Lift2) != 0);

            EXPR[] rgexpr = { null, null };
            rgexpr[0] = rgfLift[0] ? StripNubCtor(expr1) : expr1;
            rgexpr[1] = rgfLift[1] ? StripNubCtor(expr2) : expr2;

            if ((!rgfLift[0] || !rgexpr[0].TypeSym.IsNUBSYM) && (!rgfLift[1] || !rgexpr[1].TypeSym.IsNUBSYM))
            {
                // All lifted params can't be null so we don't need temps.
                nubInfo.ValueExpr[0]    = rgexpr[0];
                nubInfo.ValueExpr[1]    = rgexpr[1];
                nubInfo.IsActive        = true;
                nubInfo.IsAlwaysNonNull = true;
                return;
            }

            // Optimization: if they are the same local then we only need one temp.
            if (rgexpr[1] != null &&
                rgexpr[0].Kind == EXPRKIND.LOCAL &&
                rgexpr[1].Kind == EXPRKIND.LOCAL &&
                (rgexpr[0] as EXPRLOCAL).LocVarSym == (rgexpr[1] as EXPRLOCAL).LocVarSym &&
                rgfLift[0] == rgfLift[1])
            {
                BindNubSave(rgexpr[0], ref nubInfo, 0, rgfLift[0]);
                DebugUtil.Assert(nubInfo.TmpExpr[0].Kind == EXPRKIND.LDTMP);
                nubInfo.TmpExpr[1] = nubInfo.TmpExpr[0];
                nubInfo.IsSameTemp = true;
            }
            else
            {
                BindNubSave(rgexpr[0], ref nubInfo, 0, rgfLift[0]);
                if (rgexpr[1] != null)
                {
                    BindNubSave(rgexpr[1], ref nubInfo, 1, rgfLift[1]);
                }
            }

            for (int iexpr = 0; iexpr < 2 && rgexpr[iexpr] != null; iexpr++)
            {
                if (!rgfLift[iexpr] || !nubInfo.TmpExpr[iexpr].TypeSym.IsNUBSYM)
                {
                    nubInfo.ValueExpr[iexpr] = nubInfo.TmpExpr[iexpr];
                    continue;
                }
                nubInfo.ValueExpr[iexpr] = BindNubGetValOrDef(treeNode, nubInfo.TmpExpr[iexpr]);
                DebugUtil.Assert(!nubInfo.ValueExpr[iexpr].TypeSym.IsNUBSYM);
                if (nubInfo.FConst(iexpr))
                {
                    nubInfo.IsNull[iexpr] = nubInfo.IsAlwaysNull = true;
                }
                else if (nubInfo.IsSameTemp && iexpr != 0)
                {
                    nubInfo.ConditionExpr[iexpr] = nubInfo.ConditionExpr[0];
                }
                else
                {
                    nubInfo.ConditionExpr[iexpr] = BindNubHasValue(treeNode, nubInfo.TmpExpr[iexpr], true);
                }
            }

            if (!nubInfo.IsAlwaysNull)
            {
                if (nubInfo.ConditionExpr[0] == null)
                {
                    nubInfo.CombinedConditionExpr = nubInfo.ConditionExpr[1];
                }
                else if (nubInfo.ConditionExpr[1] == null || nubInfo.IsSameTemp)
                {
                    nubInfo.CombinedConditionExpr = nubInfo.ConditionExpr[0];
                }
                else
                {
                    nubInfo.CombinedConditionExpr = NewExprBinop(
                        treeNode,
                        EXPRKIND.BITAND,
                        GetRequiredPredefinedType(PREDEFTYPE.BOOL),
                        nubInfo.ConditionExpr[0],
                        nubInfo.ConditionExpr[1]);
                }
            }
            else
            {
                // One of the operands is null so the result will always be null and we
                // don't need the temps.
                if (nubInfo.PreExpr[0] != null && nubInfo.PreExpr[0].Kind == EXPRKIND.STTMP)
                {
                    nubInfo.PreExpr[0] = (nubInfo.PreExpr[0] as EXPRSTTMP).SourceExpr;
                }
                if (nubInfo.PreExpr[1] != null && nubInfo.PreExpr[1].Kind == EXPRKIND.STTMP)
                {
                    nubInfo.PreExpr[1] = (nubInfo.PreExpr[1] as EXPRSTTMP).SourceExpr;
                }
                nubInfo.PostExpr[0] = null;
                nubInfo.PostExpr[1] = null;
            }

            nubInfo.IsActive = true;
            DebugUtil.Assert(nubInfo.CombinedConditionExpr != null || nubInfo.IsAlwaysNull);
        }
Esempio n. 6
0
        //------------------------------------------------------------
        // FUNCBREC.BindNubSave
        //
        /// <summary>
        /// Fill in the given slot (iexpr) of the NubInfo appropriately.
        /// If exprSrc is a constant (possibly with side effects),
        /// put the side effects in nin.rgexprPre[iexpr] and the constant value in nin.rgexprVal[iexpr].
        /// Otherwise, construct an expr to save the value of exprSrc in a temp,
        /// an expr to load the temp and an expr to free the temp.
        /// Store these in the appropriate places in the NubInfo.
        /// If fLift is true, the value saved in the temp will have at most one level of Nullable.
        /// </summary>
        /// <param name="srcExpr"></param>
        /// <param name="nubInfo"></param>
        /// <param name="exprIndex"></param>
        /// <param name="fLift"></param>
        /// <returns></returns>
        //------------------------------------------------------------
        private bool BindNubSave(EXPR srcExpr, ref NubInfo nubInfo, int exprIndex, bool fLift)
        {
            DebugUtil.Assert(exprIndex == 0 || exprIndex == 1);
            DebugUtil.Assert(
                nubInfo.PreExpr[exprIndex] == null &&
                nubInfo.PostExpr[exprIndex] == null &&
                nubInfo.ValueExpr[exprIndex] == null &&
                nubInfo.TmpExpr[exprIndex] == null &&
                nubInfo.ConditionExpr[exprIndex] == null);

            // If we're lifting the expr and it's a new T?(t), just operate on t. The caller should have
            // already taken care of calling StripNubCtor!
            DebugUtil.Assert(!srcExpr.TypeSym.IsNUBSYM || !fLift || !IsNubCtor(srcExpr));

            // Check for an EXPRKIND.CONSTANT or EXPRKIND.ZEROINIT inside EXPRKIND.SEQUENCE and EXPRKIND.SEQREV exprs.
            EXPR constExpr = srcExpr.GetConst();

            if (constExpr != null)
            {
                DebugUtil.Assert(constExpr.Kind == EXPRKIND.CONSTANT || constExpr.Kind == EXPRKIND.ZEROINIT);
                if (constExpr != srcExpr)
                {
                    // Keep the side effects.
                    nubInfo.PreExpr[exprIndex] = srcExpr;
                }
                if (!constExpr.TypeSym.IsNUBSYM || !fLift)
                {
                    nubInfo.TmpExpr[exprIndex] = constExpr;
                }
                else
                {
                    nubInfo.TmpExpr[exprIndex] = NewExprZero(
                        srcExpr.TreeNode, constExpr.TypeSym.StripAllButOneNub());
                }
                return(false);
            }

            if (srcExpr.TypeSym.IsNUBSYM && fLift)
            {
                while (srcExpr.TypeSym.ParentSym.IsNUBSYM)
                {
                    srcExpr = BindNubGetValOrDef(srcExpr.TreeNode, srcExpr);
                }
            }

            if (srcExpr.Kind == EXPRKIND.LDTMP)
            {
                // The thing is already in a temp, no need to put it in another.
                nubInfo.PreExpr[exprIndex] = srcExpr;
                nubInfo.TmpExpr[exprIndex] = srcExpr;
                return(true);
            }

            // Create the temp.
            EXPRSTTMP   tmpStExpr   = NewExpr(srcExpr.TreeNode, EXPRKIND.STTMP, srcExpr.TypeSym) as EXPRSTTMP;
            EXPRLDTMP   tmpLdExpr   = NewExpr(srcExpr.TreeNode, EXPRKIND.LDTMP, srcExpr.TypeSym) as EXPRLDTMP;
            EXPRFREETMP tmpFreeExpr = NewExpr(srcExpr.TreeNode, EXPRKIND.FREETMP, srcExpr.TypeSym) as EXPRFREETMP;

            tmpStExpr.SourceExpr = srcExpr;
            tmpStExpr.Flags     |= EXPRFLAG.ASSGOP;
            tmpLdExpr.TmpExpr    = tmpStExpr;
            tmpFreeExpr.TmpExpr  = tmpStExpr;
            tmpFreeExpr.Flags   |= EXPRFLAG.ASSGOP;

            nubInfo.PreExpr[exprIndex]  = tmpStExpr;
            nubInfo.PostExpr[exprIndex] = tmpFreeExpr;
            nubInfo.TmpExpr[exprIndex]  = tmpLdExpr;

            return(true);
        }
Esempio n. 7
0
        //------------------------------------------------------------
        // FUNCBREC.BindNubConversion
        //
        // Called by bindImplicitConversion when the destination type is Nullable&lt;T&gt;. The following
        // conversions are handled by this method:
        //
        // * For S in { object, ValueType, interfaces implemented by underlying type} there is an explicit
        // unboxing conversion S =&gt; T?
        // * System.Enum =&gt; T? there is an unboxing conversion if T is an enum type
        // * null =&gt; T? implemented as default(T?)
        //
        // * Implicit T?* =&gt; T?+ implemented by either wrapping or calling GetValueOrDefault the
        // appropriate number of times.
        // * If imp/exp S =&gt; T then imp/exp S =&gt; T?+ implemented by converting to T then wrapping the
        // appropriate number of times.
        // * If imp/exp S =&gt; T then imp/exp S?+ =&gt; T?+ implemented by calling GetValueOrDefault (m-1) times
        // then calling HasValue, producing a null if it returns false, otherwise calling Value,
        // converting to T then wrapping the appropriate number of times.
        //
        // The 3 rules above can be summarized with the following recursive rules:
        //
        // * If imp/exp S =&gt; T? then imp/exp S? =&gt; T? implemented as
        // qs.HasValue ? (T?)(qs.Value) : default(T?)
        // * If imp/exp S =&gt; T then imp/exp S =&gt; T? implemented as new T?((T)s)
        //
        // This method also handles calling bindUserDefinedConverion. This method does NOT handle
        // the following conversions:
        //
        // * Implicit boxing conversion from S? to { object, ValueType, Enum, ifaces implemented by S }. (Handled by bindImplicitConversion.)
        // * If imp/exp S =&gt; T then explicit S?+ =&gt; T implemented by calling Value the appropriate number
        // of times. (Handled by bindExplicitConversion.)
        //
        // The recursive equivalent is:
        //
        // * If imp/exp S =&gt; T and T is not nullable then explicit S? =&gt; T implemented as qs.Value
        //
        // Some nullable conversion are NOT standard conversions. In particular, if S =&gt; T is implicit
        // then S? =&gt; T is not standard. Similarly if S =&gt; T is not implicit then S =&gt; T? is not standard.
        //
        /// <summary></summary>
        /// <param name="treeNode"></param>
        /// <param name="srcExpr"></param>
        /// <param name="srcTypeSym"></param>
        /// <param name="dstNubSym"></param>
        /// <param name="dstExpr"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        //------------------------------------------------------------
        private bool BindNubConversion(
            BASENODE treeNode,
            EXPR srcExpr,
            TYPESYM srcTypeSym,
            NUBSYM dstNubSym,
            ref EXPR dstExpr,
            ConvertTypeEnum flags)
        {
            // This code assumes that STANDARD and ISEXPLICIT are never both set.
            // bindUserDefinedConversion should ensure this!
            DebugUtil.Assert((~flags & (ConvertTypeEnum.STANDARD | ConvertTypeEnum.ISEXPLICIT)) != 0);

            DebugUtil.Assert(srcExpr == null || srcExpr.TypeSym == srcTypeSym);
            DebugUtil.Assert(dstExpr == null || srcExpr != null);

            DebugUtil.Assert(srcTypeSym != dstNubSym);
            // bindImplicitConversion should have taken care of this already.

            AGGTYPESYM dstAggTypeSym = dstNubSym.GetAggTypeSym();

            if (dstAggTypeSym == null)
            {
                return(false);
            }

            // Check for the unboxing conversion. This takes precedence over the wrapping conversions.
            if (Compiler.IsBaseType(dstNubSym.BaseTypeSym, srcTypeSym) && !FWrappingConv(srcTypeSym, dstNubSym))
            {
                // These should be different! Fix the caller if srcTypeSym is an AGGTYPESYM of Nullable.
                DebugUtil.Assert(dstAggTypeSym != srcTypeSym);

                // srcTypeSym is a base type of the destination nullable type so there is an explicit
                // unboxing conversion.
                if ((flags & ConvertTypeEnum.ISEXPLICIT) == 0)
                {
                    return(false);
                }
                return(BindSimpleCast(treeNode, srcExpr, dstNubSym, ref dstExpr, EXPRFLAG.UNBOX));
            }

            int     dstNubStripCount;
            int     srcNubStripCount;
            TYPESYM dstBaseTypeSym = dstNubSym.StripNubs(out dstNubStripCount);
            TYPESYM srcBaseTypeSym = srcTypeSym.StripNubs(out srcNubStripCount);

            bindNubConversion_Convert fnConvert;
            EXPR expr = null;   // temp

            if ((flags & ConvertTypeEnum.ISEXPLICIT) != 0)
            {
                fnConvert = new bindNubConversion_Convert(BindExplicitConversion);
            }
            else
            {
                fnConvert = new bindNubConversion_Convert(BindImplicitConversion);
            }

            //bool (FUNCBREC::*pfn)(BASENODE *, EXPR *, TYPESYM *, TYPESYM *, EXPR **, uint) =
            //    (flags & ISEXPLICIT) ? &FUNCBREC::bindExplicitConversion : &FUNCBREC::bindImplicitConversion;

            if (srcNubStripCount == 0)
            {
                DebugUtil.Assert(srcTypeSym == srcBaseTypeSym);

                // The null type can be implicitly converted to T? as the default value.
                if (srcTypeSym.IsNULLSYM)
                {
                    dstExpr = AddSideEffects(treeNode, NewExprZero(treeNode, dstNubSym), srcExpr, true, true);
                    return(true);
                }

                EXPR tempExpr = srcExpr;

                // If there is an implicit/explicit S => T then there is an implicit/explicit S => T?
                if (srcTypeSym == dstBaseTypeSym ||
                    fnConvert(
                        treeNode,
                        srcExpr,
                        srcTypeSym,
                        dstBaseTypeSym,
                        ref tempExpr,
                        flags | ConvertTypeEnum.NOUDC))
                {
                    // srcTypeSym is not nullable so just wrap the required number of times.
                    for (int i = 0; i < dstNubStripCount; i++)
                    {
                        tempExpr = BindNubNew(treeNode, tempExpr);
                    }
                    DebugUtil.Assert(tempExpr.TypeSym == dstNubSym);
                    dstExpr = tempExpr;
                    return(true);
                }

                // No builtin conversion. Maybe there is a user defined conversion....
                return(
                    (flags & ConvertTypeEnum.NOUDC) == 0 &&
                    BindUserDefinedConversion(
                        treeNode,
                        srcExpr,
                        srcTypeSym,
                        dstNubSym,
                        ref dstExpr,
                        (flags & ConvertTypeEnum.ISEXPLICIT) == 0));
            }

            // Both are Nullable so there is only a conversion if there is a conversion between the base types.
            // That is, if there is an implicit/explicit S => T then there is an implicit/explicit S?+ => T?+.
            if (srcBaseTypeSym != dstBaseTypeSym &&
                !fnConvert(treeNode, null, srcBaseTypeSym, dstBaseTypeSym, ref expr, flags | ConvertTypeEnum.NOUDC))
            {
                // No builtin conversion. Maybe there is a user defined conversion....
                return(
                    (flags & ConvertTypeEnum.NOUDC) == 0 &&
                    BindUserDefinedConversion(
                        treeNode,
                        srcExpr,
                        srcTypeSym,
                        dstNubSym,
                        ref dstExpr,
                        (flags & ConvertTypeEnum.ISEXPLICIT) == 0));
            }

            // We need to go all the way down to the base types, do the conversion, then come all the way back up.
            EXPR    valExpr;
            NubInfo nubInfo = new NubInfo();

            BindNubCondValBin(
                treeNode,
                srcExpr,
                null,
                ref nubInfo,
                LiftFlagsEnum.LiftBoth);
            valExpr = nubInfo.Val(0);

            DebugUtil.Assert(valExpr.TypeSym == srcBaseTypeSym);

            if (!fnConvert(
                    treeNode,
                    valExpr,
                    valExpr.TypeSym,
                    dstBaseTypeSym,
                    ref valExpr,
                    flags | ConvertTypeEnum.NOUDC))
            {
                DebugUtil.Assert(false, "bind(Im|Ex)plicitConversion failed unexpectedly");
                return(false);
            }

            for (int i = 0; i < dstNubStripCount; i++)
            {
                valExpr = BindNubNew(treeNode, valExpr);
            }
            DebugUtil.Assert(valExpr.TypeSym == dstNubSym);

            dstExpr = BindNubOpRes(treeNode, dstNubSym, dstNubSym, valExpr, ref nubInfo, false);

            return(true);
        }