Example #1
0
        // Internally callable version of the export method above. Has two additional parameters:
        //  fBoxedSource            : assume the source type is boxed so that value types and enums are
        //                            compatible with Object, ValueType and Enum (if applicable)
        //  fAllowSizeEquivalence   : allow identically sized integral types and enums to be considered
        //                            equivalent (currently used only for array element types)
        static internal unsafe bool AreTypesAssignableInternal(EEType *pSourceType, EEType *pTargetType, bool fBoxedSource, bool fAllowSizeEquivalence)
        {
            //
            // Are the types identical?
            //
            if (AreTypesEquivalentInternal(pSourceType, pTargetType))
            {
                return(true);
            }

            //
            // Handle cast to interface cases.
            //
            if (pTargetType->IsInterface)
            {
                // Value types can only be cast to interfaces if they're boxed.
                if (!fBoxedSource && pSourceType->IsValueType)
                {
                    return(false);
                }

                if (ImplementsInterface(pSourceType, pTargetType))
                {
                    return(true);
                }

                // Are the types compatible due to generic variance?
                if (pTargetType->HasGenericVariance && pSourceType->HasGenericVariance)
                {
                    return(TypesAreCompatibleViaGenericVariance(pSourceType, pTargetType));
                }

                return(false);
            }
            if (pSourceType->IsInterface)
            {
                // The only non-interface type an interface can be cast to is Object.
                return(WellKnownEETypes.IsSystemObject(pTargetType));
            }

            //
            // Handle cast to array or pointer cases.
            //
            if (pTargetType->IsParameterizedType)
            {
                if (pSourceType->IsParameterizedType && (pTargetType->ParameterizedTypeShape == pSourceType->ParameterizedTypeShape))
                {
                    // Source type is also a parameterized type. Are the parameter types compatible? Note that using
                    // AreTypesAssignableInternal here handles array covariance as well as IFoo[] -> Foo[]
                    // etc. Pass false for fBoxedSource since int[] is not assignable to object[].
                    if (pSourceType->RelatedParameterType->IsPointerTypeDefinition)
                    {
                        // If the parameter types are pointers, then only exact matches are correct.
                        // As we've already called AreTypesEquivalent at the start of this function,
                        // return false as the exact match case has already been handled.
                        // int** is not compatible with uint**, nor is int*[] oompatible with uint*[].
                        return(false);
                    }
                    else
                    {
                        return(AreTypesAssignableInternal(pSourceType->RelatedParameterType, pTargetType->RelatedParameterType, false, true));
                    }
                }

                // Can't cast a non-parameter type to a parameter type or a parameter type of different shape to a parameter type
                return(false);
            }
            if (pSourceType->IsArray)
            {
                // Target type is not an array. But we can still cast arrays to Object or System.Array.
                return(WellKnownEETypes.IsSystemObject(pTargetType) || WellKnownEETypes.IsSystemArray(pTargetType));
            }
            else if (pSourceType->IsParameterizedType)
            {
                return(false);
            }

            //
            // Handle cast to other (non-interface, non-array) cases.
            //

            if (pSourceType->IsValueType)
            {
                // Certain value types of the same size are treated as equivalent when the comparison is
                // between array element types (indicated by fAllowSizeEquivalence). These are integer types
                // of the same size (e.g. int and uint) and the base type of enums vs all integer types of the
                // same size.
                if (fAllowSizeEquivalence && pTargetType->IsValueType)
                {
                    if (ArePrimitveTypesEquivalentSize(pSourceType, pTargetType))
                    {
                        return(true);
                    }

                    // Non-identical value types aren't equivalent in any other case (since value types are
                    // sealed).
                    return(false);
                }

                // If the source type is a value type but it's not boxed then we've run out of options: the types
                // are not identical, the target type isn't an interface and we're not allowed to check whether
                // the target type is a parent of this one since value types are sealed and thus the only matches
                // would be against Object, ValueType or Enum, all of which are reference types and not compatible
                // with non-boxed value types.
                if (!fBoxedSource)
                {
                    return(false);
                }
            }

            // Sub case of casting between two instantiations of the same delegate type where one or more of
            // the type parameters have variance. Only interfaces and delegate types can have variance over
            // their type parameters and we know that neither type is an interface due to checks above.
            if (pTargetType->HasGenericVariance && pSourceType->HasGenericVariance)
            {
                // We've dealt with the identical case at the start of this method. And the regular path below
                // will handle casting to Object, Delegate and MulticastDelegate. Since we don't support
                // deriving from user delegate classes any further all we have to check here is that the
                // uninstantiated generic delegate definitions are the same and the type parameters are
                // compatible.
                return(TypesAreCompatibleViaGenericVariance(pSourceType, pTargetType));
            }

            // Is the source type derived from the target type?
            if (IsDerived(pSourceType, pTargetType))
            {
                return(true);
            }

            return(false);
        }
Example #2
0
        static public /*internal*/ unsafe object IsInstanceOfClass(object obj, void *pvTargetType)
        {
            if (obj == null)
            {
                return(null);
            }

            EEType *pTargetType = (EEType *)pvTargetType;
            EEType *pObjType    = obj.EEType;

            Debug.Assert(!pTargetType->IsParameterizedType, "IsInstanceOfClass called with parameterized EEType");
            Debug.Assert(!pTargetType->IsInterface, "IsInstanceOfClass called with interface EEType");

            // if the EETypes pointers match, we're done
            if (pObjType == pTargetType)
            {
                return(obj);
            }

            // Quick check if both types are good for simple casting: canonical, no related type via IAT, no generic variance
            if (System.Runtime.EEType.BothSimpleCasting(pObjType, pTargetType))
            {
                // walk the type hierarchy looking for a match
                do
                {
                    pObjType = pObjType->BaseType;

                    if (pObjType == null)
                    {
                        return(null);
                    }

                    if (pObjType == pTargetType)
                    {
                        return(obj);
                    }
                }while (pObjType->SimpleCasting());
            }

            if (pTargetType->IsCloned)
            {
                pTargetType = pTargetType->CanonicalEEType;
            }

            if (pObjType->IsCloned)
            {
                pObjType = pObjType->CanonicalEEType;
            }

            // if the EETypes pointers match, we're done
            if (pObjType == pTargetType)
            {
                return(obj);
            }

            if (pTargetType->HasGenericVariance && pObjType->HasGenericVariance)
            {
                // Only generic interfaces and delegates can have generic variance and we shouldn't see
                // interfaces for either input here. So if the canonical types are marked as having variance
                // we know we've hit the delegate case. We've dealt with the identical case just above. And
                // the regular path below will handle casting to Object, Delegate and MulticastDelegate. Since
                // we don't support deriving from user delegate classes any further all we have to check here
                // is that the uninstantiated generic delegate definitions are the same and the type
                // parameters are compatible.
                return(TypesAreCompatibleViaGenericVariance(pObjType, pTargetType) ? obj : null);
            }

            if (pObjType->IsArray)
            {
                // arrays can be cast to System.Object
                if (WellKnownEETypes.IsSystemObject(pTargetType))
                {
                    return(obj);
                }

                // arrays can be cast to System.Array
                if (WellKnownEETypes.IsSystemArray(pTargetType))
                {
                    return(obj);
                }

                return(null);
            }


            // walk the type hierarchy looking for a match
            while (true)
            {
                pObjType = pObjType->NonClonedNonArrayBaseType;
                if (pObjType == null)
                {
                    return(null);
                }

                if (pObjType->IsCloned)
                {
                    pObjType = pObjType->CanonicalEEType;
                }

                if (pObjType == pTargetType)
                {
                    return(obj);
                }
            }
        }