public CreateCast ( EXPRFLAG nFlags, |
||
nFlags | EXPRFLAG | |
pType | ||
pArg | ||
return | Microsoft.CSharp.RuntimeBinder.Semantics.EXPRCAST |
private Expr GenerateIndexList(Expr oldIndices) { CType intType = symbolLoader.GetPredefindType(PredefinedType.PT_INT); Expr newIndices = null; Expr newIndicesTail = newIndices; for (ExpressionIterator it = new ExpressionIterator(oldIndices); !it.AtEnd(); it.MoveNext()) { Expr newIndex = it.Current(); if (newIndex.Type != intType) { newIndex = expressionFactory.CreateCast(EXPRFLAG.EXF_INDEXEXPR, intType, newIndex); newIndex.Flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } Expr rewrittenIndex = Visit(newIndex); expressionFactory.AppendItemToList(rewrittenIndex, ref newIndices, ref newIndicesTail); } return(newIndices); }
private bool bindImplicitConversionFromNull() { // null type can be implicitly converted to any reference type or pointer type or type // variable with reference-type constraint. FUNDTYPE ftDest = _typeDest.FundamentalType; if (ftDest != FUNDTYPE.FT_REF && ftDest != FUNDTYPE.FT_PTR && // null is convertible to System.Nullable<T>. !_typeDest.IsPredefType(PredefinedType.PT_G_OPTIONAL)) { return false; } if (_needsExprDest) { // If the conversion argument is a constant null then return a ZEROINIT. // Otherwise, bind this as a cast to the destination type. In a later // rewrite pass we will rewrite the cast as SEQ(side effects, ZEROINIT). _exprDest = _exprSrc is ExprConstant ? ExprFactory.CreateZeroInit(_typeDest) : ExprFactory.CreateCast(_typeDest, _exprSrc); } return true; }
private static Expr GenerateConstant(Expr expr) { EXPRFLAG flags = 0; AggregateType pObject = SymbolLoader.GetPredefindType(PredefinedType.PT_OBJECT); if (expr.Type is NullType) { ExprTypeOf pTypeOf = CreateTypeOf(pObject); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE, expr, pTypeOf)); } AggregateType stringType = SymbolLoader.GetPredefindType(PredefinedType.PT_STRING); if (expr.Type != stringType) { flags = EXPRFLAG.EXF_BOX; } ExprCast cast = ExprFactory.CreateCast(flags, pObject, expr); ExprTypeOf pTypeOf2 = CreateTypeOf(expr.Type); return(GenerateCall(PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE, cast, pTypeOf2)); }
/*************************************************************************************************** * Called by BindImplicitConversion when the destination type is Nullable<T>. 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 => T? * System.Enum => T? there is an unboxing conversion if T is an enum type * null => T? implemented as default(T?) * * Implicit T?* => T?+ implemented by either wrapping or calling GetValueOrDefault the * appropriate number of times. * If imp/exp S => T then imp/exp S => T?+ implemented by converting to T then wrapping the * appropriate number of times. * If imp/exp S => T then imp/exp S?+ => 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 => T? then imp/exp S? => T? implemented as * qs.HasValue ? (T?)(qs.Value) : default(T?) * If imp/exp S => T then imp/exp S => 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 => T then explicit S?+ => T implemented by calling Value the appropriate number * of times. (Handled by BindExplicitConversion.) * * The recursive equivalent is: * * If imp/exp S => T and T is not nullable then explicit S? => T implemented as qs.Value * * Some nullable conversion are NOT standard conversions. In particular, if S => T is implicit * then S? => T is not standard. Similarly if S => T is not implicit then S => T? is not standard. ***************************************************************************************************/ private bool BindNubConversion(NullableType nubDst) { // This code assumes that STANDARD and ISEXPLICIT are never both set. // bindUserDefinedConversion should ensure this! Debug.Assert(0 != (~_flags & (CONVERTTYPE.STANDARD | CONVERTTYPE.ISEXPLICIT))); Debug.Assert(_exprSrc == null || _exprSrc.Type == _typeSrc); Debug.Assert(!_needsExprDest || _exprSrc != null); Debug.Assert(_typeSrc != nubDst); // BindImplicitConversion should have taken care of this already. AggregateType atsDst = nubDst.GetAts(); // Check for the unboxing conversion. This takes precedence over the wrapping conversions. if (SymbolLoader.HasBaseConversion(nubDst.UnderlyingType, _typeSrc) && !CConversions.FWrappingConv(_typeSrc, nubDst)) { // These should be different! Fix the caller if typeSrc is an AggregateType of Nullable. Debug.Assert(atsDst != _typeSrc); // typeSrc is a base type of the destination nullable type so there is an explicit // unboxing conversion. if (0 == (_flags & CONVERTTYPE.ISEXPLICIT)) { return(false); } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_UNBOX); } return(true); } bool dstWasNullable; bool srcWasNullable; CType typeDstBase = nubDst.StripNubs(out dstWasNullable); CType typeSrcBase = _typeSrc.StripNubs(out srcWasNullable); ConversionFunc pfn = (_flags & CONVERTTYPE.ISEXPLICIT) != 0 ? (ConversionFunc)_binder.BindExplicitConversion : (ConversionFunc)_binder.BindImplicitConversion; if (!srcWasNullable) { Debug.Assert(_typeSrc == typeSrcBase); // The null type can be implicitly converted to T? as the default value. if (_typeSrc is NullType) { // If we have the constant null, generate it as a default value of T?. If we have // some wacky expression which has been determined to be always null, like (null??null) // keep it in its expression form and transform it in the nullable rewrite pass. if (_needsExprDest) { _exprDest = _exprSrc is ExprConstant ? ExprFactory.CreateZeroInit(nubDst) : ExprFactory.CreateCast(_typeDest, _exprSrc); } return(true); } Expr exprTmp = _exprSrc; // If there is an implicit/explicit S => T then there is an implicit/explicit S => T? if (_typeSrc == typeDstBase || pfn(_exprSrc, _typeSrc, typeDstBase, _needsExprDest, out exprTmp, _flags | CONVERTTYPE.NOUDC)) { if (_needsExprDest) { ExprUserDefinedConversion exprUDC = exprTmp as ExprUserDefinedConversion; if (exprUDC != null) { exprTmp = exprUDC.UserDefinedCall; } if (dstWasNullable) { ExprCall call = BindNubNew(exprTmp); exprTmp = call; call.NullableCallLiftKind = NullableCallLiftKind.NullableConversionConstructor; } if (exprUDC != null) { exprUDC.UserDefinedCall = exprTmp; exprTmp = exprUDC; } Debug.Assert(exprTmp.Type == nubDst); _exprDest = exprTmp; } return(true); } // No builtin conversion. Maybe there is a user defined conversion.... return(0 == (_flags & CONVERTTYPE.NOUDC) && _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, nubDst, _needsExprDest, out _exprDest, 0 == (_flags & CONVERTTYPE.ISEXPLICIT))); } // 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 (typeSrcBase != typeDstBase && !pfn(null, typeSrcBase, typeDstBase, false, out _exprDest, _flags | CONVERTTYPE.NOUDC)) { // No builtin conversion. Maybe there is a user defined conversion.... return(0 == (_flags & CONVERTTYPE.NOUDC) && _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, nubDst, _needsExprDest, out _exprDest, 0 == (_flags & CONVERTTYPE.ISEXPLICIT))); } if (_needsExprDest) { MethWithInst mwi = new MethWithInst(null, null); ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi); ExprCall exprDst = ExprFactory.CreateCall(0, nubDst, _exprSrc, pMemGroup, null); // Here we want to first check whether or not the conversions work on the base types. Expr arg1 = _binder.mustCast(_exprSrc, typeSrcBase); bool convertible = (_flags & CONVERTTYPE.ISEXPLICIT) != 0 ? _binder.BindExplicitConversion( arg1, arg1.Type, typeDstBase, out arg1, _flags | CONVERTTYPE.NOUDC) : _binder.BindImplicitConversion( arg1, arg1.Type, typeDstBase, out arg1, _flags | CONVERTTYPE.NOUDC); if (!convertible) { Debug.Fail("bind(Im|Ex)plicitConversion failed unexpectedly"); return(false); } exprDst.CastOfNonLiftedResultToLiftedType = _binder.mustCast(arg1, nubDst, 0); exprDst.NullableCallLiftKind = NullableCallLiftKind.NullableConversion; exprDst.PConversions = exprDst.CastOfNonLiftedResultToLiftedType; _exprDest = exprDst; } return(true); }
///////////////////////////////////////////////////////////////////////////////// private static EXPR GenerateOptionalArgument( SymbolLoader symbolLoader, ExprFactory exprFactory, MethodOrPropertySymbol methprop, CType type, int index) { CType pParamType = type; CType pRawParamType = type.IsNullableType() ? type.AsNullableType().GetUnderlyingType() : type; EXPR optionalArgument = null; if (methprop.HasDefaultParameterValue(index)) { CType pConstValType = methprop.GetDefaultParameterValueConstValType(index); CONSTVAL cv = methprop.GetDefaultParameterValue(index); if (pConstValType.isPredefType(PredefinedType.PT_DATETIME) && (pRawParamType.isPredefType(PredefinedType.PT_DATETIME) || pRawParamType.isPredefType(PredefinedType.PT_OBJECT) || pRawParamType.isPredefType(PredefinedType.PT_VALUE))) { // This is the specific case where we want to create a DateTime // but the constval that stores it is a long. AggregateType dateTimeType = symbolLoader.GetReqPredefType(PredefinedType.PT_DATETIME); optionalArgument = exprFactory.CreateConstant(dateTimeType, new CONSTVAL(DateTime.FromBinary(cv.longVal))); } else if (pConstValType.isSimpleOrEnumOrString()) { // In this case, the constval is a simple type (all the numerics, including // decimal), or an enum or a string. This covers all the substantial values, // and everything else that can be encoded is just null or default(something). // For enum parameters, we create a constant of the enum type. For everything // else, we create the appropriate constant. if (pRawParamType.isEnumType() && pConstValType == pRawParamType.underlyingType()) { optionalArgument = exprFactory.CreateConstant(pRawParamType, cv); } else { optionalArgument = exprFactory.CreateConstant(pConstValType, cv); } } else if ((pParamType.IsRefType() || pParamType.IsNullableType()) && cv.IsNullRef()) { // We have an "= null" default value with a reference type or a nullable type. optionalArgument = exprFactory.CreateNull(); } else { // We have a default value that is encoded as a nullref, and that nullref is // interpreted as default(something). For instance, the pParamType could be // a type parameter type or a non-simple value type. optionalArgument = exprFactory.CreateZeroInit(pParamType); } } else { // There was no default parameter specified, so generally use default(T), // except for some cases when the parameter type in metatdata is object. if (pParamType.isPredefType(PredefinedType.PT_OBJECT)) { if (methprop.MarshalAsObject(index)) { // For [opt] parameters of type object, if we have marshal(iunknown), // marshal(idispatch), or marshal(interface), then we emit a null. optionalArgument = exprFactory.CreateNull(); } else { // Otherwise, we generate Type.Missing AggregateSymbol agg = symbolLoader.GetOptPredefAgg(PredefinedType.PT_MISSING); Name name = symbolLoader.GetNameManager().GetPredefinedName(PredefinedName.PN_CAP_VALUE); FieldSymbol field = symbolLoader.LookupAggMember(name, agg, symbmask_t.MASK_FieldSymbol).AsFieldSymbol(); FieldWithType fwt = new FieldWithType(field, agg.getThisType()); EXPRFIELD exprField = exprFactory.CreateField(0, agg.getThisType(), null, 0, fwt, null); if (agg.getThisType() != type) { optionalArgument = exprFactory.CreateCast(0, type, exprField); } else { optionalArgument = exprField; } } } else { // Every type aside from object that doesn't have a default value gets // its default value. optionalArgument = exprFactory.CreateZeroInit(pParamType); } } Debug.Assert(optionalArgument != null); optionalArgument.IsOptionalArgument = true; return optionalArgument; }