public ExprClass CreateClass(CType pType, ExprTypeArguments pOptionalTypeArguments) { Debug.Assert(pType != null); ExprClass rval = new ExprClass(pType); return(rval); }
private ExprTypeOf CreateTypeOf(ExprClass pSourceType) { ExprTypeOf rval = new ExprTypeOf(GetTypes().GetReqPredefAgg(PredefinedType.PT_TYPE).getThisType()); rval.Flags = EXPRFLAG.EXF_CANTBENULL; rval.SourceType = pSourceType; return(rval); }
public ExprCast(EXPRFLAG flags, ExprClass destinationType, Expr argument) : base(ExpressionKind.Cast) { Debug.Assert(argument != null); Debug.Assert(destinationType != null); Debug.Assert((flags & ~(EXPRFLAG.EXF_CAST_ALL | EXPRFLAG.EXF_MASK_ANY)) == 0); Argument = argument; Flags = flags; DestinationType = destinationType; }
public ExprClass CreateClass(CType pType, Expr pOptionalLHS, ExprTypeArguments pOptionalTypeArguments) { Debug.Assert(pType != null); ExprClass rval = new ExprClass(); rval.Kind = ExpressionKind.EK_CLASS; rval.Type = pType; rval.TypeOrNamespace = pType; Debug.Assert(rval != null); return(rval); }
public ImplicitConversion(ExpressionBinder binder, Expr exprSrc, CType typeSrc, ExprClass typeDest, bool needsExprDest, CONVERTTYPE flags) { _binder = binder; _exprSrc = exprSrc; _typeSrc = typeSrc; _typeDest = typeDest.Type; _exprTypeDest = typeDest; _needsExprDest = needsExprDest; _flags = flags; _exprDest = null; }
// ---------------------------------------------------------------------------- // BindExplicitConversion // ---------------------------------------------------------------------------- public ExplicitConversion(ExpressionBinder binder, Expr exprSrc, CType typeSrc, ExprClass typeDest, CType pDestinationTypeForLambdaErrorReporting, bool needsExprDest, CONVERTTYPE flags) { _binder = binder; _exprSrc = exprSrc; _typeSrc = typeSrc; _typeDest = typeDest.Type; _pDestinationTypeForLambdaErrorReporting = pDestinationTypeForLambdaErrorReporting; _exprTypeDest = typeDest; _needsExprDest = needsExprDest; _flags = flags; _exprDest = null; }
public ExprCast CreateCast(EXPRFLAG nFlags, ExprClass pType, Expr pArg) { Debug.Assert(pArg != null); Debug.Assert(pType != null); Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_CAST_ALL | EXPRFLAG.EXF_MASK_ANY))); ExprCast rval = new ExprCast(); rval.Argument = pArg; rval.Flags = nFlags; rval.DestinationType = pType; return(rval); }
private AggCastResult bindExplicitConversionFromEnumToDecimal(AggregateType aggTypeDest) { Debug.Assert(_typeSrc != null); Debug.Assert(aggTypeDest != null); Debug.Assert(aggTypeDest.isPredefType(PredefinedType.PT_DECIMAL)); AggregateType underlyingType = _typeSrc.underlyingType() as AggregateType; // Need to first cast the source expr to its underlying type. Expr exprCast; if (_exprSrc == null) { exprCast = null; } else { ExprClass underlyingExpr = GetExprFactory().CreateClass(underlyingType); _binder.bindSimpleCast(_exprSrc, underlyingExpr, out exprCast); } // There is always an implicit conversion from any integral type to decimal. if (exprCast.GetConst() != null) { // Fold the constant cast if possible. ConstCastResult result = _binder.bindConstantCast(exprCast, _exprTypeDest, _needsExprDest, out _exprDest, true); if (result == ConstCastResult.Success) { return(AggCastResult.Success); // else, don't fold and use a regular cast, below. } if (result == ConstCastResult.CheckFailure && 0 == (_flags & CONVERTTYPE.CHECKOVERFLOW)) { return(AggCastResult.Abort); } } // Conversions from integral types to decimal are always bound as a user-defined conversion. if (_needsExprDest) { // 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 CONVERTTYPE.NOUDC flag here. bool ok = _binder.bindUserDefinedConversion(exprCast, underlyingType, aggTypeDest, _needsExprDest, out _exprDest, false); Debug.Assert(ok); } return(AggCastResult.Success); }
private bool bindExplicitConversionToTypeVar() { // 13.2.3 Explicit reference conversions // // For a type-parameter T that is known to be a reference type (25.7), the following // explicit reference conversions exist: // // * From the effective base class C of T to T and from any base class of C to T. // * From any interface-type to T. // * From a type-parameter U to T provided that T depends on U (25.7). Debug.Assert(_typeSrc != null); Debug.Assert(_typeDest != null); // NOTE: for the flags, we have to use EXPRFLAG.EXF_FORCE_UNBOX (not EXPRFLAG.EXF_REFCHECK) even when // we know that the type is a reference type. The verifier expects all code for // type parameters to behave as if the type parameter is a value type. // The jitter should be smart about it.... if (_typeSrc.isInterfaceType() || _binder.canConvert(_typeDest, _typeSrc, CONVERTTYPE.NOUDC)) { if (!_needsExprDest) { return(true); } // There is an explicit, possibly unboxing, conversion from Object or any interface to // a type variable. This will involve a type check and possibly an unbox. // There is an explicit conversion from non-interface X to the type var iff there is an // implicit conversion from the type var to X. if (_typeSrc is TypeParameterType) { // Need to box first before unboxing. Expr exprT; ExprClass exprObj = GetExprFactory().CreateClass(_binder.GetPredefindType(PredefinedType.PT_OBJECT)); _binder.bindSimpleCast(_exprSrc, exprObj, out exprT, EXPRFLAG.EXF_FORCE_BOX); _exprSrc = exprT; } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_FORCE_UNBOX); } return(true); } return(false); }
protected virtual Expr VisitCLASS(ExprClass pExpr) { return(VisitEXPR(pExpr)); }
private ExprTypeOf CreateTypeOf(ExprClass sourceType) => new ExprTypeOf(Types.GetPredefAgg(PredefinedType.PT_TYPE).getThisType(), sourceType);
public ExprCast CreateCast(EXPRFLAG flags, ExprClass type, Expr argument) => new ExprCast(flags, type, argument);
private Expr CreateZeroInit(ExprClass typeExpr, Expr originalConstructorCall, bool isConstructor) { Debug.Assert(typeExpr != null); CType type = typeExpr.Type; bool isError = false; if (type.isEnumType()) { // For enum types, we create a constant that has the default value // as an object pointer. return(CreateConstant(type, ConstVal.Get(Activator.CreateInstance(type.AssociatedSystemType)))); } switch (type.fundType()) { case FUNDTYPE.FT_PTR: { CType nullType = Types.GetNullType(); // It looks like this if is always false ... if (nullType.fundType() == type.fundType()) { // Create a constant here. return(CreateConstant(type, ConstVal.GetDefaultValue(ConstValKind.IntPtr))); } // Just allocate a new node and fill it in. return(CreateCast(0, typeExpr, CreateNull())); } case FUNDTYPE.FT_REF: case FUNDTYPE.FT_I1: case FUNDTYPE.FT_U1: case FUNDTYPE.FT_I2: case FUNDTYPE.FT_U2: case FUNDTYPE.FT_I4: case FUNDTYPE.FT_U4: case FUNDTYPE.FT_I8: case FUNDTYPE.FT_U8: case FUNDTYPE.FT_R4: case FUNDTYPE.FT_R8: return(CreateConstant(type, ConstVal.GetDefaultValue(type.constValKind()))); case FUNDTYPE.FT_STRUCT: if (type.isPredefType(PredefinedType.PT_DECIMAL)) { goto case FUNDTYPE.FT_R8; } break; case FUNDTYPE.FT_VAR: break; default: isError = true; break; } return(new ExprZeroInit(type, originalConstructorCall, isConstructor, isError)); }
/*************************************************************************************************** * 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 (GetSymbolLoader().HasBaseConversion(nubDst.GetUnderlyingType(), _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, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_UNBOX); } return(true); } bool dstWasNullable; bool srcWasNullable; CType typeDstBase = nubDst.StripNubs(out dstWasNullable); ExprClass exprTypeDstBase = GetExprFactory().CreateClass(typeDstBase); 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 crazy 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) { if (_exprSrc.isCONSTANT_OK()) { _exprDest = GetExprFactory().CreateZeroInit(nubDst); } else { _exprDest = GetExprFactory().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, exprTypeDstBase, nubDst, _needsExprDest, out exprTmp, _flags | CONVERTTYPE.NOUDC)) { if (_needsExprDest) { ExprUserDefinedConversion exprUDC = exprTmp as ExprUserDefinedConversion; if (exprUDC != null) { exprTmp = exprUDC.UserDefinedCall; } if (dstWasNullable) { ExprCall call = _binder.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, exprTypeDstBase, nubDst, 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 = GetExprFactory().CreateMemGroup(null, mwi); ExprCall exprDst = GetExprFactory().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); ExprClass arg2 = GetExprFactory().CreateClass(typeDstBase); bool convertible = (_flags & CONVERTTYPE.ISEXPLICIT) != 0 ? _binder.BindExplicitConversion( arg1, arg1.Type, arg2, typeDstBase, out arg1, _flags | CONVERTTYPE.NOUDC) : _binder.BindImplicitConversion( arg1, arg1.Type, arg2, 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); }
protected virtual Expr VisitCLASS(ExprClass pExpr) { return(VisitTYPEORNAMESPACE(pExpr)); }
//////////////////////////////////////////////////////////////////////////////// // // Precondition: // // pType - Non-null // // This returns a null for reference types and an EXPRZEROINIT for all others. public Expr CreateZeroInit(CType pType) { ExprClass exprClass = MakeClass(pType); return(CreateZeroInit(exprClass)); }
private bool bindImplicitConversionFromTypeVar(TypeParameterType tyVarSrc) { // 13.1.4 // // For a type-parameter T that is known to be a reference type (25.7), the following implicit // reference conversions exist: // // * From T to its effective base class C, from T to any base class of C, and from T to any // interface implemented by C. // * From T to an interface-type I in T's effective interface set and from T to any base // interface of I. // * From T to a type parameter U provided that T depends on U (25.7). [Note: Since T is known // to be a reference type, within the scope of T, the run-time type of U will always be a // reference type, even if U is not known to be a reference type at compile-time.] // * From the null type (11.2.7) to T. // // 13.1.5 // // For a type-parameter T that is not known to be a reference type (25.7), the following conversions // involving T are considered to be boxing conversions at compile-time. At run-time, if T is a value // type, the conversion is executed as a boxing conversion. At run-time, if T is a reference type, // the conversion is executed as an implicit reference conversion or identity conversion. // // * From T to its effective base class C, from T to any base class of C, and from T to any // interface implemented by C. [Note: C will be one of the types System.Object, System.ValueType, // or System.Enum (otherwise T would be known to be a reference type and 13.1.4 would apply // instead of this clause).] // * From T to an interface-type I in T's effective interface set and from T to any base // interface of I. // // 13.1.6 Implicit type parameter conversions // // This clause details implicit conversions involving type parameters that are not classified as // implicit reference conversions or implicit boxing conversions. // // For a type-parameter T that is not known to be a reference type, there is an implicit conversion // from T to a type parameter U provided T depends on U. At run-time, if T is a value type and U is // a reference type, the conversion is executed as a boxing conversion. At run-time, if both T and U // are value types, then T and U are necessarily the same type and no conversion is performed. At // run-time, if T is a reference type, then U is necessarily also a reference type and the conversion // is executed as an implicit reference conversion or identity conversion (25.7). CType typeTmp = tyVarSrc.GetEffectiveBaseClass(); TypeArray bnds = tyVarSrc.GetBounds(); int itype = -1; for (; ;) { if (_binder.canConvert(typeTmp, _typeDest, _flags | CONVERTTYPE.NOUDC)) { if (!_needsExprDest) { return(true); } if (_typeDest.IsTypeParameterType()) { // For a type var destination we need to cast to object then to the other type var. Expr exprT; ExprClass exprObj = GetExprFactory().MakeClass(_binder.GetReqPDT(PredefinedType.PT_OBJECT)); _binder.bindSimpleCast(_exprSrc, exprObj, out exprT, EXPRFLAG.EXF_FORCE_BOX); _binder.bindSimpleCast(exprT, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_FORCE_UNBOX); } else { _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_FORCE_BOX); } return(true); } do { if (++itype >= bnds.Count) { return(false); } typeTmp = bnds[itype]; }while (!typeTmp.isInterfaceType() && !typeTmp.IsTypeParameterType()); } }
private Expr CreateZeroInit(ExprClass pTypeExpr, Expr pOptionalOriginalConstructorCall, bool isConstructor) { Debug.Assert(pTypeExpr != null); CType pType = pTypeExpr.Type; bool bIsError = false; if (pType.isEnumType()) { // For enum types, we create a constant that has the default value // as an object pointer. ExprConstant expr = CreateConstant(pType, ConstVal.Get(Activator.CreateInstance(pType.AssociatedSystemType))); return(expr); } switch (pType.fundType()) { default: bIsError = true; break; case FUNDTYPE.FT_PTR: { CType nullType = GetTypes().GetNullType(); // It looks like this if is always false ... if (nullType.fundType() == pType.fundType()) { // Create a constant here. ExprConstant expr = CreateConstant(pType, ConstVal.GetDefaultValue(ConstValKind.IntPtr)); return(expr); } // Just allocate a new node and fill it in. ExprCast cast = CreateCast(0, pTypeExpr, CreateNull()); return(cast); } case FUNDTYPE.FT_REF: case FUNDTYPE.FT_I1: case FUNDTYPE.FT_U1: case FUNDTYPE.FT_I2: case FUNDTYPE.FT_U2: case FUNDTYPE.FT_I4: case FUNDTYPE.FT_U4: case FUNDTYPE.FT_I8: case FUNDTYPE.FT_U8: case FUNDTYPE.FT_R4: case FUNDTYPE.FT_R8: { ExprConstant expr = CreateConstant(pType, ConstVal.GetDefaultValue(pType.constValKind())); ExprConstant exprInOriginal = CreateConstant(pType, ConstVal.GetDefaultValue(pType.constValKind())); exprInOriginal.OptionalConstructorCall = pOptionalOriginalConstructorCall; return(expr); } case FUNDTYPE.FT_STRUCT: if (pType.isPredefType(PredefinedType.PT_DECIMAL)) { ExprConstant expr = CreateConstant(pType, ConstVal.GetDefaultValue(pType.constValKind())); ExprConstant exprOriginal = CreateConstant(pType, ConstVal.GetDefaultValue(pType.constValKind())); exprOriginal.OptionalConstructorCall = pOptionalOriginalConstructorCall; return(expr); } break; case FUNDTYPE.FT_VAR: break; } ExprZeroInit rval = new ExprZeroInit(pType); rval.OptionalConstructorCall = pOptionalOriginalConstructorCall; rval.IsConstructor = isConstructor; if (bIsError) { rval.SetError(); } return(rval); }
private Expr CreateZeroInit(ExprClass pTypeExpr) { return(CreateZeroInit(pTypeExpr, null, false)); }