Beispiel #1
0
            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);
            }
Beispiel #2
0
            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());
                }
            }