/// <inheritdoc/>
        internal override bool IsAssignableFrom(TypeData sourceType, IsAssignableFromContext context)
        {
            if (base.IsAssignableFrom(sourceType, context))
            {
                return(true);
            }

            if (context.OnlyReferenceAndIdentityConversions == false)
            {
                // See if there are any user-defined implicit conversions from the source type to the target type defined in new types:
                // (we want to check in new types because a breaking change in a new version due to a type change can be mitigated by
                // defining an implicit conversion in one of the types in the new version).
                if (DoesSourceTypeHaveImplicitOperatorOverloadToTarget(sourceType, context))
                {
                    return(true);
                }

                if (DoesTargetTypeHaveImplicitOperatorOverloadFromSource(sourceType, context))
                {
                    return(true);
                }
            }

            return(false);
        }
Пример #2
0
        /// <summary>
        /// Gets the value indicating whether a variable of the current type is assignable from the specified source type.
        /// </summary>
        /// <param name="sourceType">The source type from which to test assignability to this type.</param>
        /// <param name="context">Information about the context of the IsAssignableFrom invocation.</param>
        /// <returns>True if a value of the source type is assignable to a variable of the current type.</returns>
#endif
        internal override bool IsAssignableFrom(TypeData sourceType, IsAssignableFromContext context)
        {
            if (base.IsAssignableFrom(sourceType, context))
            {
                return(true);
            }

            // From C# specification: (The implicit reference conversions are)
            // - 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:
            //   - S and T differ only in element type. In other words, S and T have the same number of dimensions.
            //   - Both Se and Te are reference-types.
            //   - An implicit reference conversion exists from Se to Te.
            if (this.ElementType.IsValueType == false)
            {
                int      sourceRank;
                TypeData sourceElementType;
                if (sourceType.IsArray(out sourceRank, out sourceElementType) &&
                    sourceElementType.IsValueType == false &&
                    this.ArrayRank == sourceRank)
                {
                    return(this.ElementType.IsAssignableFrom(sourceElementType, new IsAssignableFromContext(context.NewAssemblyFamily, context.IsSourceTypeOld, onlyReferenceAndIdentityConversions: true)));
                }
            }

            return(false);
        }
Пример #3
0
        /// <summary>
        /// Indicates whether a variable of the current type is assignable from the specified source type.
        /// </summary>
        /// <param name="sourceType">The source type from which to test assignability to this type.</param>
        /// <param name="context">Information about the context of the IsAssignableFrom invocation.</param>
        /// <returns>True if a value of the source type is assignable to a variable of the current type.</returns>
#endif
        internal virtual bool IsAssignableFrom(TypeData sourceType, IsAssignableFromContext context)
        {
            if (this.IsEquivalentTo(sourceType, context.NewAssemblyFamily, context.IsSourceTypeOld))
            {
                return(true);
            }

            foreach (var implicitConversionType in sourceType.GetDirectImplicitConversions(context.OnlyReferenceAndIdentityConversions))
            {
                if (this.IsAssignableFrom(implicitConversionType, context))
                {
                    return(true);
                }
            }

            return(false);
        }
Пример #4
0
        /// <summary>
        /// Gets the value indicating whether a variable of the current type is assignable from the specified source type.
        /// </summary>
        /// <param name="sourceType">The source type from which to test assignability to this type.</param>
        /// <param name="context">Information about the context of the IsAssignableFrom invocation.</param>
        /// <returns>True if a value of the source type is assignable to a variable of the current type.</returns>
#endif
        internal override bool IsAssignableFrom(TypeData sourceType, IsAssignableFromContext context)
        {
            if (base.IsAssignableFrom(sourceType, context))
            {
                return(true);
            }

            // Test for covariance and contravariance
            if (this.SupportsVariantTypeParameters && sourceType.IsVarianceConvertibleTo(this, context))
            {
                return(true);
            }

            // From C# specification: (The implicit reference conversions are)
            // - From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces, provided that there is an implicit identity
            //   or reference conversion from S to T.
            TypeData iListElementType;
            int      arrayRank;
            TypeData arrayElementType;

            if (this.IsIListGenericType(out iListElementType) &&
                sourceType.IsArray(out arrayRank, out arrayElementType) &&
                arrayRank == 1)
            {
                return(iListElementType.IsAssignableFrom(arrayElementType, new IsAssignableFromContext(context.NewAssemblyFamily, context.IsSourceTypeOld, onlyReferenceAndIdentityConversions: true)));
            }

            if (context.OnlyReferenceAndIdentityConversions == false)
            {
                TypeData targetUnderlyingType;
                if (this.IsNullable(out targetUnderlyingType))
                {
                    // An implicit conversion from S? to T?
                    TypeData sourceUnderlyingType;
                    if (sourceType.IsNullable(out sourceUnderlyingType))
                    {
                        return(targetUnderlyingType.IsAssignableFrom(sourceUnderlyingType, context));
                    }

                    // An implicit conversion from S to T?
                    return(targetUnderlyingType.IsAssignableFrom(sourceType, context));
                }
            }

            return(false);
        }
Пример #5
0
        /// <inheritdoc/>
        internal override bool IsAssignableFrom(TypeData sourceType, IsAssignableFromContext context)
        {
            if (base.IsAssignableFrom(sourceType, context))
            {
                return(true);
            }

            // Test for covariance and contravariance
            if (SupportsVariantTypeParameters && sourceType.IsVarianceConvertibleTo(this, context))
            {
                return(true);
            }
            if (IsIListGenericType(out TypeData iListElementType) &&
                sourceType.IsArray(out int arrayRank, out TypeData arrayElementType) &&
                arrayRank == 1)
            {
                return(iListElementType.IsAssignableFrom(arrayElementType, new IsAssignableFromContext(context.NewAssemblyFamily, context.IsSourceTypeOld, onlyReferenceAndIdentityConversions: true)));
            }

            if (context.OnlyReferenceAndIdentityConversions == false)
            {
                if (IsNullable(out TypeData targetUnderlyingType))
                {
                    // An implicit conversion from S? to T?
                    if (sourceType.IsNullable(out TypeData sourceUnderlyingType))
                    {
                        return(targetUnderlyingType.IsAssignableFrom(sourceUnderlyingType, context));
                    }

                    // An implicit conversion from S to T?
                    return(targetUnderlyingType.IsAssignableFrom(sourceType, context));
                }
            }

            return(false);
        }
Пример #6
0
        /// <inheritdoc/>
        internal override bool IsVarianceConvertibleTo(ConstructedGenericTypeData target, IsAssignableFromContext context)
        {
            if (target.TypeKind == TypeKind &&
                target.GenericTypeDefinition == GenericTypeDefinition &&
                target.GenericArguments.Count == GenericArguments.Count)
            {
                Debug.Assert(
                    target.GenericArguments.Count == GenericArguments.Count,
                    "Two constructed generic types from the same generic type definition should have the same number of generic arguments.");

                var genericParameters = target.GenericTypeDefinition.GenericParameters;
                for (int i = 0, count = genericParameters.Count; i < count; i++)
                {
                    if (genericParameters[i].IsGenericTypeArgumentVariant(target.GenericArguments[i], GenericArguments[i], context) == false)
                    {
                        return(false);
                    }
                }

                return(true);
            }

            return(false);
        }
        private bool DoesTargetTypeHaveImplicitOperatorOverloadFromSource(TypeData sourceType, IsAssignableFromContext context)
        {
            var newTargetType = context.IsTargetTypeOld
                ? GetEquivalentNewType(context.NewAssemblyFamily) as DeclaringTypeData
                : this;

            if (newTargetType == null)
            {
                return(false);
            }

            var implicitOperators = newTargetType.GetMembers(OperatorData.ImplicitCastOperatorName)
                                    .OfType <OperatorData>()
                                    .Where(o => o.Type == newTargetType);

            foreach (var op in implicitOperators)
            {
                if (context.IsSourceTypeOld)
                {
                    if (op.Parameters[0].Type.IsEquivalentToOld(sourceType, context.NewAssemblyFamily))
                    {
                        return(true);
                    }
                }
                else
                {
                    if (op.Parameters[0].Type == sourceType)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Пример #8
0
        /// <summary>
        /// Determines whether the variance of the type parameter allows the source type in the parameter's position to vary to the target type when the declaring
        /// generic of one construction is trying to be converted to a another construction.
        /// </summary>
        /// <param name="targetArgument">The type in this parameter's position in the target constructed generic type.</param>
        /// <param name="sourceArgument">The type in this parameter's position in the source constructed generic type.</param>
        /// <param name="context">Information about the context of the IsAssignableFrom invocation.</param>
        internal bool IsGenericTypeArgumentVariant(TypeData targetArgument, TypeData sourceArgument, IsAssignableFromContext context)
        {
            var variance = GenericParameterAttributes & GenericParameterAttributes.VarianceMask;

            switch (variance)
            {
            case GenericParameterAttributes.None:
                return(targetArgument.IsEquivalentTo(sourceArgument, context.NewAssemblyFamily, context.IsSourceTypeOld));

            case GenericParameterAttributes.Contravariant:
                return(sourceArgument.IsAssignableFrom(targetArgument, new IsAssignableFromContext(context.NewAssemblyFamily, context.IsSourceTypeOld, onlyReferenceAndIdentityConversions: true)));

            case GenericParameterAttributes.Covariant:
                return(targetArgument.IsAssignableFrom(sourceArgument, new IsAssignableFromContext(context.NewAssemblyFamily, context.IsSourceTypeOld, onlyReferenceAndIdentityConversions: true)));

            default:
                Debug.Fail("Unknown variance: " + variance);
                return(false);
            }
        }
Пример #9
0
        /// <summary>
        /// Indicates whether the type can convert to the specified target type using type parameter variance.
        /// </summary>
        /// <param name="target">The target type to which this type might convert.</param>
        /// <param name="context">Information about the context of the IsAssignableFrom invocation.</param>
        /// <returns>True is the type is variance convertible to the target; False otherwise.</returns>
#endif
        internal virtual bool IsVarianceConvertibleTo(ConstructedGenericTypeData target, IsAssignableFromContext context)
        {
            return(false);
        }