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.IsTypeParameterType()) { // Need to box first before unboxing. EXPR exprT; EXPRCLASS exprObj = GetExprFactory().MakeClass(_binder.GetReqPDT(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); }
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.Size) { return(false); } typeTmp = bnds.Item(itype); }while (!typeTmp.isInterfaceType() && !typeTmp.IsTypeParameterType()); } }