HasIdentityOrImplicitReferenceConversion() public method

public HasIdentityOrImplicitReferenceConversion ( CType pSource, CType pDest ) : bool
pSource CType
pDest CType
return bool
Example #1
0
        public static bool HasGenericDelegateExplicitReferenceConversion(CType pSource, AggregateType pTarget)
        {
            if (!(pSource is AggregateType aggSrc) ||
                !aggSrc.IsDelegateType ||
                !pTarget.IsDelegateType ||
                aggSrc.OwningAggregate != pTarget.OwningAggregate ||
                SymbolLoader.HasIdentityOrImplicitReferenceConversion(aggSrc, pTarget))
            {
                return(false);
            }

            TypeArray pTypeParams = aggSrc.OwningAggregate.GetTypeVarsAll();
            TypeArray pSourceArgs = aggSrc.TypeArgsAll;
            TypeArray pTargetArgs = pTarget.TypeArgsAll;

            Debug.Assert(pTypeParams.Count == pSourceArgs.Count);
            Debug.Assert(pTypeParams.Count == pTargetArgs.Count);

            for (int iParam = 0; iParam < pTypeParams.Count; ++iParam)
            {
                CType pSourceArg = pSourceArgs[iParam];
                CType pTargetArg = pTargetArgs[iParam];

                // If they're identical then this one is automatically good, so skip it.
                // If we have an error type, then we're in some fault tolerance. Let it through.
                if (pSourceArg == pTargetArg)
                {
                    continue;
                }

                TypeParameterType pParam = (TypeParameterType)pTypeParams[iParam];
                if (pParam.Invariant)
                {
                    return(false);
                }

                if (pParam.Covariant)
                {
                    if (!FExpRefConv(pSourceArg, pTargetArg))
                    {
                        return(false);
                    }
                }
                else if (pParam.Contravariant)
                {
                    if (!pSourceArg.IsReferenceType || !pTargetArg.IsReferenceType)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Example #2
0
        /***************************************************************************************************
        *
        *  There exists an explicit conversion ...
        * From a generic delegate type S to generic delegate type T, provided all of the follow are true:
        *   o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is,
        *     S is D<S1,... Sk> and T is D<T1,... Tk>.
        *   o S is not compatible with or identical to T.
        *   o If type parameter Xi is declared to be invariant then Si must be identical to Ti.
        *   o If type parameter Xi is declared to be covariant ("out") then Si must be convertible
        *     to Ti via an identify conversion,  implicit reference conversion, or explicit reference conversion.
        *   o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti,
        *     or Si and Ti must both be reference types.
        ***************************************************************************************************/
        public static bool HasGenericDelegateExplicitReferenceConversion(SymbolLoader loader, CType pSource, CType pTarget)
        {
            if (!pSource.isDelegateType() ||
                !pTarget.isDelegateType() ||
                pSource.getAggregate() != pTarget.getAggregate() ||
                loader.HasIdentityOrImplicitReferenceConversion(pSource, pTarget))
            {
                return(false);
            }

            TypeArray pTypeParams = pSource.getAggregate().GetTypeVarsAll();
            TypeArray pSourceArgs = pSource.AsAggregateType().GetTypeArgsAll();
            TypeArray pTargetArgs = pTarget.AsAggregateType().GetTypeArgsAll();

            Debug.Assert(pTypeParams.size == pSourceArgs.size);
            Debug.Assert(pTypeParams.size == pTargetArgs.size);

            for (int iParam = 0; iParam < pTypeParams.size; ++iParam)
            {
                CType pSourceArg = pSourceArgs.Item(iParam);
                CType pTargetArg = pTargetArgs.Item(iParam);

                // If they're identical then this one is automatically good, so skip it.
                // If we have an error type, then we're in some fault tolerance. Let it through.
                if (pSourceArg == pTargetArg || pTargetArg.IsErrorType() || pSourceArg.IsErrorType())
                {
                    continue;
                }
                TypeParameterType pParam = pTypeParams.Item(iParam).AsTypeParameterType();
                if (pParam.Invariant)
                {
                    return(false);
                }

                if (pParam.Covariant)
                {
                    if (!FExpRefConv(loader, pSourceArg, pTargetArg))
                    {
                        return(false);
                    }
                }
                else if (pParam.Contravariant)
                {
                    if (!pSourceArg.IsRefType() || !pTargetArg.IsRefType())
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
Example #3
0
        /***************************************************************************************************
        *   Determine whether there is an explicit or implicit reference conversion (or identity conversion)
        *   from typeSrc to typeDst. This is when:
        *
        *  13.2.3 Explicit reference conversions
        *
        *  The explicit reference conversions are:
        *   From object to any reference-type.
        *   From any class-type S to any class-type T, provided S is a base class of T.
        *   From any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T.
        *   From any interface-type S to any class-type T, provided T is not sealed or provided T implements S.
        *   From any interface-type S to any interface-type T, provided S is not derived from T.
        *   From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true:
        *   o   S and T differ only in element type. (In other words, S and T have the same number of dimensions.)
        *   o   An explicit reference conversion exists from SE to TE.
        *   From System.Array and the interfaces it implements, to any array-type.
        *   From System.Delegate and the interfaces it implements, to any delegate-type.
        *   From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces, provided there is an explicit reference conversion from S to T.
        *   From a generic delegate type S to generic delegate type  T, provided all of the follow are true:
        *   o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is,
        *     S is D<S1,... Sk> and T is D<T1,... Tk>.
        *   o S is not compatible with or identical to T.
        *   o If type parameter Xi is declared to be invariant then Si must be identical to Ti.
        *   o If type parameter Xi is declared to be covariant ("out") then Si must be convertible
        *     to Ti via an identify conversion,  implicit reference conversion, or explicit reference conversion.
        *   o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti,
        *      or Si and Ti must both be reference types.
        *   From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T are the same type or there is an implicit or explicit reference conversion from S to T.
        *
        *  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 T to any interface-type I provided there isn't already an implicit reference conversion from T to I.
        *   From a type-parameter U to T 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. end note]
        *
        * Both src and dst are reference types and there is a builtin explicit conversion from
        *     src to dst.
        * Or src is a reference type and dst is a base type of src (in which case the conversion is
        *     implicit as well).
        * Or dst is a reference type and src is a base type of dst.
        *
        *   The latter two cases can happen with type variables even though the other type variable is not
        *   a reference type.
        ***************************************************************************************************/
        public static bool FExpRefConv(CType typeSrc, CType typeDst)
        {
            Debug.Assert(typeSrc != null);
            Debug.Assert(typeDst != null);
            if (typeSrc.IsReferenceType && typeDst.IsReferenceType)
            {
                // is there an implicit reference conversion in either direction?
                // this handles the bulk of the cases ...
                if (SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst) ||
                    SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc))
                {
                    return(true);
                }

                // For a type-parameter T that is known to be a reference type (25.7), the following explicit reference conversions exist:
                // *    From any interface-type to T.
                // *    From T to any interface-type I provided there isn't already an implicit reference conversion from T to I.
                if (typeSrc.IsInterfaceType && typeDst is TypeParameterType || typeSrc is TypeParameterType && typeDst.IsInterfaceType)
                {
                    return(true);
                }

                // * From any class-type S to any interface-type T, provided S is not sealed
                // * From any interface-type S to any class-type T, provided T is not sealed
                // * From any interface-type S to any interface-type T, provided S is not derived from T.
                if (typeSrc is AggregateType atSrc && typeDst is AggregateType atDst)
                {
                    AggregateSymbol aggSrc  = atSrc.OwningAggregate;
                    AggregateSymbol aggDest = atDst.OwningAggregate;

                    if ((aggSrc.IsClass() && !aggSrc.IsSealed() && aggDest.IsInterface()) ||
                        (aggSrc.IsInterface() && aggDest.IsClass() && !aggDest.IsSealed()) ||
                        (aggSrc.IsInterface() && aggDest.IsInterface()))
                    {
                        return(true);
                    }
                }

                if (typeSrc is ArrayType arrSrc)
                {
                    // *    From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true:
                    //     o    S and T differ only in element type. (In other words, S and T have the same number of dimensions.)
                    //     o    An explicit reference conversion exists from SE to TE.
                    if (typeDst is ArrayType arrDst)
                    {
                        return(arrSrc.Rank == arrDst.Rank &&
                               arrSrc.IsSZArray == arrDst.IsSZArray &&
                               FExpRefConv(arrSrc.ElementType, arrDst.ElementType));
                    }

                    // *    From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T>
                    //      and their base interfaces, provided there is an explicit reference conversion from S to T.
                    if (!arrSrc.IsSZArray || !typeDst.IsInterfaceType)
                    {
                        return(false);
                    }

                    AggregateType aggDst      = (AggregateType)typeDst;
                    TypeArray     typeArgsAll = aggDst.TypeArgsAll;

                    if (typeArgsAll.Count != 1)
                    {
                        return(false);
                    }

                    AggregateSymbol aggIList         = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST);
                    AggregateSymbol aggIReadOnlyList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST);

                    if ((aggIList == null ||
                         !SymbolLoader.IsBaseAggregate(aggIList, aggDst.OwningAggregate)) &&
                        (aggIReadOnlyList == null ||
                         !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggDst.OwningAggregate)))
                    {
                        return(false);
                    }

                    return(FExpRefConv(arrSrc.ElementType, typeArgsAll[0]));
                }

                if (typeDst is ArrayType arrayDest && typeSrc is AggregateType aggtypeSrc)
                {
                    // * From System.Array and the interfaces it implements, to any array-type.
                    if (SymbolLoader.HasIdentityOrImplicitReferenceConversion(SymbolLoader.GetPredefindType(PredefinedType.PT_ARRAY), typeSrc))
                    {
                        return(true);
                    }

                    // *    From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a
                    //      one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to
                    //      System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T
                    //      are the same type or there is an implicit or explicit reference conversion from S to T.
                    if (!arrayDest.IsSZArray || !typeSrc.IsInterfaceType || aggtypeSrc.TypeArgsAll.Count != 1)
                    {
                        return(false);
                    }

                    AggregateSymbol aggIList         = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST);
                    AggregateSymbol aggIReadOnlyList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST);

                    if ((aggIList == null ||
                         !SymbolLoader.IsBaseAggregate(aggIList, aggtypeSrc.OwningAggregate)) &&
                        (aggIReadOnlyList == null ||
                         !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggtypeSrc.OwningAggregate)))
                    {
                        return(false);
                    }

                    CType typeArr = arrayDest.ElementType;
                    CType typeLst = aggtypeSrc.TypeArgsAll[0];

                    Debug.Assert(!(typeArr is MethodGroupType));
                    return(typeArr == typeLst || FExpRefConv(typeArr, typeLst));
                }
                if (HasGenericDelegateExplicitReferenceConversion(typeSrc, typeDst))
                {
                    return(true);
                }
            }
            else if (typeSrc.IsReferenceType)
            {
                // conversion of T . U, where T : class, U
                // .. these constraints implies where U : class
                return(SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst));
            }
            else if (typeDst.IsReferenceType)
            {
                // conversion of T . U, where U : class, T
                // .. these constraints implies where T : class
                return(SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc));
            }
            return(false);
        }
Example #4
0
        // WARNING: These methods do not precisely match the spec.
        // WARNING: For example most also return true for identity conversions,
        // WARNING: FExpRefConv includes all Implicit and Explicit reference conversions.

        /***************************************************************************************************
        *   Determine whether there is an implicit reference conversion from typeSrc to typeDst. This is
        *   when the source is a reference type and the destination is a base type of the source. Note
        *   that typeDst.IsRefType() may still return false (when both are type parameters).
        ***************************************************************************************************/
        public static bool FImpRefConv(CType typeSrc, CType typeDst) =>
        typeSrc.IsReferenceType && SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst);
Example #5
0
        /***************************************************************************************************
            Determine whether there is an explicit or implicit reference conversion (or identity conversion)
            from typeSrc to typeDst. This is when:
         
         13.2.3 Explicit reference conversions
        
        The explicit reference conversions are:
        *   From object to any reference-type.
        *   From any class-type S to any class-type T, provided S is a base class of T.
        *   From any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T.
        *   From any interface-type S to any class-type T, provided T is not sealed or provided T implements S.
        *   From any interface-type S to any interface-type T, provided S is not derived from T.
        *   From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true:
            o   S and T differ only in element type. (In other words, S and T have the same number of dimensions.)
            o   An explicit reference conversion exists from SE to TE.
        *   From System.Array and the interfaces it implements, to any array-type.
        *   From System.Delegate and the interfaces it implements, to any delegate-type.
        *   From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces, provided there is an explicit reference conversion from S to T.
        *   From a generic delegate type S to generic delegate type  T, provided all of the follow are true:
            o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is, 
              S is D<S1,... Sk> and T is D<T1,... Tk>.
            o S is not compatible with or identical to T.
            o If type parameter Xi is declared to be invariant then Si must be identical to Ti.
            o If type parameter Xi is declared to be covariant ("out") then Si must be convertible 
              to Ti via an identify conversion,  implicit reference conversion, or explicit reference conversion.
            o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti, 
               or Si and Ti must both be reference types.
        *   From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T are the same type or there is an implicit or explicit reference conversion from S to T.
        
        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 T to any interface-type I provided there isn’t already an implicit reference conversion from T to I.
        *   From a type-parameter U to T 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. end note]
        
            * Both src and dst are reference types and there is a builtin explicit conversion from
              src to dst.
            * Or src is a reference type and dst is a base type of src (in which case the conversion is
              implicit as well).
            * Or dst is a reference type and src is a base type of dst.
         
            The latter two cases can happen with type variables even though the other type variable is not
            a reference type.
        ***************************************************************************************************/
        public static bool FExpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst)
        {
            Debug.Assert(typeSrc != null);
            Debug.Assert(typeDst != null);
            if (typeSrc.IsRefType() && typeDst.IsRefType())
            {
                // is there an implicit reference conversion in either direction?
                // this handles the bulk of the cases ...
                if (loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst) ||
                    loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc))
                {
                    return true;
                }

                // For a type-parameter T that is known to be a reference type (§25.7), the following explicit reference conversions exist:
                // •    From any interface-type to T.
                // •    From T to any interface-type I provided there isn’t already an implicit reference conversion from T to I.
                if (typeSrc.isInterfaceType() && typeDst.IsTypeParameterType())
                {
                    return true;
                }
                if (typeSrc.IsTypeParameterType() && typeDst.isInterfaceType())
                {
                    return true;
                }

                // * From any class-type S to any interface-type T, provided S is not sealed
                // * From any interface-type S to any class-type T, provided T is not sealed
                // * From any interface-type S to any interface-type T, provided S is not derived from T.
                if (typeSrc.IsAggregateType() && typeDst.IsAggregateType())
                {
                    AggregateSymbol aggSrc = typeSrc.AsAggregateType().getAggregate();
                    AggregateSymbol aggDest = typeDst.AsAggregateType().getAggregate();

                    if ((aggSrc.IsClass() && !aggSrc.IsSealed() && aggDest.IsInterface()) ||
                        (aggSrc.IsInterface() && aggDest.IsClass() && !aggDest.IsSealed()) ||
                        (aggSrc.IsInterface() && aggDest.IsInterface()))
                    {
                        return true;
                    }
                }

                // *    From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true:
                //     o    S and T differ only in element type. (In other words, S and T have the same number of dimensions.)
                //     o    An explicit reference conversion exists from SE to TE.
                if (typeSrc.IsArrayType() && typeDst.IsArrayType())
                {
                    return typeSrc.AsArrayType().rank == typeDst.AsArrayType().rank && FExpRefConv(loader, typeSrc.AsArrayType().GetElementType(), typeDst.AsArrayType().GetElementType());
                }

                // *    From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> 
                //      and their base interfaces, provided there is an explicit reference conversion from S to T.
                if (typeSrc.IsArrayType())
                {
                    if (typeSrc.AsArrayType().rank != 1 ||
                        !typeDst.isInterfaceType() || typeDst.AsAggregateType().GetTypeArgsAll().Size != 1)
                    {
                        return false;
                    }

                    AggregateSymbol aggIList = loader.GetOptPredefAgg(PredefinedType.PT_G_ILIST);
                    AggregateSymbol aggIReadOnlyList = loader.GetOptPredefAgg(PredefinedType.PT_G_IREADONLYLIST);

                    if ((aggIList == null ||
                        !loader.IsBaseAggregate(aggIList, typeDst.AsAggregateType().getAggregate())) &&
                        (aggIReadOnlyList == null ||
                        !loader.IsBaseAggregate(aggIReadOnlyList, typeDst.AsAggregateType().getAggregate())))
                    {
                        return false;
                    }

                    return FExpRefConv(loader, typeSrc.AsArrayType().GetElementType(), typeDst.AsAggregateType().GetTypeArgsAll().Item(0));
                }

                if (typeDst.IsArrayType() && typeSrc.IsAggregateType())
                {
                    // * From System.Array and the interfaces it implements, to any array-type.
                    if (loader.HasIdentityOrImplicitReferenceConversion(loader.GetReqPredefType(PredefinedType.PT_ARRAY), typeSrc))
                    {
                        return true;
                    }

                    // *    From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a 
                    //      one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to 
                    //      System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T
                    //      are the same type or there is an implicit or explicit reference conversion from S to T.
                    ArrayType arrayDest = typeDst.AsArrayType();
                    AggregateType aggtypeSrc = typeSrc.AsAggregateType();
                    if (arrayDest.rank != 1 || !typeSrc.isInterfaceType() ||
                        aggtypeSrc.GetTypeArgsAll().Size != 1)
                    {
                        return false;
                    }

                    AggregateSymbol aggIList = loader.GetOptPredefAgg(PredefinedType.PT_G_ILIST);
                    AggregateSymbol aggIReadOnlyList = loader.GetOptPredefAgg(PredefinedType.PT_G_IREADONLYLIST);

                    if ((aggIList == null ||
                        !loader.IsBaseAggregate(aggIList, aggtypeSrc.getAggregate())) &&
                        (aggIReadOnlyList == null ||
                        !loader.IsBaseAggregate(aggIReadOnlyList, aggtypeSrc.getAggregate())))
                    {
                        return false;
                    }

                    CType typeArr = arrayDest.GetElementType();
                    CType typeLst = aggtypeSrc.GetTypeArgsAll().Item(0);

                    Debug.Assert(!typeArr.IsNeverSameType());
                    return typeArr == typeLst || FExpRefConv(loader, typeArr, typeLst);
                }
                if (HasGenericDelegateExplicitReferenceConversion(loader, typeSrc, typeDst))
                {
                    return true;
                }
            }
            else if (typeSrc.IsRefType())
            {
                // conversion of T . U, where T : class, U
                // .. these constraints implies where U : class
                return loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst);
            }
            else if (typeDst.IsRefType())
            {
                // conversion of T . U, where U : class, T 
                // .. these constraints implies where T : class
                return loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc);
            }
            return false;
        }
Example #6
0
        // WARNING: These methods do not precisely match the spec.
        // WARNING: For example most also return true for identiy conversions,
        // WARNING: FExpRefConv includes all Implict and Explicit reference conversions.

        /***************************************************************************************************
            Determine whether there is an implicit reference conversion from typeSrc to typeDst. This is
            when the source is a reference type and the destination is a base type of the source. Note
            that typeDst.IsRefType() may still return false (when both are type parameters).
        ***************************************************************************************************/
        public static bool FImpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst)
        {
            return typeSrc.IsRefType() && loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst);
        }
Example #7
0
        /***************************************************************************************************

         There exists an explicit conversion ...
         * From a generic delegate type S to generic delegate type T, provided all of the follow are true:
            o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is,
              S is D<S1,... Sk> and T is D<T1,... Tk>.
            o S is not compatible with or identical to T.
            o If type parameter Xi is declared to be invariant then Si must be identical to Ti.
            o If type parameter Xi is declared to be covariant ("out") then Si must be convertible 
              to Ti via an identify conversion,  implicit reference conversion, or explicit reference conversion.
            o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti, 
              or Si and Ti must both be reference types.
        ***************************************************************************************************/
        public static bool HasGenericDelegateExplicitReferenceConversion(SymbolLoader loader, CType pSource, CType pTarget)
        {
            if (!pSource.isDelegateType() ||
                !pTarget.isDelegateType() ||
                pSource.getAggregate() != pTarget.getAggregate() ||
                loader.HasIdentityOrImplicitReferenceConversion(pSource, pTarget))
            {
                return false;
            }

            TypeArray pTypeParams = pSource.getAggregate().GetTypeVarsAll();
            TypeArray pSourceArgs = pSource.AsAggregateType().GetTypeArgsAll();
            TypeArray pTargetArgs = pTarget.AsAggregateType().GetTypeArgsAll();

            Debug.Assert(pTypeParams.size == pSourceArgs.size);
            Debug.Assert(pTypeParams.size == pTargetArgs.size);

            for (int iParam = 0; iParam < pTypeParams.size; ++iParam)
            {
                CType pSourceArg = pSourceArgs.Item(iParam);
                CType pTargetArg = pTargetArgs.Item(iParam);

                // If they're identical then this one is automatically good, so skip it.
                // If we have an error type, then we're in some fault tolerance. Let it through.
                if (pSourceArg == pTargetArg || pTargetArg.IsErrorType() || pSourceArg.IsErrorType())
                {
                    continue;
                }
                TypeParameterType pParam = pTypeParams.Item(iParam).AsTypeParameterType();
                if (pParam.Invariant)
                {
                    return false;
                }

                if (pParam.Covariant)
                {
                    if (!FExpRefConv(loader, pSourceArg, pTargetArg))
                    {
                        return false;
                    }
                }
                else if (pParam.Contravariant)
                {
                    if (!pSourceArg.IsRefType() || !pTargetArg.IsRefType())
                    {
                        return false;
                    }
                }
            }
            return true;
        }
Example #8
0
        // WARNING: These methods do not precisely match the spec.
        // WARNING: For example most also return true for identity conversions,
        // WARNING: FExpRefConv includes all Implicit and Explicit reference conversions.

        /***************************************************************************************************
        *   Determine whether there is an implicit reference conversion from typeSrc to typeDst. This is
        *   when the source is a reference type and the destination is a base type of the source. Note
        *   that typeDst.IsRefType() may still return false (when both are type parameters).
        ***************************************************************************************************/
        public static bool FImpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst)
        {
            return(typeSrc.IsRefType() && loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst));
        }
Example #9
0
        /***************************************************************************************************
        *   Determine whether there is an explicit or implicit reference conversion (or identity conversion)
        *   from typeSrc to typeDst. This is when:
        *
        *  13.2.3 Explicit reference conversions
        *
        *  The explicit reference conversions are:
        *   From object to any reference-type.
        *   From any class-type S to any class-type T, provided S is a base class of T.
        *   From any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T.
        *   From any interface-type S to any class-type T, provided T is not sealed or provided T implements S.
        *   From any interface-type S to any interface-type T, provided S is not derived from T.
        *   From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true:
        *   o   S and T differ only in element type. (In other words, S and T have the same number of dimensions.)
        *   o   An explicit reference conversion exists from SE to TE.
        *   From System.Array and the interfaces it implements, to any array-type.
        *   From System.Delegate and the interfaces it implements, to any delegate-type.
        *   From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces, provided there is an explicit reference conversion from S to T.
        *   From a generic delegate type S to generic delegate type  T, provided all of the follow are true:
        *   o Both types are constructed generic types of the same generic delegate type, D<X1,... Xk>.That is,
        *     S is D<S1,... Sk> and T is D<T1,... Tk>.
        *   o S is not compatible with or identical to T.
        *   o If type parameter Xi is declared to be invariant then Si must be identical to Ti.
        *   o If type parameter Xi is declared to be covariant ("out") then Si must be convertible
        *     to Ti via an identify conversion,  implicit reference conversion, or explicit reference conversion.
        *   o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti,
        *      or Si and Ti must both be reference types.
        *   From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T are the same type or there is an implicit or explicit reference conversion from S to T.
        *
        *  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 T to any interface-type I provided there isn’t already an implicit reference conversion from T to I.
        *   From a type-parameter U to T 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. end note]
        *
        * Both src and dst are reference types and there is a builtin explicit conversion from
        *     src to dst.
        * Or src is a reference type and dst is a base type of src (in which case the conversion is
        *     implicit as well).
        * Or dst is a reference type and src is a base type of dst.
        *
        *   The latter two cases can happen with type variables even though the other type variable is not
        *   a reference type.
        ***************************************************************************************************/
        public static bool FExpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst)
        {
            Debug.Assert(typeSrc != null);
            Debug.Assert(typeDst != null);
            if (typeSrc.IsRefType() && typeDst.IsRefType())
            {
                // is there an implicit reference conversion in either direction?
                // this handles the bulk of the cases ...
                if (loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst) ||
                    loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc))
                {
                    return(true);
                }

                // For a type-parameter T that is known to be a reference type (§25.7), the following explicit reference conversions exist:
                // •    From any interface-type to T.
                // •    From T to any interface-type I provided there isn’t already an implicit reference conversion from T to I.
                if (typeSrc.isInterfaceType() && typeDst.IsTypeParameterType())
                {
                    return(true);
                }
                if (typeSrc.IsTypeParameterType() && typeDst.isInterfaceType())
                {
                    return(true);
                }

                // * From any class-type S to any interface-type T, provided S is not sealed
                // * From any interface-type S to any class-type T, provided T is not sealed
                // * From any interface-type S to any interface-type T, provided S is not derived from T.
                if (typeSrc.IsAggregateType() && typeDst.IsAggregateType())
                {
                    AggregateSymbol aggSrc  = typeSrc.AsAggregateType().getAggregate();
                    AggregateSymbol aggDest = typeDst.AsAggregateType().getAggregate();

                    if ((aggSrc.IsClass() && !aggSrc.IsSealed() && aggDest.IsInterface()) ||
                        (aggSrc.IsInterface() && aggDest.IsClass() && !aggDest.IsSealed()) ||
                        (aggSrc.IsInterface() && aggDest.IsInterface()))
                    {
                        return(true);
                    }
                }

                // *    From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true:
                //     o    S and T differ only in element type. (In other words, S and T have the same number of dimensions.)
                //     o    An explicit reference conversion exists from SE to TE.
                if (typeSrc.IsArrayType() && typeDst.IsArrayType())
                {
                    return(typeSrc.AsArrayType().rank == typeDst.AsArrayType().rank&& FExpRefConv(loader, typeSrc.AsArrayType().GetElementType(), typeDst.AsArrayType().GetElementType()));
                }

                // *    From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T>
                //      and their base interfaces, provided there is an explicit reference conversion from S to T.
                if (typeSrc.IsArrayType())
                {
                    if (typeSrc.AsArrayType().rank != 1 ||
                        !typeDst.isInterfaceType() || typeDst.AsAggregateType().GetTypeArgsAll().Size != 1)
                    {
                        return(false);
                    }

                    AggregateSymbol aggIList         = loader.GetOptPredefAgg(PredefinedType.PT_G_ILIST);
                    AggregateSymbol aggIReadOnlyList = loader.GetOptPredefAgg(PredefinedType.PT_G_IREADONLYLIST);

                    if ((aggIList == null ||
                         !loader.IsBaseAggregate(aggIList, typeDst.AsAggregateType().getAggregate())) &&
                        (aggIReadOnlyList == null ||
                         !loader.IsBaseAggregate(aggIReadOnlyList, typeDst.AsAggregateType().getAggregate())))
                    {
                        return(false);
                    }

                    return(FExpRefConv(loader, typeSrc.AsArrayType().GetElementType(), typeDst.AsAggregateType().GetTypeArgsAll().Item(0)));
                }

                if (typeDst.IsArrayType() && typeSrc.IsAggregateType())
                {
                    // * From System.Array and the interfaces it implements, to any array-type.
                    if (loader.HasIdentityOrImplicitReferenceConversion(loader.GetReqPredefType(PredefinedType.PT_ARRAY), typeSrc))
                    {
                        return(true);
                    }

                    // *    From System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T> and their base interfaces to a
                    //      one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to
                    //      System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T
                    //      are the same type or there is an implicit or explicit reference conversion from S to T.
                    ArrayType     arrayDest  = typeDst.AsArrayType();
                    AggregateType aggtypeSrc = typeSrc.AsAggregateType();
                    if (arrayDest.rank != 1 || !typeSrc.isInterfaceType() ||
                        aggtypeSrc.GetTypeArgsAll().Size != 1)
                    {
                        return(false);
                    }

                    AggregateSymbol aggIList         = loader.GetOptPredefAgg(PredefinedType.PT_G_ILIST);
                    AggregateSymbol aggIReadOnlyList = loader.GetOptPredefAgg(PredefinedType.PT_G_IREADONLYLIST);

                    if ((aggIList == null ||
                         !loader.IsBaseAggregate(aggIList, aggtypeSrc.getAggregate())) &&
                        (aggIReadOnlyList == null ||
                         !loader.IsBaseAggregate(aggIReadOnlyList, aggtypeSrc.getAggregate())))
                    {
                        return(false);
                    }

                    CType typeArr = arrayDest.GetElementType();
                    CType typeLst = aggtypeSrc.GetTypeArgsAll().Item(0);

                    Debug.Assert(!typeArr.IsNeverSameType());
                    return(typeArr == typeLst || FExpRefConv(loader, typeArr, typeLst));
                }
                if (HasGenericDelegateExplicitReferenceConversion(loader, typeSrc, typeDst))
                {
                    return(true);
                }
            }
            else if (typeSrc.IsRefType())
            {
                // conversion of T . U, where T : class, U
                // .. these constraints implies where U : class
                return(loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst));
            }
            else if (typeDst.IsRefType())
            {
                // conversion of T . U, where U : class, T
                // .. these constraints implies where T : class
                return(loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc));
            }
            return(false);
        }