AsArrayType() public méthode

public AsArrayType ( ) : Microsoft.CSharp.RuntimeBinder.Semantics.ArrayType
Résultat Microsoft.CSharp.RuntimeBinder.Semantics.ArrayType
            private bool bindExplicitConversionFromArrayToIList()
            {
                // 13.2.2
                //
                // The explicit reference conversions are:
                //
                // * 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.

                Debug.Assert(_typeSrc != null);
                Debug.Assert(_typeDest != null);

                if (!_typeSrc.IsArrayType() || _typeSrc.AsArrayType().rank != 1 ||
                    !_typeDest.isInterfaceType() || _typeDest.AsAggregateType().GetTypeArgsAll().Count != 1)
                {
                    return(false);
                }

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

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

                CType typeArr = _typeSrc.AsArrayType().GetElementType();
                CType typeLst = _typeDest.AsAggregateType().GetTypeArgsAll()[0];

                if (!CConversions.FExpRefConv(GetSymbolLoader(), typeArr, typeLst))
                {
                    return(false);
                }

                if (_needsExprDest)
                {
                    _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_REFCHECK);
                }
                return(true);
            }
Exemple #2
0
            private bool bindImplicitConversionFromArray()
            {
                // 13.1.4
                //
                // 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.
                //     *   An implicit reference conversion exists from SE to TE.
                // *   From a one-dimensional array-type S[] to System.Collections.Generic.IList<S>,
                //     System.Collections.Generic.IReadOnlyList<S> and their base interfaces
                // *   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 implicit reference conversion from S to T.
                // *   From any array-type to System.Array.
                // *   From any array-type to any interface implemented by System.Array.

                if (!GetSymbolLoader().HasBaseConversion(typeSrc, typeDest))
                {
                    return(false);
                }

                EXPRFLAG grfex = 0;

                // The above if checks for dest==Array, object or an interface the array implements,
                // including IList<T>, ICollection<T>, IEnumerable<T>, IReadOnlyList<T>, IReadOnlyCollection<T>
                // and the non-generic versions.
                // REVIEW : Determine when we need EXF_REFCHECK!

                if ((typeDest.IsArrayType() ||
                     (typeDest.isInterfaceType() &&
                      typeDest.AsAggregateType().GetTypeArgsAll().Size == 1 &&
                      ((typeDest.AsAggregateType().GetTypeArgsAll().Item(0) != typeSrc.AsArrayType().GetElementType()) ||
                       0 != (flags & CONVERTTYPE.FORCECAST))))
                    &&
                    (0 != (flags & CONVERTTYPE.FORCECAST) ||
                     TypeManager.TypeContainsTyVars(typeSrc, null) ||
                     TypeManager.TypeContainsTyVars(typeDest, null)))
                {
                    grfex = EXPRFLAG.EXF_REFCHECK;
                }
                if (needsExprDest)
                {
                    binder.bindSimpleCast(exprSrc, exprTypeDest, out exprDest, grfex);
                }
                return(true);
            }
Exemple #3
0
        public ExprArrayIndex CreateArrayIndex(Expr pArray, Expr pIndex)
        {
            CType pType = pArray.Type;

            if (pType != null && pType.IsArrayType())
            {
                pType = pType.AsArrayType().GetElementType();
            }
            else if (pType == null)
            {
                pType = GetTypes().GetReqPredefAgg(PredefinedType.PT_INT).getThisType();
            }
            ExprArrayIndex pResult = new ExprArrayIndex(pType);

            pResult.Array = pArray;
            pResult.Index = pIndex;
            return(pResult);
        }
        public EXPRARRAYINDEX CreateArrayIndex(EXPR pArray, EXPR pIndex)
        {
            CType pType = pArray.type;

            if (pType != null && pType.IsArrayType())
            {
                pType = pType.AsArrayType().GetElementType();
            }
            else if (pType == null)
            {
                pType = GetTypes().GetReqPredefAgg(PredefinedType.PT_INT).getThisType();
            }
            EXPRARRAYINDEX pResult = new EXPRARRAYINDEX();

            pResult.kind  = ExpressionKind.EK_ARRAYINDEX;
            pResult.type  = pType;
            pResult.flags = 0;
            pResult.SetArray(pArray);
            pResult.SetIndex(pIndex);
            return(pResult);
        }
        ////////////////////////////////////////////////////////////////////////////////

        private bool ExactArrayInference(CType pSource, CType pDest)
        {
            // SPEC:  Otherwise, if U is an array CType UE[...] and V is an array CType VE[...]
            // SPEC:   of the same rank then an exact inference from UE to VE is made.
            if (!pSource.IsArrayType() || !pDest.IsArrayType())
            {
                return false;
            }
            ArrayType pArraySource = pSource.AsArrayType();
            ArrayType pArrayDest = pDest.AsArrayType();
            if (pArraySource.rank != pArrayDest.rank)
            {
                return false;
            }
            ExactInference(pArraySource.GetElementType(), pArrayDest.GetElementType());
            return true;
        }
Exemple #6
0
        private static Type CalculateAssociatedSystemType(CType src)
        {
            Type result = null;

            switch (src.GetTypeKind())
            {
            case TypeKind.TK_ArrayType:
                ArrayType a           = src.AsArrayType();
                Type      elementType = a.GetElementType().AssociatedSystemType;
                if (a.rank == 1)
                {
                    result = elementType.MakeArrayType();
                }
                else
                {
                    result = elementType.MakeArrayType(a.rank);
                }
                break;

            case TypeKind.TK_NullableType:
                NullableType n = src.AsNullableType();
                Type         underlyingType = n.GetUnderlyingType().AssociatedSystemType;
                result = typeof(Nullable <>).MakeGenericType(underlyingType);
                break;

            case TypeKind.TK_PointerType:
                PointerType p            = src.AsPointerType();
                Type        referentType = p.GetReferentType().AssociatedSystemType;
                result = referentType.MakePointerType();
                break;

            case TypeKind.TK_ParameterModifierType:
                ParameterModifierType r = src.AsParameterModifierType();
                Type parameterType      = r.GetParameterType().AssociatedSystemType;
                result = parameterType.MakeByRefType();
                break;

            case TypeKind.TK_AggregateType:
                result = CalculateAssociatedSystemTypeForAggregate(src.AsAggregateType());
                break;

            case TypeKind.TK_TypeParameterType:
                TypeParameterType t = src.AsTypeParameterType();
                Type parentType     = null;
                if (t.IsMethodTypeParameter())
                {
                    MethodInfo meth = t.GetOwningSymbol().AsMethodSymbol().AssociatedMemberInfo as MethodInfo;
                    result = meth.GetGenericArguments()[t.GetIndexInOwnParameters()];
                }
                else
                {
                    parentType = t.GetOwningSymbol().AsAggregateSymbol().AssociatedSystemType;
                    result     = parentType.GetTypeInfo().GenericTypeParameters[t.GetIndexInOwnParameters()];
                }
                break;

            case TypeKind.TK_ArgumentListType:
            case TypeKind.TK_BoundLambdaType:
            case TypeKind.TK_ErrorType:
            case TypeKind.TK_MethodGroupType:
            case TypeKind.TK_NaturalIntegerType:
            case TypeKind.TK_NullType:
            case TypeKind.TK_OpenTypePlaceholderType:
            case TypeKind.TK_UnboundLambdaType:
            case TypeKind.TK_VoidType:

            default:
                break;
            }

            Debug.Assert(result != null || src.GetTypeKind() == TypeKind.TK_AggregateType);
            return(result);
        }
Exemple #7
0
        private static Type CalculateAssociatedSystemType(CType src)
        {
            Type result = null;

            switch (src.GetTypeKind())
            {
                case TypeKind.TK_ArrayType:
                    ArrayType a = src.AsArrayType();
                    Type elementType = a.GetElementType().AssociatedSystemType;
                    if (a.rank == 1)
                    {
                        result = elementType.MakeArrayType();
                    }
                    else
                    {
                        result = elementType.MakeArrayType(a.rank);
                    }
                    break;

                case TypeKind.TK_NullableType:
                    NullableType n = src.AsNullableType();
                    Type underlyingType = n.GetUnderlyingType().AssociatedSystemType;
                    result = typeof(Nullable<>).MakeGenericType(underlyingType);
                    break;

                case TypeKind.TK_PointerType:
                    PointerType p = src.AsPointerType();
                    Type referentType = p.GetReferentType().AssociatedSystemType;
                    result = referentType.MakePointerType();
                    break;

                case TypeKind.TK_ParameterModifierType:
                    ParameterModifierType r = src.AsParameterModifierType();
                    Type parameterType = r.GetParameterType().AssociatedSystemType;
                    result = parameterType.MakeByRefType();
                    break;

                case TypeKind.TK_AggregateType:
                    result = CalculateAssociatedSystemTypeForAggregate(src.AsAggregateType());
                    break;

                case TypeKind.TK_TypeParameterType:
                    TypeParameterType t = src.AsTypeParameterType();
                    if (t.IsMethodTypeParameter())
                    {
                        MethodInfo meth = t.GetOwningSymbol().AsMethodSymbol().AssociatedMemberInfo as MethodInfo;
                        result = meth.GetGenericArguments()[t.GetIndexInOwnParameters()];
                    }
                    else
                    {
                        Type parentType = t.GetOwningSymbol().AsAggregateSymbol().AssociatedSystemType;
                        result = parentType.GetTypeInfo().GenericTypeParameters[t.GetIndexInOwnParameters()];
                    }
                    break;

                case TypeKind.TK_ArgumentListType:
                case TypeKind.TK_BoundLambdaType:
                case TypeKind.TK_ErrorType:
                case TypeKind.TK_MethodGroupType:
                case TypeKind.TK_NaturalIntegerType:
                case TypeKind.TK_NullType:
                case TypeKind.TK_OpenTypePlaceholderType:
                case TypeKind.TK_UnboundLambdaType:
                case TypeKind.TK_VoidType:

                default:
                    break;
            }

            Debug.Assert(result != null || src.GetTypeKind() == TypeKind.TK_AggregateType);
            return result;
        }
Exemple #8
0
        public bool SubstEqualTypesCore(CType typeDst, CType typeSrc, SubstContext pctx)
        {
        LRecurse:  // Label used for "tail" recursion.

            if (typeDst == typeSrc || typeDst.Equals(typeSrc))
            {
                return true;
            }

            switch (typeSrc.GetTypeKind())
            {
                default:
                    Debug.Assert(false, "Bad Symbol kind in SubstEqualTypesCore");
                    return false;

                case TypeKind.TK_NullType:
                case TypeKind.TK_VoidType:
                case TypeKind.TK_OpenTypePlaceholderType:
                    // There should only be a single instance of these.
                    Debug.Assert(typeDst.GetTypeKind() != typeSrc.GetTypeKind());
                    return false;

                case TypeKind.TK_ArrayType:
                    if (typeDst.GetTypeKind() != TypeKind.TK_ArrayType || typeDst.AsArrayType().rank != typeSrc.AsArrayType().rank)
                        return false;
                    goto LCheckBases;

                case TypeKind.TK_ParameterModifierType:
                    if (typeDst.GetTypeKind() != TypeKind.TK_ParameterModifierType ||
                        ((pctx.grfst & SubstTypeFlags.NoRefOutDifference) == 0 &&
                         typeDst.AsParameterModifierType().isOut != typeSrc.AsParameterModifierType().isOut))
                        return false;
                    goto LCheckBases;

                case TypeKind.TK_PointerType:
                case TypeKind.TK_NullableType:
                    if (typeDst.GetTypeKind() != typeSrc.GetTypeKind())
                        return false;
                    LCheckBases:
                    typeSrc = typeSrc.GetBaseOrParameterOrElementType();
                    typeDst = typeDst.GetBaseOrParameterOrElementType();
                    goto LRecurse;

                case TypeKind.TK_AggregateType:
                    if (typeDst.GetTypeKind() != TypeKind.TK_AggregateType)
                        return false;
                    { // BLOCK
                        AggregateType atsSrc = typeSrc.AsAggregateType();
                        AggregateType atsDst = typeDst.AsAggregateType();

                        if (atsSrc.getAggregate() != atsDst.getAggregate())
                            return false;

                        Debug.Assert(atsSrc.GetTypeArgsAll().Size == atsDst.GetTypeArgsAll().Size);

                        // All the args must unify.
                        for (int i = 0; i < atsSrc.GetTypeArgsAll().Size; i++)
                        {
                            if (!SubstEqualTypesCore(atsDst.GetTypeArgsAll().Item(i), atsSrc.GetTypeArgsAll().Item(i), pctx))
                                return false;
                        }
                    }
                    return true;

                case TypeKind.TK_ErrorType:
                    if (!typeDst.IsErrorType() || !typeSrc.AsErrorType().HasParent() || !typeDst.AsErrorType().HasParent())
                        return false;
                    {
                        ErrorType errSrc = typeSrc.AsErrorType();
                        ErrorType errDst = typeDst.AsErrorType();
                        Debug.Assert(errSrc.nameText != null && errSrc.typeArgs != null);
                        Debug.Assert(errDst.nameText != null && errDst.typeArgs != null);

                        if (errSrc.nameText != errDst.nameText || errSrc.typeArgs.Size != errDst.typeArgs.Size)
                            return false;

                        if (errSrc.HasTypeParent() != errDst.HasTypeParent())
                        {
                            return false;
                        }
                        if (errSrc.HasTypeParent())
                        {
                            if (errSrc.GetTypeParent() != errDst.GetTypeParent())
                            {
                                return false;
                            }
                            if (!SubstEqualTypesCore(errDst.GetTypeParent(), errSrc.GetTypeParent(), pctx))
                            {
                                return false;
                            }
                        }
                        else
                        {
                            if (errSrc.GetNSParent() != errDst.GetNSParent())
                            {
                                return false;
                            }
                        }

                        // All the args must unify.
                        for (int i = 0; i < errSrc.typeArgs.Size; i++)
                        {
                            if (!SubstEqualTypesCore(errDst.typeArgs.Item(i), errSrc.typeArgs.Item(i), pctx))
                                return false;
                        }
                    }
                    return true;

                case TypeKind.TK_TypeParameterType:
                    { // BLOCK
                        TypeParameterSymbol tvs = typeSrc.AsTypeParameterType().GetTypeParameterSymbol();
                        int index = tvs.GetIndexInTotalParameters();

                        if (tvs.IsMethodTypeParameter())
                        {
                            if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null)
                            {
                                // typeDst == typeSrc was handled above.
                                Debug.Assert(typeDst != typeSrc);
                                return false;
                            }
                            Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters());
                            Debug.Assert(pctx.prgtypeMeth == null || tvs.GetIndexInTotalParameters() < pctx.ctypeMeth);
                            if (index < pctx.ctypeMeth && pctx.prgtypeMeth != null)
                            {
                                return typeDst == pctx.prgtypeMeth[index];
                            }
                            if ((pctx.grfst & SubstTypeFlags.NormMeth) != 0)
                            {
                                return typeDst == GetStdMethTypeVar(index);
                            }
                        }
                        else
                        {
                            if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null)
                            {
                                // typeDst == typeSrc was handled above.
                                Debug.Assert(typeDst != typeSrc);
                                return false;
                            }
                            Debug.Assert(pctx.prgtypeCls == null || tvs.GetIndexInTotalParameters() < pctx.ctypeCls);
                            if (index < pctx.ctypeCls)
                                return typeDst == pctx.prgtypeCls[index];
                            if ((pctx.grfst & SubstTypeFlags.NormClass) != 0)
                                return typeDst == GetStdClsTypeVar(index);
                        }
                    }
                    return false;
            }
        }
Exemple #9
0
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        // RUNTIME BINDER ONLY CHANGE
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        internal bool GetBestAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, CType typeSrc, out CType typeDst)
        {
            // This method implements the "best accessible type" algorithm for determining the type
            // of untyped arguments in the runtime binder. It is also used in method type inference
            // to fix type arguments to types that are accessible.

            // The new type is returned in an out parameter. The result will be true (and the out param
            // non-null) only when the algorithm could find a suitable accessible type.

            Debug.Assert(semanticChecker != null);
            Debug.Assert(bindingContext != null);
            Debug.Assert(typeSrc != null);

            typeDst = null;

            if (semanticChecker.CheckTypeAccess(typeSrc, bindingContext.ContextForMemberLookup()))
            {
                // If we already have an accessible type, then use it. This is the terminal point of the recursion.
                typeDst = typeSrc;
                return true;
            }

            // These guys have no accessibility concerns.
            Debug.Assert(!typeSrc.IsVoidType() && !typeSrc.IsErrorType() && !typeSrc.IsTypeParameterType());

            if (typeSrc.IsParameterModifierType() || typeSrc.IsPointerType())
            {
                // We cannot vary these.
                return false;
            }

            CType intermediateType;
            if ((typeSrc.isInterfaceType() || typeSrc.isDelegateType()) && TryVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, typeSrc.AsAggregateType(), out intermediateType))
            {
                // If we have an interface or delegate type, then it can potentially be varied by its type arguments
                // to produce an accessible type, and if that's the case, then return that.
                // Example: IEnumerable<PrivateConcreteFoo> --> IEnumerable<PublicAbstractFoo>
                typeDst = intermediateType;

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
                return true;
            }

            if (typeSrc.IsArrayType() && TryArrayVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, typeSrc.AsArrayType(), out intermediateType))
            {
                // Similarly to the interface and delegate case, arrays are covariant in their element type and
                // so we can potentially produce an array type that is accessible.
                // Example: PrivateConcreteFoo[] --> PublicAbstractFoo[]
                typeDst = intermediateType;

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
                return true;
            }

            if (typeSrc.IsNullableType())
            {
                // We have an inaccessible nullable type, which means that the best we can do is System.ValueType.
                typeDst = this.GetOptPredefAgg(PredefinedType.PT_VALUE).getThisType();

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
                return true;
            }

            if (typeSrc.IsArrayType())
            {
                // We have an inaccessible array type for which we could not earlier find a better array type
                // with a covariant conversion, so the best we can do is System.Array.
                typeDst = this.GetReqPredefAgg(PredefinedType.PT_ARRAY).getThisType();

                Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup()));
                return true;
            }

            Debug.Assert(typeSrc.IsAggregateType());

            if (typeSrc.IsAggregateType())
            {
                // We have an AggregateType, so recurse on its base class.
                AggregateType aggType = typeSrc.AsAggregateType();
                AggregateType baseType = aggType.GetBaseClass();

                if (baseType == null)
                {
                    // This happens with interfaces, for instance. But in that case, the
                    // conversion to object does exist, is an implicit reference conversion,
                    // and so we will use it.
                    baseType = this.GetReqPredefAgg(PredefinedType.PT_OBJECT).getThisType();
                }

                return GetBestAccessibleType(semanticChecker, bindingContext, baseType, out typeDst);
            }

            return false;
        }
Exemple #10
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;
        }
Exemple #11
0
        private bool HasImplicitReferenceConversion(CType pSource, CType pDest)
        {
            Debug.Assert(pSource != null);
            Debug.Assert(pDest != null);

            // The implicit reference conversions are:
            // * From any reference type to Object.
            if (pSource.IsRefType() && pDest.isPredefType(PredefinedType.PT_OBJECT))
            {
                return(true);
            }
            // * From any class type S to any class type T provided S is derived from T.
            if (pSource.isClassType() && pDest.isClassType() && IsBaseClass(pSource, pDest))
            {
                return(true);
            }

            // ORIGINAL RULES:
            //    // * From any class type S to any interface type T provided S implements T.
            //    if (pSource.isClassType() && pDest.isInterfaceType() && IsBaseInterface(pSource, pDest))
            //    {
            //        return true;
            //    }
            //    // * from any interface type S to any interface type T, provided S is derived from T.
            //    if (pSource.isInterfaceType() && pDest.isInterfaceType() && IsBaseInterface(pSource, pDest))
            //    {
            //        return true;
            //    }

            // VARIANCE EXTENSIONS:
            // * From any class type S to any interface type T provided S implements an interface
            //   convertible to T.
            // * From any interface type S to any interface type T provided S implements an interface
            //   convertible to T.
            // * From any interface type S to any interface type T provided S is not T and S is
            //   an interface convertible to T.

            if (pSource.isClassType() && pDest.isInterfaceType() && HasAnyBaseInterfaceConversion(pSource, pDest))
            {
                return(true);
            }
            if (pSource.isInterfaceType() && pDest.isInterfaceType() && HasAnyBaseInterfaceConversion(pSource, pDest))
            {
                return(true);
            }
            if (pSource.isInterfaceType() && pDest.isInterfaceType() && pSource != pDest &&
                HasInterfaceConversion(pSource.AsAggregateType(), pDest.AsAggregateType()))
            {
                return(true);
            }

            // * From an array type S with an element type SE to an array type T with element type TE
            //   provided that 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 (pSource.IsArrayType() && pDest.IsArrayType() &&
                HasCovariantArrayConversion(pSource.AsArrayType(), pDest.AsArrayType()))
            {
                return(true);
            }
            // * From any array type to System.Array or any interface implemented by System.Array.
            if (pSource.IsArrayType() && (pDest.isPredefType(PredefinedType.PT_ARRAY) ||
                                          IsBaseInterface(GetReqPredefType(PredefinedType.PT_ARRAY, false), pDest)))
            {
                return(true);
            }
            // * From a single-dimensional array type S[] to IList<T> and its base
            //   interfaces, provided that there is an implicit identity or reference
            //   conversion from S to T.
            if (pSource.IsArrayType() && HasArrayConversionToInterface(pSource.AsArrayType(), pDest))
            {
                return(true);
            }

            // * From any delegate type to System.Delegate
            //
            // SPEC OMISSION:
            //
            // The spec should actually say
            //
            // * From any delegate type to System.Delegate
            // * From any delegate type to System.MulticastDelegate
            // * From any delegate type to any interface implemented by System.MulticastDelegate
            if (pSource.isDelegateType() &&
                (pDest.isPredefType(PredefinedType.PT_MULTIDEL) ||
                 pDest.isPredefType(PredefinedType.PT_DELEGATE) ||
                 IsBaseInterface(GetReqPredefType(PredefinedType.PT_MULTIDEL, false), pDest)))
            {
                return(true);
            }

            // VARIANCE EXTENSION:
            // * From any delegate type S to a delegate type T provided S is not T and
            //   S is a delegate convertible to T

            if (pSource.isDelegateType() && pDest.isDelegateType() &&
                HasDelegateConversion(pSource.AsAggregateType(), pDest.AsAggregateType()))
            {
                return(true);
            }

            // * From the null literal to any reference type
            // NOTE: We extend the specification here. The C# 3.0 spec does not describe
            // a "null type". Rather, it says that the null literal is typeless, and is
            // convertible to any reference or nullable type. However, the C# 2.0 and 3.0
            // implementations have a "null type" which some expressions other than the
            // null literal may have. (For example, (null??null), which is also an
            // extension to the specification.)
            if (pSource.IsNullType() && pDest.IsRefType())
            {
                return(true);
            }
            if (pSource.IsNullType() && pDest.IsNullableType())
            {
                return(true);
            }

            // * Implicit conversions involving type parameters that are known to be reference types.
            if (pSource.IsTypeParameterType() &&
                HasImplicitReferenceTypeParameterConversion(pSource.AsTypeParameterType(), pDest))
            {
                return(true);
            }

            return(false);
        }
            /*
             * BindExplicitConversion
             *
             * This is a complex routine with complex parameter. Generally, this should
             * be called through one of the helper methods that insulates you
             * from the complexity of the interface. This routine handles all the logic
             * associated with explicit conversions.
             *
             * Note that this function calls BindImplicitConversion first, so the main
             * logic is only concerned with conversions that can be made explicitly, but
             * not implicitly.
             */
            public bool Bind()
            {
                // To test for a standard conversion, call canConvert(exprSrc, typeDest, STANDARDANDCONVERTTYPE.NOUDC) and
                // canConvert(typeDest, typeSrc, STANDARDANDCONVERTTYPE.NOUDC).
                Debug.Assert((_flags & CONVERTTYPE.STANDARD) == 0);

                // 13.2 Explicit conversions
                //
                // The following conversions are classified as explicit conversions:
                //
                // * All implicit conversions
                // * Explicit numeric conversions
                // * Explicit enumeration conversions
                // * Explicit reference conversions
                // * Explicit interface conversions
                // * Unboxing conversions
                // * Explicit type parameter conversions
                // * User-defined explicit conversions
                // * Explicit nullable conversions
                // * Lifted user-defined explicit conversions
                //
                // Explicit conversions can occur in cast expressions (14.6.6).
                //
                // The explicit conversions that are not implicit conversions are conversions that cannot be
                // proven always to succeed, conversions that are known possibly to lose information, and
                // conversions across domains of types sufficiently different to merit explicit notation.

                // The set of explicit conversions includes all implicit conversions.

                // Don't try user-defined conversions now because we'll try them again later.
                if (_binder.BindImplicitConversion(_exprSrc, _typeSrc, _exprTypeDest, _pDestinationTypeForLambdaErrorReporting, _needsExprDest, out _exprDest, _flags | CONVERTTYPE.ISEXPLICIT))
                {
                    return(true);
                }

                if (_typeSrc == null || _typeDest == null || _typeSrc.IsErrorType() ||
                    _typeDest.IsErrorType() || _typeDest.IsNeverSameType())
                {
                    return(false);
                }

                if (_typeDest.IsNullableType())
                {
                    // This is handled completely by BindImplicitConversion.
                    return(false);
                }

                if (_typeSrc.IsNullableType())
                {
                    return(bindExplicitConversionFromNub());
                }

                if (bindExplicitConversionFromArrayToIList())
                {
                    return(true);
                }

                // if we were casting an integral constant to another constant type,
                // then, if the constant were in range, then the above call would have succeeded.

                // But it failed, and so we know that the constant is not in range

                switch (_typeDest.GetTypeKind())
                {
                default:
                    VSFAIL("Bad type kind");
                    return(false);

                case TypeKind.TK_VoidType:
                    return(false);    // Can't convert to a method group or anon method.

                case TypeKind.TK_NullType:
                    return(false);     // Can never convert TO the null type.

                case TypeKind.TK_TypeParameterType:
                    if (bindExplicitConversionToTypeVar())
                    {
                        return(true);
                    }
                    break;

                case TypeKind.TK_ArrayType:
                    if (bindExplicitConversionToArray(_typeDest.AsArrayType()))
                    {
                        return(true);
                    }
                    break;

                case TypeKind.TK_PointerType:
                    if (bindExplicitConversionToPointer())
                    {
                        return(true);
                    }
                    break;

                case TypeKind.TK_AggregateType:
                {
                    AggCastResult result = bindExplicitConversionToAggregate(_typeDest.AsAggregateType());

                    if (result == AggCastResult.Success)
                    {
                        return(true);
                    }
                    if (result == AggCastResult.Abort)
                    {
                        return(false);
                    }
                    break;
                }
                }

                // No built-in conversion was found. Maybe a user-defined conversion?
                if (0 == (_flags & CONVERTTYPE.NOUDC))
                {
                    return(_binder.bindUserDefinedConversion(_exprSrc, _typeSrc, _typeDest, _needsExprDest, out _exprDest, false));
                }
                return(false);
            }
Exemple #13
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);
        }
Exemple #14
0
        public bool HasImplicitReferenceConversion(CType pSource, CType pDest)
        {
            Debug.Assert(pSource != null);
            Debug.Assert(pDest != null);

            // The implicit reference conversions are:
            // * From any reference type to Object.
            if (pSource.IsRefType() && pDest.isPredefType(PredefinedType.PT_OBJECT))
            {
                return true;
            }
            // * From any class type S to any class type T provided S is derived from T.
            if (pSource.isClassType() && pDest.isClassType() && IsBaseClass(pSource, pDest))
            {
                return true;
            }

            // ORIGINAL RULES:
            //    // * From any class type S to any interface type T provided S implements T.
            //    if (pSource.isClassType() && pDest.isInterfaceType() && IsBaseInterface(pSource, pDest))
            //    {
            //        return true;
            //    }
            //    // * from any interface type S to any interface type T, provided S is derived from T.
            //    if (pSource.isInterfaceType() && pDest.isInterfaceType() && IsBaseInterface(pSource, pDest))
            //    {
            //        return true;
            //    }

            // VARIANCE EXTENSIONS:
            // * From any class type S to any interface type T provided S implements an interface
            //   convertible to T.
            // * From any interface type S to any interface type T provided S implements an interface
            //   convertible to T.
            // * From any interface type S to any interface type T provided S is not T and S is 
            //   an interface convertible to T.

            if (pSource.isClassType() && pDest.isInterfaceType() && HasAnyBaseInterfaceConversion(pSource, pDest))
            {
                return true;
            }
            if (pSource.isInterfaceType() && pDest.isInterfaceType() && HasAnyBaseInterfaceConversion(pSource, pDest))
            {
                return true;
            }
            if (pSource.isInterfaceType() && pDest.isInterfaceType() && pSource != pDest &&
                HasInterfaceConversion(pSource.AsAggregateType(), pDest.AsAggregateType()))
            {
                return true;
            }

            // * From an array type S with an element type SE to an array type T with element type TE
            //   provided that 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 (pSource.IsArrayType() && pDest.IsArrayType() &&
                HasCovariantArrayConversion(pSource.AsArrayType(), pDest.AsArrayType()))
            {
                return true;
            }
            // * From any array type to System.Array or any interface implemented by System.Array.
            if (pSource.IsArrayType() && (pDest.isPredefType(PredefinedType.PT_ARRAY) ||
                IsBaseInterface(GetReqPredefType(PredefinedType.PT_ARRAY, false), pDest)))
            {
                return true;
            }
            // * From a single-dimensional array type S[] to IList<T> and its base
            //   interfaces, provided that there is an implicit identity or reference
            //   conversion from S to T.
            if (pSource.IsArrayType() && HasArrayConversionToInterface(pSource.AsArrayType(), pDest))
            {
                return true;
            }

            // * From any delegate type to System.Delegate
            // 
            // SPEC OMISSION:
            // 
            // The spec should actually say
            //
            // * From any delegate type to System.Delegate 
            // * From any delegate type to System.MulticastDelegate
            // * From any delegate type to any interface implemented by System.MulticastDelegate
            if (pSource.isDelegateType() &&
                (pDest.isPredefType(PredefinedType.PT_MULTIDEL) ||
                pDest.isPredefType(PredefinedType.PT_DELEGATE) ||
                IsBaseInterface(GetReqPredefType(PredefinedType.PT_MULTIDEL, false), pDest)))
            {
                return true;
            }

            // VARIANCE EXTENSION:
            // * From any delegate type S to a delegate type T provided S is not T and
            //   S is a delegate convertible to T

            if (pSource.isDelegateType() && pDest.isDelegateType() &&
                HasDelegateConversion(pSource.AsAggregateType(), pDest.AsAggregateType()))
            {
                return true;
            }

            // * From the null literal to any reference type
            // NOTE: We extend the specification here. The C# 3.0 spec does not describe
            // a "null type". Rather, it says that the null literal is typeless, and is
            // convertible to any reference or nullable type. However, the C# 2.0 and 3.0
            // implementations have a "null type" which some expressions other than the
            // null literal may have. (For example, (null??null), which is also an
            // extension to the specification.)
            if (pSource.IsNullType() && pDest.IsRefType())
            {
                return true;
            }
            if (pSource.IsNullType() && pDest.IsNullableType())
            {
                return true;
            }

            // * Implicit conversions involving type parameters that are known to be reference types.
            if (pSource.IsTypeParameterType() &&
                HasImplicitReferenceTypeParameterConversion(pSource.AsTypeParameterType(), pDest))
            {
                return true;
            }

            return false;
        }
Exemple #15
0
        ////////////////////////////////////////////////////////////////////////////////

        private bool LowerBoundArrayInference(CType pSource, CType pDest)
        {
            // SPEC:  Otherwise, if U is an array CType Ue[...] and V is either an array
            // SPEC:   CType Ve[...] of the same rank, or if U is a one-dimensional array
            // SPEC:   CType Ue[] and V is one of IEnumerable<Ve>, ICollection<Ve>, 
            // SPEC:   IList<Ve>, IReadOnlyCollection<Ve> or IReadOnlyList<Ve> then
            // SPEC:    if Ue is known to be a reference CType then a lower-bound inference
            // SPEC:     from Ue to Ve is made.
            // SPEC:    otherwise an exact inference from Ue to Ve is made.

            // Consider the following:
            //
            // abstract class B<T> { public abstract M<U>(U u) : where U : T; }
            // class D : B<int[]> {
            //   static void M<X>(X[] x) { }
            //   public override M<U>(U u) { M(u); } // should infer M<int>
            // }

            if (pSource.IsTypeParameterType())
            {
                pSource = pSource.AsTypeParameterType().GetEffectiveBaseClass();
            }

            if (!pSource.IsArrayType())
            {
                return false;
            }
            ArrayType pArraySource = pSource.AsArrayType();
            CType pElementSource = pArraySource.GetElementType();
            CType pElementDest = null;

            if (pDest.IsArrayType())
            {
                ArrayType pArrayDest = pDest.AsArrayType();
                if (pArrayDest.rank != pArraySource.rank)
                {
                    return false;
                }
                pElementDest = pArrayDest.GetElementType();
            }
            else if (pDest.isPredefType(PredefinedType.PT_G_IENUMERABLE) ||
                pDest.isPredefType(PredefinedType.PT_G_ICOLLECTION) ||
                pDest.isPredefType(PredefinedType.PT_G_ILIST) ||
                pDest.isPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION) ||
                pDest.isPredefType(PredefinedType.PT_G_IREADONLYLIST))
            {
                if (pArraySource.rank != 1)
                {
                    return false;
                }
                AggregateType pAggregateDest = pDest.AsAggregateType();
                pElementDest = pAggregateDest.GetTypeArgsThis().Item(0);
            }
            else
            {
                return false;
            }

            if (pElementSource.IsRefType())
            {
                LowerBoundInference(pElementSource, pElementDest);
            }
            else
            {
                ExactInference(pElementSource, pElementDest);
            }
            return true;
        }
Exemple #16
0
        private CType SubstTypeCore(CType type, SubstContext pctx)
        {
            CType typeSrc;
            CType typeDst;

            switch (type.GetTypeKind())
            {
                default:
                    Debug.Assert(false);
                    return type;

                case TypeKind.TK_NullType:
                case TypeKind.TK_VoidType:
                case TypeKind.TK_OpenTypePlaceholderType:
                case TypeKind.TK_MethodGroupType:
                case TypeKind.TK_BoundLambdaType:
                case TypeKind.TK_UnboundLambdaType:
                case TypeKind.TK_NaturalIntegerType:
                case TypeKind.TK_ArgumentListType:
                    return type;

                case TypeKind.TK_ParameterModifierType:
                    typeDst = SubstTypeCore(typeSrc = type.AsParameterModifierType().GetParameterType(), pctx);
                    return (typeDst == typeSrc) ? type : GetParameterModifier(typeDst, type.AsParameterModifierType().isOut);

                case TypeKind.TK_ArrayType:
                    typeDst = SubstTypeCore(typeSrc = type.AsArrayType().GetElementType(), pctx);
                    return (typeDst == typeSrc) ? type : GetArray(typeDst, type.AsArrayType().rank);

                case TypeKind.TK_PointerType:
                    typeDst = SubstTypeCore(typeSrc = type.AsPointerType().GetReferentType(), pctx);
                    return (typeDst == typeSrc) ? type : GetPointer(typeDst);

                case TypeKind.TK_NullableType:
                    typeDst = SubstTypeCore(typeSrc = type.AsNullableType().GetUnderlyingType(), pctx);
                    return (typeDst == typeSrc) ? type : GetNullable(typeDst);

                case TypeKind.TK_AggregateType:
                    if (type.AsAggregateType().GetTypeArgsAll().size > 0)
                    {
                        AggregateType ats = type.AsAggregateType();

                        TypeArray typeArgs = SubstTypeArray(ats.GetTypeArgsAll(), pctx);
                        if (ats.GetTypeArgsAll() != typeArgs)
                            return GetAggregate(ats.getAggregate(), typeArgs);
                    }
                    return type;

                case TypeKind.TK_ErrorType:
                    if (type.AsErrorType().HasParent())
                    {
                        ErrorType err = type.AsErrorType();
                        Debug.Assert(err.nameText != null && err.typeArgs != null);

                        CType pParentType = null;
                        if (err.HasTypeParent())
                        {
                            pParentType = SubstTypeCore(err.GetTypeParent(), pctx);
                        }

                        TypeArray typeArgs = SubstTypeArray(err.typeArgs, pctx);
                        if (typeArgs != err.typeArgs || (err.HasTypeParent() && pParentType != err.GetTypeParent()))
                        {
                            return GetErrorType(pParentType, err.GetNSParent(), err.nameText, typeArgs);
                        }
                    }
                    return type;

                case TypeKind.TK_TypeParameterType:
                    {
                        TypeParameterSymbol tvs = type.AsTypeParameterType().GetTypeParameterSymbol();
                        int index = tvs.GetIndexInTotalParameters();
                        if (tvs.IsMethodTypeParameter())
                        {
                            if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null)
                                return type;
                            Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters());
                            if (index < pctx.ctypeMeth)
                            {
                                Debug.Assert(pctx.prgtypeMeth != null);
                                return pctx.prgtypeMeth[index];
                            }
                            else
                            {
                                return ((pctx.grfst & SubstTypeFlags.NormMeth) != 0 ? GetStdMethTypeVar(index) : type);
                            }
                        }
                        if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null)
                            return type;
                        return index < pctx.ctypeCls ? pctx.prgtypeCls[index] :
                               ((pctx.grfst & SubstTypeFlags.NormClass) != 0 ? GetStdClsTypeVar(index) : type);
                    }
            }
        }
Exemple #17
0
        ////////////////////////////////////////////////////////////////////////////////

        private bool UpperBoundArrayInference(CType pSource, CType pDest)
        {
            // SPEC:  Otherwise, if V is an array CType Ve[...] and U is an array
            // SPEC:   CType Ue[...] of the same rank, or if V is a one-dimensional array
            // SPEC:   CType Ve[] and U is one of IEnumerable<Ue>, ICollection<Ue>,
            // SPEC:   IList<Ue>, IReadOnlyCollection<Ue> or IReadOnlyList<Ue> then
            // SPEC:    if Ue is known to be a reference CType then an upper-bound inference
            // SPEC:     from Ue to Ve is made.
            // SPEC:    otherwise an exact inference from Ue to Ve is made.

            if (!pDest.IsArrayType())
            {
                return false;
            }
            ArrayType pArrayDest = pDest.AsArrayType();
            CType pElementDest = pArrayDest.GetElementType();
            CType pElementSource = null;

            if (pSource.IsArrayType())
            {
                ArrayType pArraySource = pSource.AsArrayType();
                if (pArrayDest.rank != pArraySource.rank)
                {
                    return false;
                }
                pElementSource = pArraySource.GetElementType();
            }
            else if (pSource.isPredefType(PredefinedType.PT_G_IENUMERABLE) ||
                pSource.isPredefType(PredefinedType.PT_G_ICOLLECTION) ||
                pSource.isPredefType(PredefinedType.PT_G_ILIST) ||
                pSource.isPredefType(PredefinedType.PT_G_IREADONLYLIST) ||
                pSource.isPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION))
            {
                if (pArrayDest.rank != 1)
                {
                    return false;
                }
                AggregateType pAggregateSource = pSource.AsAggregateType();
                pElementSource = pAggregateSource.GetTypeArgsThis().Item(0);
            }
            else
            {
                return false;
            }

            if (pElementSource.IsRefType())
            {
                UpperBoundInference(pElementSource, pElementDest);
            }
            else
            {
                ExactInference(pElementSource, pElementDest);
            }
            return true;
        }
Exemple #18
0
        public void ErrAppendType(CType pType, SubstContext pctx, bool fArgs)
        {
            if (pctx != null)
            {
                if (!pctx.FNop())
                {
                    pType = GetTypeManager().SubstType(pType, pctx);
                }
                // We shouldn't use the SubstContext again so set it to NULL.
                pctx = null;
            }

            switch (pType.GetTypeKind())
            {
                case TypeKind.TK_AggregateType:
                    {
                        AggregateType pAggType = pType.AsAggregateType();

                        // Check for a predefined class with a special "nice" name for
                        // error reported.
                        string text = PredefinedTypes.GetNiceName(pAggType.getAggregate());
                        if (text != null)
                        {
                            // Found a nice name.
                            ErrAppendString(text);
                        }
                        else if (pAggType.getAggregate().IsAnonymousType())
                        {
                            ErrAppendPrintf("AnonymousType#{0}", GetTypeID(pAggType));
                            break;
                        }
                        else
                        {
                            if (pAggType.outerType != null)
                            {
                                ErrAppendType(pAggType.outerType, pctx);
                                ErrAppendChar('.');
                            }
                            else
                            {
                                // In a namespace.
                                ErrAppendParentSym(pAggType.getAggregate(), pctx);
                            }
                            ErrAppendName(pAggType.getAggregate().name);
                        }
                        ErrAppendTypeParameters(pAggType.GetTypeArgsThis(), pctx, true);
                        break;
                    }

                case TypeKind.TK_TypeParameterType:
                    if (null == pType.GetName())
                    {
                        // It's a standard type variable.
                        if (pType.AsTypeParameterType().IsMethodTypeParameter())
                        {
                            ErrAppendChar('!');
                        }
                        ErrAppendChar('!');
                        ErrAppendPrintf("{0}", pType.AsTypeParameterType().GetIndexInTotalParameters());
                    }
                    else
                    {
                        ErrAppendName(pType.GetName());
                    }
                    break;

                case TypeKind.TK_ErrorType:
                    if (pType.AsErrorType().HasParent())
                    {
                        Debug.Assert(pType.AsErrorType().nameText != null && pType.AsErrorType().typeArgs != null);
                        ErrAppendParentType(pType, pctx);
                        ErrAppendName(pType.AsErrorType().nameText);
                        ErrAppendTypeParameters(pType.AsErrorType().typeArgs, pctx, true);
                    }
                    else
                    {
                        // Load the string "<error>".
                        Debug.Assert(null == pType.AsErrorType().typeArgs);
                        ErrAppendId(MessageID.ERRORSYM);
                    }
                    break;

                case TypeKind.TK_NullType:
                    // Load the string "<null>".
                    ErrAppendId(MessageID.NULL);
                    break;

                case TypeKind.TK_OpenTypePlaceholderType:
                    // Leave blank.
                    break;

                case TypeKind.TK_BoundLambdaType:
                    ErrAppendId(MessageID.AnonMethod);
                    break;

                case TypeKind.TK_UnboundLambdaType:
                    ErrAppendId(MessageID.Lambda);
                    break;

                case TypeKind.TK_MethodGroupType:
                    ErrAppendId(MessageID.MethodGroup);
                    break;

                case TypeKind.TK_ArgumentListType:
                    ErrAppendString(TokenFacts.GetText(TokenKind.ArgList));
                    break;

                case TypeKind.TK_ArrayType:
                    {
                        CType elementType = pType.AsArrayType().GetBaseElementType();
                        int rank;

                        if (null == elementType)
                        {
                            Debug.Assert(false, "No element type");
                            break;
                        }

                        ErrAppendType(elementType, pctx);

                        for (elementType = pType;
                                elementType != null && elementType.IsArrayType();
                                elementType = elementType.AsArrayType().GetElementType())
                        {
                            rank = elementType.AsArrayType().rank;

                            // Add [] with (rank-1) commas inside
                            ErrAppendChar('[');

#if ! CSEE
                            // known rank.
                            if (rank > 1)
                            {
                                ErrAppendChar('*');
                            }
#endif

                            for (int i = rank; i > 1; --i)
                            {
                                ErrAppendChar(',');
#if ! CSEE

                                ErrAppendChar('*');
#endif
                            }

                            ErrAppendChar(']');
                        }
                        break;
                    }

                case TypeKind.TK_VoidType:
                    ErrAppendName(GetNameManager().Lookup(TokenFacts.GetText(TokenKind.Void)));
                    break;

                case TypeKind.TK_ParameterModifierType:
                    // add ref or out
                    ErrAppendString(pType.AsParameterModifierType().isOut ? "out " : "ref ");

                    // add base type name
                    ErrAppendType(pType.AsParameterModifierType().GetParameterType(), pctx);
                    break;

                case TypeKind.TK_PointerType:
                    // Generate the base type.
                    ErrAppendType(pType.AsPointerType().GetReferentType(), pctx);
                    {
                        // add the trailing *
                        ErrAppendChar('*');
                    }
                    break;

                case TypeKind.TK_NullableType:
                    ErrAppendType(pType.AsNullableType().GetUnderlyingType(), pctx);
                    ErrAppendChar('?');
                    break;

                case TypeKind.TK_NaturalIntegerType:
                default:
                    // Shouldn't happen.
                    Debug.Assert(false, "Bad type kind");
                    break;
            }
        }