示例#1
0
        private Expr GenerateUserDefinedConversion(ExprUserDefinedConversion pExpr, Expr pArgument)
        {
            Expr pCastCall     = pExpr.UserDefinedCall;
            Expr pCastArgument = pExpr.Argument;
            Expr pConversionSource;

            if (!isEnumToDecimalConversion(pArgument.Type, pExpr.Type) &&
                IsNullableValueAccess(pCastArgument, pArgument))
            {
                // We have an implicit conversion of nullable CType to the value CType, generate a convert node for it.
                pConversionSource = GenerateValueAccessConversion(pArgument);
            }
            else
            {
                ExprCall call          = pCastCall as ExprCall;
                Expr     pUDConversion = call?.PConversions;
                if (pUDConversion != null)
                {
                    if (pUDConversion is ExprCall convCall)
                    {
                        Expr pUDConversionArgument = convCall.OptionalArguments;
                        if (IsNullableValueAccess(pUDConversionArgument, pArgument))
                        {
                            pConversionSource = GenerateValueAccessConversion(pArgument);
                        }
                        else
                        {
                            pConversionSource = Visit(pUDConversionArgument);
                        }

                        return(GenerateConversionWithSource(pConversionSource, pCastCall.Type, call.isChecked()));
                    }

                    // This can happen if we have a UD conversion from C to, say, int,
                    // and we have an explicit cast to decimal?. The conversion should
                    // then be bound as two chained user-defined conversions.
                    Debug.Assert(pUDConversion is ExprUserDefinedConversion);

                    // Just recurse.
                    return(GenerateUserDefinedConversion((ExprUserDefinedConversion)pUDConversion, pArgument));
                }

                pConversionSource = Visit(pCastArgument);
            }

            return(GenerateUserDefinedConversion(pCastArgument, pExpr.Type, pConversionSource, pExpr.UserDefinedCallMethod));
        }
示例#2
0
        protected override Expr VisitCALL(ExprCall expr)
        {
            Debug.Assert(expr != null);
            switch (expr.NullableCallLiftKind)
            {
            default:
                break;

            case NullableCallLiftKind.NullableIntermediateConversion:
            case NullableCallLiftKind.NullableConversion:
            case NullableCallLiftKind.NullableConversionConstructor:
                return(GenerateConversion(expr.OptionalArguments, expr.Type, expr.isChecked()));

            case NullableCallLiftKind.NotLiftedIntermediateConversion:
            case NullableCallLiftKind.UserDefinedConversion:
                return(GenerateUserDefinedConversion(expr.OptionalArguments, expr.Type, expr.MethWithInst));
            }

            if (expr.MethWithInst.Meth().IsConstructor())
            {
                return(GenerateConstructor(expr));
            }

            ExprMemberGroup memberGroup = expr.MemberGroup;

            if (memberGroup.IsDelegate)
            {
                return(GenerateDelegateInvoke(expr));
            }

            Expr pObject;

            if (expr.MethWithInst.Meth().isStatic || expr.MemberGroup.OptionalObject == null)
            {
                pObject = GetExprFactory().CreateNull();
            }
            else
            {
                pObject = expr.MemberGroup.OptionalObject;

                // If we have, say, an int? which is the object of a call to ToString
                // then we do NOT want to generate ((object)i).ToString() because that
                // will convert a null-valued int? to a null object.  Rather what we want
                // to do is box it to a ValueType and call ValueType.ToString.
                //
                // To implement this we say that if the object of the call is an implicit boxing cast
                // then just generate the object, not the cast.  If the cast is explicit in the
                // source code then it will be an EXPLICITCAST and we will visit it normally.
                //
                // It might be better to rewrite the expression tree API so that it
                // can handle in the general case all implicit boxing conversions. Right now it
                // requires that all arguments to a call that need to be boxed be explicitly boxed.

                if (pObject != null && pObject is ExprCast cast && cast.IsBoxingCast)
                {
                    pObject = cast.Argument;
                }
                pObject = Visit(pObject);
            }
            Expr       methodInfo = GetExprFactory().CreateMethodInfo(expr.MethWithInst);
            Expr       args       = GenerateArgsList(expr.OptionalArguments);
            Expr       Params     = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION);
            PREDEFMETH pdm        = PREDEFMETH.PM_EXPRESSION_CALL;

            Debug.Assert(!expr.MethWithInst.Meth().isVirtual || expr.MemberGroup.OptionalObject != null);

            return(GenerateCall(pdm, pObject, methodInfo, Params));
        }