Esempio n. 1
0
        //------------------------------------------------------------
        // FUNCBREC.BindNubNew
        //
        /// <summary>
        /// Create an expr for new T?(exprSrc) where T is exprSrc-&gt;type.
        /// </summary>
        /// <param name="treeNode"></param>
        /// <param name="srcExpr"></param>
        /// <returns></returns>
        //------------------------------------------------------------
        private EXPR BindNubNew(BASENODE treeNode, EXPR srcExpr)
        {
            DebugUtil.Assert(srcExpr != null);

            // Create a NUBSYM instance whose base bype is represented by srcExpr.TypeSym.
            NUBSYM nubSym = Compiler.MainSymbolManager.GetNubType(srcExpr.TypeSym);

            // Get a TYPESYM instance representing Nullable<> for nubSym.
            AGGTYPESYM aggTypeSym = nubSym.GetAggTypeSym();

            if (aggTypeSym == null)
            {
                return(NewError(treeNode, nubSym));
            }
            Compiler.EnsureState(aggTypeSym, AggStateEnum.Prepared);

            METHSYM methSym = Compiler.MainSymbolManager.NullableCtorMethodSym;

            if (methSym == null)
            {
                string name = Compiler.NameManager.GetPredefinedName(PREDEFNAME.CTOR);

                for (SYM sym = Compiler.MainSymbolManager.LookupAggMember(name, aggTypeSym.GetAggregate(), SYMBMASK.ALL);
                     ;
                     sym = sym.NextSameNameSym)
                {
                    if (sym == null)
                    {
                        Compiler.Error(treeNode, CSCERRID.ERR_MissingPredefinedMember,
                                       new ErrArg(aggTypeSym), new ErrArg(name));
                        return(NewError(treeNode, nubSym));
                    }
                    if (sym.IsMETHSYM)
                    {
                        methSym = sym as METHSYM;
                        if (methSym.ParameterTypes.Count == 1 && methSym.ParameterTypes[0].IsTYVARSYM &&
                            methSym.Access == ACCESS.PUBLIC)
                        {
                            break;
                        }
                    }
                }
                Compiler.MainSymbolManager.NullableCtorMethodSym = methSym;
            }

            EXPRCALL resExpr = NewExpr(treeNode, EXPRKIND.CALL, nubSym) as EXPRCALL;

            resExpr.MethodWithInst.Set(methSym, aggTypeSym, BSYMMGR.EmptyTypeArray);
            resExpr.ArgumentsExpr = srcExpr;
            resExpr.ObjectExpr    = null;
            resExpr.Flags        |= EXPRFLAG.NEWOBJCALL | EXPRFLAG.CANTBENULL;

            return(resExpr);
        }
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.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);
        }