public bool DependsOn(TypeParameterType pType)
        {
            Debug.Assert(pType != null);

            // * If a type parameter T is used as a constraint for type parameter S
            //   then S depends on T.
            // * If a type parameter S depends on a type parameter T and T depends on
            //   U then S depends on U.

            TypeArray pConstraints = GetBounds();
            for (int iConstraint = 0; iConstraint < pConstraints.size; ++iConstraint)
            {
                CType pConstraint = pConstraints.Item(iConstraint);
                if (pConstraint == pType)
                {
                    return true;
                }
                if (pConstraint.IsTypeParameterType() &&
                    pConstraint.AsTypeParameterType().DependsOn(pType))
                {
                    return true;
                }
            }
            return false;
        }
Exemple #2
0
        public TypeArray typeVars;          // All the type variables for a generic method, as declarations.

        // If there is a type variable in the method which is used in no parameter,
        // then inference must fail. Since this is expensive to check, we cache
        // the result of the first call.

        public bool InferenceMustFail()
        {
            if (_checkedInfMustFail)
            {
                return(_inferenceMustFail);
            }
            Debug.Assert(!_inferenceMustFail);
            _checkedInfMustFail = true;
            for (int ivar = 0; ivar < typeVars.Size; ivar++)
            {
                TypeParameterType var = typeVars.ItemAsTypeParameterType(ivar);
                // See if type var is used in a parameter.
                for (int ipar = 0; ; ipar++)
                {
                    if (ipar >= Params.Size)
                    {
                        // This type variable is not in any parameter.
                        _inferenceMustFail = true;
                        return(true);
                    }
                    if (TypeManager.TypeContainsType(Params.Item(ipar), var))
                    {
                        break;
                    }
                }
            }
            // All type variables are used in a parameter.
            return(false);
        }
        //////////////////////////////////////////////////////////////////////////////

        private static bool HasVariantConversion(AggregateType pSource, AggregateType pDest)
        {
            Debug.Assert(pSource != null);
            Debug.Assert(pDest != null);
            if (pSource == pDest)
            {
                return(true);
            }

            AggregateSymbol pAggSym = pSource.OwningAggregate;

            if (pAggSym != pDest.OwningAggregate)
            {
                return(false);
            }

            TypeArray pTypeParams = pAggSym.GetTypeVarsAll();
            TypeArray pSourceArgs = pSource.TypeArgsAll;
            TypeArray pDestArgs   = pDest.TypeArgsAll;

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

            for (int iParam = 0; iParam < pTypeParams.Count; ++iParam)
            {
                CType pSourceArg = pSourceArgs[iParam];
                CType pDestArg   = pDestArgs[iParam];
                // If they're identical then this one is automatically good, so skip it.
                if (pSourceArg == pDestArg)
                {
                    continue;
                }
                TypeParameterType pParam = (TypeParameterType)pTypeParams[iParam];
                if (pParam.Invariant)
                {
                    return(false);
                }
                if (pParam.Covariant)
                {
                    if (!HasImplicitReferenceConversion(pSourceArg, pDestArg))
                    {
                        return(false);
                    }
                }
                if (pParam.Contravariant)
                {
                    if (!HasImplicitReferenceConversion(pDestArg, pSourceArg))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
Exemple #4
0
        public TypeArray GetStdMethTyVarArray(int cTyVars)
        {
            TypeParameterType[] prgvar = new TypeParameterType[cTyVars];

            for (int ivar = 0; ivar < cTyVars; ivar++)
            {
                prgvar[ivar] = GetStdMethTypeVar(ivar);
            }

            return(_BSymmgr.AllocParams(cTyVars, (CType[])prgvar));
        }
Exemple #5
0
        public static bool HasGenericDelegateExplicitReferenceConversion(CType pSource, AggregateType pTarget)
        {
            if (!(pSource is AggregateType aggSrc) ||
                !aggSrc.IsDelegateType ||
                !pTarget.IsDelegateType ||
                aggSrc.OwningAggregate != pTarget.OwningAggregate ||
                SymbolLoader.HasIdentityOrImplicitReferenceConversion(aggSrc, pTarget))
            {
                return(false);
            }

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

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

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

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

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

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

            return(true);
        }
Exemple #6
0
        //////////////////////////////////////////////////////////////////////////////

        bool HasVariantConversion(AggregateType pSource, AggregateType pDest)
        {
            Debug.Assert(pSource != null);
            Debug.Assert(pDest != null);
            if (pSource == pDest)
            {
                return(true);
            }
            AggregateSymbol pAggSym = pSource.getAggregate();

            if (pAggSym != pDest.getAggregate())
            {
                return(false);
            }

            TypeArray pTypeParams = pAggSym.GetTypeVarsAll();
            TypeArray pSourceArgs = pSource.GetTypeArgsAll();
            TypeArray pDestArgs   = pDest.GetTypeArgsAll();

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

            for (int iParam = 0; iParam < pTypeParams.size; ++iParam)
            {
                CType pSourceArg = pSourceArgs.Item(iParam);
                CType pDestArg   = pDestArgs.Item(iParam);
                // If they're identical then this one is automatically good, so skip it.
                if (pSourceArg == pDestArg)
                {
                    continue;
                }
                TypeParameterType pParam = pTypeParams.Item(iParam).AsTypeParameterType();
                if (pParam.Invariant)
                {
                    return(false);
                }
                if (pParam.Covariant)
                {
                    if (!HasImplicitReferenceConversion(pSourceArg, pDestArg))
                    {
                        return(false);
                    }
                }
                if (pParam.Contravariant)
                {
                    if (!HasImplicitReferenceConversion(pDestArg, pSourceArg))
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
Exemple #7
0
        // TypeParameter
        public TypeParameterType CreateTypeParameter(TypeParameterSymbol pSymbol)
        {
            TypeParameterType type = new TypeParameterType();

            type.SetTypeParameterSymbol(pSymbol);
            type.SetName(pSymbol.name);
            Debug.Assert(pSymbol.GetTypeParameterType() == null);
            pSymbol.SetTypeParameterType(type);

            type.SetTypeKind(TypeKind.TK_TypeParameterType);
            return(type);
        }
        private static IEnumerable <AggregateType> AllPossibleInterfaces(TypeParameterType type)
        {
            foreach (AggregateType t in type.GetEffectiveBaseClass().TypeAndBaseClassInterfaces())
            {
                yield return(t);
            }

            foreach (AggregateType t in type.GetInterfaceBounds().AllConstraintInterfaces())
            {
                yield return(t);
            }
        }
Exemple #9
0
        private static Type CalculateAssociatedSystemType(CType src)
        {
            Type result = null;

            switch (src.GetTypeKind())
            {
            case TypeKind.TK_ArrayType:
                ArrayType a           = (ArrayType)src;
                Type      elementType = a.GetElementType().AssociatedSystemType;
                result = a.IsSZArray ? elementType.MakeArrayType() : elementType.MakeArrayType(a.rank);
                break;

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

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

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

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

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

            Debug.Assert(result != null || src.GetTypeKind() == TypeKind.TK_AggregateType);
            return(result);
        }
Exemple #10
0
        // TypeParameter
        public TypeParameterType CreateTypeParameter(TypeParameterSymbol pSymbol)
        {
            TypeParameterType type = new TypeParameterType();

            type.SetTypeParameterSymbol(pSymbol);
            type.SetUnresolved(pSymbol.parent != null && pSymbol.parent.IsAggregateSymbol() && pSymbol.parent.AsAggregateSymbol().IsUnresolved());
            type.SetName(pSymbol.name);
            Debug.Assert(pSymbol.GetTypeParameterType() == null);
            pSymbol.SetTypeParameterType(type);

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

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

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

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

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

                if (pParam.Covariant)
                {
                    if (!FExpRefConv(loader, pSourceArg, pTargetArg))
                    {
                        return(false);
                    }
                }
                else if (pParam.Contravariant)
                {
                    if (!pSourceArg.IsRefType() || !pTargetArg.IsRefType())
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
Exemple #12
0
 public static bool ParametersContainTyVar(TypeArray @params, TypeParameterType typeFind)
 {
     Debug.Assert(@params != null);
     Debug.Assert(typeFind != null);
     for (int p = 0; p < @params.Count; p++)
     {
         CType sym = @params[p];
         if (TypeContainsType(sym, typeFind))
         {
             return(true);
         }
     }
     return(false);
 }
Exemple #13
0
        public TypeParameterType GetTypeParameter(TypeParameterSymbol pSymbol)
        {
            // These guys should be singletons for each.

            TypeParameterType pTypeParameter = _typeTable.LookupTypeParameter(pSymbol);

            if (pTypeParameter == null)
            {
                pTypeParameter = _typeFactory.CreateTypeParameter(pSymbol);
                _typeTable.InsertTypeParameter(pSymbol, pTypeParameter);
            }

            return(pTypeParameter);
        }
Exemple #14
0
        private bool HasImplicitReferenceTypeParameterConversion(
            TypeParameterType pSource, CType pDest)
        {
            Debug.Assert(pSource != null);
            Debug.Assert(pDest != null);

            if (!pSource.IsRefType())
            {
                // Not a reference conversion.
                return(false);
            }

            // The following implicit conversions exist for a given type parameter T:
            //
            // * From T to its effective base class C.
            AggregateType pEBC = pSource.GetEffectiveBaseClass();

            if (pDest == pEBC)
            {
                return(true);
            }
            // * From T to any base class of C.
            if (IsBaseClass(pEBC, pDest))
            {
                return(true);
            }
            // * From T to any interface implemented by C.
            if (IsBaseInterface(pEBC, pDest))
            {
                return(true);
            }
            // * From T to any interface type I in T's effective interface set, and
            //   from T to any base interface of I.
            TypeArray pInterfaces = pSource.GetInterfaceBounds();

            for (int i = 0; i < pInterfaces.Count; ++i)
            {
                if (pInterfaces[i] == pDest)
                {
                    return(true);
                }
            }
            // * From T to a type parameter U, provided T depends on U.
            if (pDest.IsTypeParameterType() && pSource.DependsOn(pDest.AsTypeParameterType()))
            {
                return(true);
            }
            return(false);
        }
Exemple #15
0
        private bool HasImplicitBoxingTypeParameterConversion(
            TypeParameterType pSource, CType pDest)
        {
            Debug.Assert(pSource != null);
            Debug.Assert(pDest != null);

            if (pSource.IsRefType())
            {
                // Not a boxing conversion; both source and destination are references.
                return(false);
            }

            // The following implicit conversions exist for a given type parameter T:
            //
            // * From T to its effective base class C.
            AggregateType pEBC = pSource.GetEffectiveBaseClass();

            if (pDest == pEBC)
            {
                return(true);
            }
            // * From T to any base class of C.
            if (IsBaseClass(pEBC, pDest))
            {
                return(true);
            }
            // * From T to any interface implemented by C.
            if (IsBaseInterface(pEBC, pDest))
            {
                return(true);
            }
            // * From T to any interface type I in T's effective interface set, and
            //   from T to any base interface of I.
            TypeArray pInterfaces = pSource.GetInterfaceBounds();

            for (int i = 0; i < pInterfaces.Count; ++i)
            {
                if (pInterfaces[i] == pDest)
                {
                    return(true);
                }
            }
            // * The conversion from T to a type parameter U, provided T depends on U, is not
            //   classified as a boxing conversion because it is not guaranteed to box.
            //   (If both T and U are value types then it is an identity conversion.)

            return(false);
        }
Exemple #16
0
        private bool HasImplicitTypeParameterBaseConversion(
            TypeParameterType pSource, CType pDest)
        {
            Debug.Assert(pSource != null);
            Debug.Assert(pDest != null);

            if (HasImplicitReferenceTypeParameterConversion(pSource, pDest))
            {
                return(true);
            }
            if (HasImplicitBoxingTypeParameterConversion(pSource, pDest))
            {
                return(true);
            }

            return(pDest is TypeParameterType typeParamDest && pSource.DependsOn(typeParamDest));
        }
Exemple #17
0
        ////////////////////////////////////////////////////////////////////////////////
        // Check whether typeArgs satisfies the constraints of typeVars. The
        // typeArgsCls and typeArgsMeth are used for substitution on the bounds. The
        // tree and symErr are used for error reporting.

        private static bool CheckConstraintsCore(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeArray typeVars, TypeArray typeArgs, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
        {
            Debug.Assert(typeVars.Count == typeArgs.Count);
            Debug.Assert(typeVars.Count > 0);
            Debug.Assert(flags == CheckConstraintsFlags.None || flags == CheckConstraintsFlags.NoErrors);

            bool fError = false;

            for (int i = 0; i < typeVars.Count; i++)
            {
                // Empty bounds should be set to object.
                TypeParameterType var = (TypeParameterType)typeVars[i];
                CType             arg = typeArgs[i];

                bool fOK = CheckSingleConstraint(checker, errHandling, symErr, var, arg, typeArgsCls, typeArgsMeth, flags);
                fError |= !fOK;
            }

            return(!fError);
        }
        ////////////////////////////////////////////////////////////////////////////////
        // Check whether typeArgs satisfies the constraints of typeVars. The
        // typeArgsCls and typeArgsMeth are used for substitution on the bounds. The
        // tree and symErr are used for error reporting.
        private static bool CheckConstraintsCore(Symbol symErr, TypeArray typeVars, TypeArray typeArgs, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
        {
            Debug.Assert(typeVars.Count == typeArgs.Count);
            Debug.Assert(typeVars.Count > 0);
            Debug.Assert(flags == CheckConstraintsFlags.None || flags == CheckConstraintsFlags.NoErrors);

            for (int i = 0; i < typeVars.Count; i++)
            {
                // Empty bounds should be set to object.
                TypeParameterType var = (TypeParameterType)typeVars[i];
                CType             arg = typeArgs[i];

                if (!CheckSingleConstraint(symErr, var, arg, typeArgsCls, typeArgsMeth, flags))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemple #19
0
        // TypeParameter
        public TypeParameterType CreateTypeParameter(TypeParameterSymbol pSymbol)
        {
            TypeParameterType type = new TypeParameterType();
            type.SetTypeParameterSymbol(pSymbol);
            type.SetUnresolved(pSymbol.parent != null && pSymbol.parent.IsAggregateSymbol() && pSymbol.parent.AsAggregateSymbol().IsUnresolved());
            type.SetName(pSymbol.name);

#if CSEE
            type.typeRes = type;
            if (!type.IsUnresolved())
            {
                type.tsRes = ktsImportMax;
            }
#endif // CSEE

            Debug.Assert(pSymbol.GetTypeParameterType() == null);
            pSymbol.SetTypeParameterType(type);

            type.SetTypeKind(TypeKind.TK_TypeParameterType);
            return type;
        }
Exemple #20
0
        // TypeParameter
        public TypeParameterType CreateTypeParameter(TypeParameterSymbol pSymbol)
        {
            TypeParameterType type = new TypeParameterType();

            type.SetTypeParameterSymbol(pSymbol);
            type.SetUnresolved(pSymbol.parent != null && pSymbol.parent.IsAggregateSymbol() && pSymbol.parent.AsAggregateSymbol().IsUnresolved());
            type.SetName(pSymbol.name);

#if CSEE
            type.typeRes = type;
            if (!type.IsUnresolved())
            {
                type.tsRes = ktsImportMax;
            }
#endif // CSEE

            Debug.Assert(pSymbol.GetTypeParameterType() == null);
            pSymbol.SetTypeParameterType(type);

            type.SetTypeKind(TypeKind.TK_TypeParameterType);
            return(type);
        }
Exemple #21
0
            ////////////////////////////////////////////////////////////////////////////////
            // Get the standard type variable (eg, !0, !1, or !!0, !!1).
            //
            //      iv is the index.
            //      pbsm is the containing symbol manager
            //      fMeth designates whether this is a method type var or class type var
            //
            // The standard class type variables are useful during emit, but not for type
            // comparison when binding. The standard method type variables are useful during
            // binding for signature comparison.

            public TypeParameterType GetTypeVarSym(int iv, TypeManager pTypeManager, bool fMeth)
            {
                Debug.Assert(iv >= 0);

                TypeParameterType tpt = null;

                if (iv >= this.prgptvs.Count)
                {
                    TypeParameterSymbol pTypeParameter = new TypeParameterSymbol();
                    pTypeParameter.SetIsMethodTypeParameter(fMeth);
                    pTypeParameter.SetIndexInOwnParameters(iv);
                    pTypeParameter.SetIndexInTotalParameters(iv);
                    pTypeParameter.SetAccess(ACCESS.ACC_PRIVATE);
                    tpt = pTypeManager.GetTypeParameter(pTypeParameter);
                    this.prgptvs.Add(tpt);
                }
                else
                {
                    tpt = this.prgptvs[iv];
                }
                Debug.Assert(tpt != null);
                return(tpt);
            }
Exemple #22
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 #23
0
 public void InsertTypeParameter(
     TypeParameterSymbol pTypeParameterSymbol,
     TypeParameterType pTypeParameter)
 {
     _pTypeParameterTable.Add(pTypeParameterSymbol, pTypeParameter);
 }
Exemple #24
0
        public TypeArray GetStdMethTyVarArray(int cTyVars)
        {
            TypeParameterType[] prgvar = new TypeParameterType[cTyVars];

            for (int ivar = 0; ivar < cTyVars; ivar++)
            {
                prgvar[ivar] = GetStdMethTypeVar(ivar);
            }

            return _BSymmgr.AllocParams(cTyVars, (CType[])prgvar);
        }
Exemple #25
0
        ////////////////////////////////////////////////////////////////////////////////
        //
        // Output types
        //
        private bool DoesOutputTypeContain(EXPR pSource, CType pDest,
            TypeParameterType pParam)
        {
            // SPEC: If E is a method group or an anonymous function and T is a delegate
            // SPEC: CType or expression tree CType then the return CType of T is an output CType
            // SPEC: of E with CType T.

            pDest = pDest.GetDelegateTypeOfPossibleExpression();
            if (!pDest.isDelegateType())
            {
                return false;
            }

            if (!pSource.isUNBOUNDLAMBDA() && !pSource.isMEMGRP())
            {
                return false;
            }

            CType pDelegateReturn = pDest.AsAggregateType().GetDelegateReturnType(GetSymbolLoader());
            if (pDelegateReturn == null)
            {
                return false;
            }
            return TypeManager.TypeContainsType(pDelegateReturn, pParam);
        }
Exemple #26
0
        ////////////////////////////////////////////////////////////////////////////////

        private void AddExactBound(TypeParameterType pParam, CType pBound)
        {
            Debug.Assert(IsUnfixed(pParam));
            int iParam = pParam.GetIndexInTotalParameters();
            if (!_pExactBounds[iParam].Contains(pBound))
            {
                _pExactBounds[iParam].Add(pBound);
            }
        }
        private static bool CheckSingleConstraint(Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
        {
            Debug.Assert(!(arg is PointerType));
            Debug.Assert(!arg.IsStaticClass);

            bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors);

            if (var.HasRefConstraint && !arg.IsReferenceType)
            {
                if (fReportErrors)
                {
                    throw ErrorHandling.Error(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
                }

                return(false);
            }

            TypeArray bnds     = TypeManager.SubstTypeArray(var.Bounds, typeArgsCls, typeArgsMeth);
            int       itypeMin = 0;

            if (var.HasValConstraint)
            {
                // If we have a type variable that is constrained to a value type, then we
                // want to check if its a nullable type, so that we can report the
                // constraint error below. In order to do this however, we need to check
                // that either the type arg is not a value type, or it is a nullable type.
                //
                // To check whether or not its a nullable type, we need to get the resolved
                // bound from the type argument and check against that.

                if (!arg.IsNonNullableValueType)
                {
                    if (fReportErrors)
                    {
                        throw ErrorHandling.Error(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
                    }

                    return(false);
                }

                // Since FValCon() is set it is redundant to check System.ValueType as well.
                if (bnds.Count != 0 && bnds[0].IsPredefType(PredefinedType.PT_VALUE))
                {
                    itypeMin = 1;
                }
            }

            for (int j = itypeMin; j < bnds.Count; j++)
            {
                CType typeBnd = bnds[j];
                if (!SatisfiesBound(arg, typeBnd))
                {
                    if (fReportErrors)
                    {
                        // The bound isn't satisfied because of a constraint type. Explain to the user why not.
                        // There are 4 main cases, based on the type of the supplied type argument:
                        //  - reference type, or type parameter known to be a reference type
                        //  - nullable type, from which there is a boxing conversion to the constraint type(see below for details)
                        //  - type variable
                        //  - value type
                        // These cases are broken out because: a) The sets of conversions which can be used
                        // for constraint satisfaction is different based on the type argument supplied,
                        // and b) Nullable is one funky type, and user's can use all the help they can get
                        // when using it.
                        ErrorCode error;
                        if (arg.IsReferenceType)
                        {
                            // A reference type can only satisfy bounds to types
                            // to which they have an implicit reference conversion
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType;
                        }
                        else if (arg is NullableType nubArg && SymbolLoader.HasBaseConversion(nubArg.UnderlyingType, typeBnd))    // This is inlining FBoxingConv
                        {
                            // nullable types do not satisfy bounds to every type that they are boxable to
                            // They only satisfy bounds of object and ValueType
                            if (typeBnd.IsPredefType(PredefinedType.PT_ENUM) || nubArg.UnderlyingType == typeBnd)
                            {
                                // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum
                                // even though the conversion from Nullable to these types is a boxing conversion
                                // This is a rare case, because these bounds can never be directly stated ...
                                // These bounds can only occur when one type paramter is constrained to a second type parameter
                                // and the second type parameter is instantiated with Enum or the underlying type of the first type
                                // parameter
                                error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum;
                            }
                            else
                            {
                                // Nullable types don't satisfy the bounds of any interface type
                                // even when there is a boxing conversion from the Nullable type to
                                // the interface type. This will be a relatively common scenario
                                // so we cal it out separately from the previous case.
                                Debug.Assert(typeBnd.IsInterfaceType);
                                error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface;
                            }
                        }
                        else
                        {
                            // Value types can only satisfy bounds through boxing conversions.
                            // Note that the exceptional case of Nullable types and boxing is handled above.
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType;
                        }

                        throw ErrorHandling.Error(error, new ErrArg(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArg(arg, ErrArgFlags.Unique));
                    }

                    return(false);
                }
            }
Exemple #28
0
        private bool HasImplicitTypeParameterBaseConversion(
            TypeParameterType pSource, CType pDest)
        {
            Debug.Assert(pSource != null);
            Debug.Assert(pDest != null);

            if (HasImplicitReferenceTypeParameterConversion(pSource, pDest))
            {
                return true;
            }
            if (HasImplicitBoxingTypeParameterConversion(pSource, pDest))
            {
                return true;
            }
            if (pDest.IsTypeParameterType() && pSource.DependsOn(pDest.AsTypeParameterType()))
            {
                return true;
            }
            return false;
        }
Exemple #29
0
        private static bool CheckSingleConstraint(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
        {
            bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors);

            if (arg.IsOpenTypePlaceholderType())
            {
                return(true);
            }

            if (arg.IsErrorType())
            {
                // Error should have been reported previously.
                return(false);
            }

            if (checker.CheckBogus(arg))
            {
                if (fReportErrors)
                {
                    errHandling.ErrorRef(ErrorCode.ERR_BogusType, arg);
                }

                return(false);
            }

            if (arg.IsPointerType() || arg.isSpecialByRefType())
            {
                if (fReportErrors)
                {
                    errHandling.Error(ErrorCode.ERR_BadTypeArgument, arg);
                }

                return(false);
            }

            if (arg.isStaticClass())
            {
                if (fReportErrors)
                {
                    checker.ReportStaticClassError(null, arg, ErrorCode.ERR_GenericArgIsStaticClass);
                }

                return(false);
            }

            bool fError = false;

            if (var.HasRefConstraint() && !arg.IsRefType())
            {
                if (fReportErrors)
                {
                    errHandling.ErrorRef(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
                }

                fError = true;
            }

            TypeArray bnds     = checker.GetSymbolLoader().GetTypeManager().SubstTypeArray(var.GetBounds(), typeArgsCls, typeArgsMeth);
            int       itypeMin = 0;

            if (var.HasValConstraint())
            {
                // If we have a type variable that is constrained to a value type, then we
                // want to check if its a nullable type, so that we can report the
                // constraint error below. In order to do this however, we need to check
                // that either the type arg is not a value type, or it is a nullable type.
                //
                // To check whether or not its a nullable type, we need to get the resolved
                // bound from the type argument and check against that.

                bool bIsValueType = arg.IsValType();
                bool bIsNullable  = arg.IsNullableType();
                if (bIsValueType && arg.IsTypeParameterType())
                {
                    TypeArray pArgBnds = arg.AsTypeParameterType().GetBounds();
                    if (pArgBnds.Count > 0)
                    {
                        bIsNullable = pArgBnds[0].IsNullableType();
                    }
                }

                if (!bIsValueType || bIsNullable)
                {
                    if (fReportErrors)
                    {
                        errHandling.ErrorRef(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
                    }

                    fError = true;
                }

                // Since FValCon() is set it is redundant to check System.ValueType as well.
                if (bnds.Count != 0 && bnds[0].isPredefType(PredefinedType.PT_VALUE))
                {
                    itypeMin = 1;
                }
            }

            for (int j = itypeMin; j < bnds.Count; j++)
            {
                CType typeBnd = bnds[j];
                if (!SatisfiesBound(checker, arg, typeBnd))
                {
                    if (fReportErrors)
                    {
                        // The bound isn't satisfied because of a constraint type. Explain to the user why not.
                        // There are 4 main cases, based on the type of the supplied type argument:
                        //  - reference type, or type parameter known to be a reference type
                        //  - nullable type, from which there is a boxing conversion to the constraint type(see below for details)
                        //  - type variable
                        //  - value type
                        // These cases are broken out because: a) The sets of conversions which can be used
                        // for constraint satisfaction is different based on the type argument supplied,
                        // and b) Nullable is one funky type, and user's can use all the help they can get
                        // when using it.
                        ErrorCode error;
                        if (arg.IsRefType())
                        {
                            // A reference type can only satisfy bounds to types
                            // to which they have an implicit reference conversion
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType;
                        }
                        else if (arg.IsNullableType() && checker.GetSymbolLoader().HasBaseConversion(arg.AsNullableType().GetUnderlyingType(), typeBnd))    // This is inlining FBoxingConv
                        {
                            // nullable types do not satisfy bounds to every type that they are boxable to
                            // They only satisfy bounds of object and ValueType
                            if (typeBnd.isPredefType(PredefinedType.PT_ENUM) || arg.AsNullableType().GetUnderlyingType() == typeBnd)
                            {
                                // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum
                                // even though the conversion from Nullable to these types is a boxing conversion
                                // This is a rare case, because these bounds can never be directly stated ...
                                // These bounds can only occur when one type paramter is constrained to a second type parameter
                                // and the second type parameter is instantiated with Enum or the underlying type of the first type
                                // parameter
                                error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum;
                            }
                            else
                            {
                                // Nullable types don't satisfy the bounds of any interface type
                                // even when there is a boxing conversion from the Nullable type to
                                // the interface type. This will be a relatively common scenario
                                // so we cal it out separately from the previous case.
                                Debug.Assert(typeBnd.isInterfaceType());
                                error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface;
                            }
                        }
                        else if (arg.IsTypeParameterType())
                        {
                            // Type variables can satisfy bounds through boxing and type variable conversions
                            Debug.Assert(!arg.IsRefType());
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar;
                        }
                        else
                        {
                            // Value types can only satisfy bounds through boxing conversions.
                            // Note that the exceptional case of Nullable types and boxing is handled above.
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType;
                        }
                        errHandling.Error(error, new ErrArgRef(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArgRef(arg, ErrArgFlags.Unique));
                    }
                    fError = true;
                }
            }

            // Check the newable constraint.
            if (!var.HasNewConstraint() || arg.IsValType())
            {
                return(!fError);
            }

            if (arg.isClassType())
            {
                AggregateSymbol agg = arg.AsAggregateType().getAggregate();

                // Due to late binding nature of IDE created symbols, the AggregateSymbol might not
                // have all the information necessary yet, if it is not fully bound.
                // by calling LookupAggMember, it will ensure that we will update all the
                // information necessary at least for the given method.
                checker.GetSymbolLoader().LookupAggMember(checker.GetNameManager().GetPredefName(PredefinedName.PN_CTOR), agg, symbmask_t.MASK_ALL);

                if (agg.HasPubNoArgCtor() && !agg.IsAbstract())
                {
                    return(!fError);
                }
            }
            else if (arg.IsTypeParameterType() && arg.AsTypeParameterType().HasNewConstraint())
            {
                return(!fError);
            }

            if (fReportErrors)
            {
                errHandling.ErrorRef(ErrorCode.ERR_NewConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
            }

            return(false);
        }
Exemple #30
0
 public static bool ParametersContainTyVar(TypeArray @params, TypeParameterType typeFind)
 {
     Debug.Assert(@params != null);
     Debug.Assert(typeFind != null);
     for (int p = 0; p < @params.size; p++)
     {
         CType sym = @params[p];
         if (TypeContainsType(sym, typeFind))
         {
             return true;
         }
     }
     return false;
 }
Exemple #31
0
            private bool bindImplicitConversionFromTypeVar(TypeParameterType tyVarSrc)
            {
                // 13.1.4
                //
                // For a type-parameter T that is known to be a reference type (25.7), the following implicit
                // reference conversions exist:
                //
                // *   From T to its effective base class C, from T to any base class of C, and from T to any
                //     interface implemented by C.
                // *   From T to an interface-type I in T's effective interface set and from T to any base
                //     interface of I.
                // *   From T to a type parameter U provided that T depends on U (25.7). [Note: Since T is known
                //     to be a reference type, within the scope of T, the run-time type of U will always be a
                //     reference type, even if U is not known to be a reference type at compile-time.]
                // *   From the null type (11.2.7) to T.
                //
                // 13.1.5
                //
                // For a type-parameter T that is not known to be a reference type (25.7), the following conversions
                // involving T are considered to be boxing conversions at compile-time. At run-time, if T is a value
                // type, the conversion is executed as a boxing conversion. At run-time, if T is a reference type,
                // the conversion is executed as an implicit reference conversion or identity conversion.
                //
                // *   From T to its effective base class C, from T to any base class of C, and from T to any
                //     interface implemented by C. [Note: C will be one of the types System.Object, System.ValueType,
                //     or System.Enum (otherwise T would be known to be a reference type and 13.1.4 would apply
                //     instead of this clause).]
                // *   From T to an interface-type I in T's effective interface set and from T to any base
                //     interface of I.
                //
                // 13.1.6 Implicit type parameter conversions
                //
                // This clause details implicit conversions involving type parameters that are not classified as
                // implicit reference conversions or implicit boxing conversions.
                //
                // For a type-parameter T that is not known to be a reference type, there is an implicit conversion
                // from T to a type parameter U provided T depends on U. At run-time, if T is a value type and U is
                // a reference type, the conversion is executed as a boxing conversion. At run-time, if both T and U
                // are value types, then T and U are necessarily the same type and no conversion is performed. At
                // run-time, if T is a reference type, then U is necessarily also a reference type and the conversion
                // is executed as an implicit reference conversion or identity conversion (25.7).

                CType     typeTmp = tyVarSrc.GetEffectiveBaseClass();
                TypeArray bnds    = tyVarSrc.GetBounds();
                int       itype   = -1;

                for (; ;)
                {
                    if (binder.canConvert(typeTmp, typeDest, flags | CONVERTTYPE.NOUDC))
                    {
                        if (!needsExprDest)
                        {
                            return(true);
                        }
                        if (typeDest.IsTypeParameterType())
                        {
                            // For a type var destination we need to cast to object then to the other type var.
                            EXPR      exprT;
                            EXPRCLASS exprObj = GetExprFactory().MakeClass(binder.GetReqPDT(PredefinedType.PT_OBJECT));
                            binder.bindSimpleCast(exprSrc, exprObj, out exprT, EXPRFLAG.EXF_FORCE_BOX);
                            binder.bindSimpleCast(exprT, exprTypeDest, out exprDest, EXPRFLAG.EXF_FORCE_UNBOX);
                        }
                        else
                        {
                            binder.bindSimpleCast(exprSrc, exprTypeDest, out exprDest, EXPRFLAG.EXF_FORCE_BOX);
                        }
                        return(true);
                    }
                    do
                    {
                        if (++itype >= bnds.Size)
                        {
                            return(false);
                        }
                        typeTmp = bnds.Item(itype);
                    }while (!typeTmp.isInterfaceType() && !typeTmp.IsTypeParameterType());
                }
            }
 public void SetTypeParameterType(TypeParameterType pType)
 {
     _pTypeParameterType = pType;
 }
Exemple #33
0
 public void SetTypeParameterType(TypeParameterType pType)
 {
     _pTypeParameterType = pType;
 }
Exemple #34
0
        ////////////////////////////////////////////////////////////////////////////////

        private bool IsUnfixed(TypeParameterType pParam)
        {
            Debug.Assert(pParam != null);
            Debug.Assert(pParam.IsMethodTypeParameter());
            int iParam = pParam.GetIndexInTotalParameters();
            Debug.Assert(_pMethodTypeParameters.ItemAsTypeParameterType(iParam) == pParam);
            return IsUnfixed(iParam);
        }
Exemple #35
0
        private bool HasImplicitReferenceTypeParameterConversion(
            TypeParameterType pSource, CType pDest)
        {
            Debug.Assert(pSource != null);
            Debug.Assert(pDest != null);

            if (!pSource.IsRefType())
            {
                // Not a reference conversion.
                return false;
            }

            // The following implicit conversions exist for a given type parameter T:
            //
            // * From T to its effective base class C.
            AggregateType pEBC = pSource.GetEffectiveBaseClass();
            if (pDest == pEBC)
            {
                return true;
            }
            // * From T to any base class of C.
            if (IsBaseClass(pEBC, pDest))
            {
                return true;
            }
            // * From T to any interface implemented by C.
            if (IsBaseInterface(pEBC, pDest))
            {
                return true;
            }
            // * From T to any interface type I in T's effective interface set, and
            //   from T to any base interface of I.
            TypeArray pInterfaces = pSource.GetInterfaceBounds();
            for (int i = 0; i < pInterfaces.Size; ++i)
            {
                if (pInterfaces.Item(i) == pDest)
                {
                    return true;
                }
            }
            // * From T to a type parameter U, provided T depends on U.
            if (pDest.IsTypeParameterType() && pSource.DependsOn(pDest.AsTypeParameterType()))
            {
                return true;
            }
            return false;
        }
Exemple #36
0
        ////////////////////////////////////////////////////////////////////////////////
        //
        // Input types
        //
        private bool DoesInputTypeContain(EXPR pSource, CType pDest,
            TypeParameterType pParam)
        {
            // SPEC: If E is a method group or an anonymous function and T is a delegate
            // SPEC: CType or expression tree CType then all the parameter types of T are
            // SPEC: input types of E with CType T.

            pDest = pDest.GetDelegateTypeOfPossibleExpression();
            if (!pDest.isDelegateType())
            {
                return false; // No input types.
            }

            if (!pSource.isUNBOUNDLAMBDA() && !pSource.isMEMGRP())
            {
                return false; // No input types.
            }

            TypeArray pDelegateParameters =
                pDest.AsAggregateType().GetDelegateParameters(GetSymbolLoader());
            if (pDelegateParameters == null)
            {
                return false;
            }
            return TypeManager.ParametersContainTyVar(pDelegateParameters, pParam);
        }
Exemple #37
0
            private bool bindImplicitConversionFromTypeVar(TypeParameterType tyVarSrc)
            {
                // 13.1.4
                // 
                // For a type-parameter T that is known to be a reference type (25.7), the following implicit
                // reference conversions exist:
                // 
                // *   From T to its effective base class C, from T to any base class of C, and from T to any 
                //     interface implemented by C.
                // *   From T to an interface-type I in T's effective interface set and from T to any base 
                //     interface of I.
                // *   From T to a type parameter U provided that T depends on U (25.7). [Note: Since T is known
                //     to be a reference type, within the scope of T, the run-time type of U will always be a 
                //     reference type, even if U is not known to be a reference type at compile-time.]
                // *   From the null type (11.2.7) to T.
                //
                // 13.1.5
                //
                // For a type-parameter T that is not known to be a reference type (25.7), the following conversions
                // involving T are considered to be boxing conversions at compile-time. At run-time, if T is a value
                // type, the conversion is executed as a boxing conversion. At run-time, if T is a reference type,
                // the conversion is executed as an implicit reference conversion or identity conversion.
                // 
                // *   From T to its effective base class C, from T to any base class of C, and from T to any 
                //     interface implemented by C. [Note: C will be one of the types System.Object, System.ValueType,
                //     or System.Enum (otherwise T would be known to be a reference type and 13.1.4 would apply
                //     instead of this clause).]
                // *   From T to an interface-type I in T's effective interface set and from T to any base
                //     interface of I.
                //
                // 13.1.6 Implicit type parameter conversions
                // 
                // This clause details implicit conversions involving type parameters that are not classified as 
                // implicit reference conversions or implicit boxing conversions.
                // 
                // For a type-parameter T that is not known to be a reference type, there is an implicit conversion 
                // from T to a type parameter U provided T depends on U. At run-time, if T is a value type and U is
                // a reference type, the conversion is executed as a boxing conversion. At run-time, if both T and U
                // are value types, then T and U are necessarily the same type and no conversion is performed. At 
                // run-time, if T is a reference type, then U is necessarily also a reference type and the conversion
                // is executed as an implicit reference conversion or identity conversion (25.7).

                CType typeTmp = tyVarSrc.GetEffectiveBaseClass();
                TypeArray bnds = tyVarSrc.GetBounds();
                int itype = -1;
                for (; ;)
                {
                    if (_binder.canConvert(typeTmp, _typeDest, _flags | CONVERTTYPE.NOUDC))
                    {
                        if (!_needsExprDest)
                        {
                            return true;
                        }
                        if (_typeDest.IsTypeParameterType())
                        {
                            // For a type var destination we need to cast to object then to the other type var.
                            EXPR exprT;
                            EXPRCLASS exprObj = GetExprFactory().MakeClass(_binder.GetReqPDT(PredefinedType.PT_OBJECT));
                            _binder.bindSimpleCast(_exprSrc, exprObj, out exprT, EXPRFLAG.EXF_FORCE_BOX);
                            _binder.bindSimpleCast(exprT, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_FORCE_UNBOX);
                        }
                        else
                        {
                            _binder.bindSimpleCast(_exprSrc, _exprTypeDest, out _exprDest, EXPRFLAG.EXF_FORCE_BOX);
                        }
                        return true;
                    }
                    do
                    {
                        if (++itype >= bnds.Size)
                        {
                            return false;
                        }
                        typeTmp = bnds.Item(itype);
                    }
                    while (!typeTmp.isInterfaceType() && !typeTmp.IsTypeParameterType());
                }
            }
Exemple #38
0
        private bool HasImplicitBoxingTypeParameterConversion(
            TypeParameterType pSource, CType pDest)
        {
            Debug.Assert(pSource != null);
            Debug.Assert(pDest != null);

            if (pSource.IsRefType())
            {
                // Not a boxing conversion; both source and destination are references.
                return false;
            }

            // The following implicit conversions exist for a given type parameter T:
            //
            // * From T to its effective base class C.
            AggregateType pEBC = pSource.GetEffectiveBaseClass();
            if (pDest == pEBC)
            {
                return true;
            }
            // * From T to any base class of C.
            if (IsBaseClass(pEBC, pDest))
            {
                return true;
            }
            // * From T to any interface implemented by C.
            if (IsBaseInterface(pEBC, pDest))
            {
                return true;
            }
            // * From T to any interface type I in T's effective interface set, and
            //   from T to any base interface of I.
            TypeArray pInterfaces = pSource.GetInterfaceBounds();
            for (int i = 0; i < pInterfaces.Size; ++i)
            {
                if (pInterfaces.Item(i) == pDest)
                {
                    return true;
                }
            }
            // * The conversion from T to a type parameter U, provided T depends on U, is not
            //   classified as a boxing conversion because it is not guaranteed to box.
            //   (If both T and U are value types then it is an identity conversion.)

            return false;
        }
Exemple #39
0
        private static bool CheckSingleConstraint(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
        {
            bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors);

            if (arg.IsOpenTypePlaceholderType())
            {
                return true;
            }

            if (arg.IsErrorType())
            {
                // Error should have been reported previously.
                return false;
            }

            if (checker.CheckBogus(arg))
            {
                if (fReportErrors)
                {
                    errHandling.ErrorRef(ErrorCode.ERR_BogusType, arg);
                }

                return false;
            }

            if (arg.IsPointerType() || arg.isSpecialByRefType())
            {
                if (fReportErrors)
                {
                    errHandling.Error(ErrorCode.ERR_BadTypeArgument, arg);
                }

                return false;
            }

            if (arg.isStaticClass())
            {
                if (fReportErrors)
                {
                    checker.ReportStaticClassError(null, arg, ErrorCode.ERR_GenericArgIsStaticClass);
                }

                return false;
            }

            bool fError = false;
            if (var.HasRefConstraint() && !arg.IsRefType())
            {
                if (fReportErrors)
                {
                    errHandling.ErrorRef(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
                }

                fError = true;
            }

            TypeArray bnds = checker.GetSymbolLoader().GetTypeManager().SubstTypeArray(var.GetBounds(), typeArgsCls, typeArgsMeth);
            int itypeMin = 0;

            if (var.HasValConstraint())
            {
                // If we have a type variable that is constrained to a value type, then we
                // want to check if its a nullable type, so that we can report the 
                // constraint error below. In order to do this however, we need to check 
                // that either the type arg is not a value type, or it is a nullable type.
                //
                // To check whether or not its a nullable type, we need to get the resolved
                // bound from the type argument and check against that.

                bool bIsValueType = arg.IsValType();
                bool bIsNullable = arg.IsNullableType();
                if (bIsValueType && arg.IsTypeParameterType())
                {
                    TypeArray pArgBnds = arg.AsTypeParameterType().GetBounds();
                    if (pArgBnds.size > 0)
                    {
                        bIsNullable = pArgBnds.Item(0).IsNullableType();
                    }
                }

                if (!bIsValueType || bIsNullable)
                {
                    if (fReportErrors)
                    {
                        errHandling.ErrorRef(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
                    }

                    fError = true;
                }

                // Since FValCon() is set it is redundant to check System.ValueType as well.
                if (bnds.size != 0 && bnds.Item(0).isPredefType(PredefinedType.PT_VALUE))
                {
                    itypeMin = 1;
                }
            }

            for (int j = itypeMin; j < bnds.size; j++)
            {
                CType typeBnd = bnds.Item(j);
                if (!SatisfiesBound(checker, arg, typeBnd))
                {
                    if (fReportErrors)
                    {
                        // The bound isn't satisfied because of a constaint type. Explain to the user why not.
                        // There are 4 main cases, based on the type of the supplied type argument:
                        //  - reference type, or type parameter known to be a reference type
                        //  - nullable type, from which there is a boxing conversion to the constraint type(see below for details)
                        //  - type varaiable
                        //  - value type
                        // These cases are broken out because: a) The sets of conversions which can be used 
                        // for constraint satisfaction is different based on the type argument supplied, 
                        // and b) Nullable is one funky type, and user's can use all the help they can get
                        // when using it.
                        ErrorCode error;
                        if (arg.IsRefType())
                        {
                            // A reference type can only satisfy bounds to types 
                            // to which they have an implicit reference conversion
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType;
                        }
                        else if (arg.IsNullableType() && checker.GetSymbolLoader().HasBaseConversion(arg.AsNullableType().GetUnderlyingType(), typeBnd))    // This is inlining FBoxingConv
                        {
                            // nullable types do not satisfy bounds to every type that they are boxable to
                            // They only satisfy bounds of object and ValueType
                            if (typeBnd.isPredefType(PredefinedType.PT_ENUM) || arg.AsNullableType().GetUnderlyingType() == typeBnd)
                            {
                                // Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum
                                // even though the conversion from Nullable to these types is a boxing conversion
                                // This is a rare case, because these bounds can never be directly stated ...
                                // These bounds can only occur when one type paramter is constrained to a second type parameter
                                // and the second type parameter is instantiated with Enum or the underlying type of the first type
                                // parameter
                                error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum;
                            }
                            else
                            {
                                // Nullable types don't satisfy the bounds of any interface type
                                // even when there is a boxing conversion from the Nullable type to 
                                // the interface type. This will be a relatively common scenario
                                // so we cal it out separately from the previous case.
                                Debug.Assert(typeBnd.isInterfaceType());
                                error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface;
                            }
                        }
                        else if (arg.IsTypeParameterType())
                        {
                            // Type variables can satisfy bounds through boxing and type variable conversions
                            Debug.Assert(!arg.IsRefType());
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar;
                        }
                        else
                        {
                            // Value types can only satisfy bounds through boxing conversions.
                            // Note that the exceptional case of Nullable types and boxing is handled above.
                            error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType;
                        }
                        errHandling.Error(error, new ErrArgRef(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArgRef(arg, ErrArgFlags.Unique));
                    }
                    fError = true;
                }
            }

            // Check the newable constraint.
            if (!var.HasNewConstraint() || arg.IsValType())
            {
                return !fError;
            }

            if (arg.isClassType())
            {
                AggregateSymbol agg = arg.AsAggregateType().getAggregate();

                // Due to late binding nature of IDE created symbols, the AggregateSymbol might not
                // have all the information necessary yet, if it is not fully bound.
                // by calling LookupAggMember, it will ensure that we will update all the
                // information necessary at least for the given method.
                checker.GetSymbolLoader().LookupAggMember(checker.GetNameManager().GetPredefName(PredefinedName.PN_CTOR), agg, symbmask_t.MASK_ALL);

                if (agg.HasPubNoArgCtor() && !agg.IsAbstract())
                {
                    return !fError;
                }
            }
            else if (arg.IsTypeParameterType() && arg.AsTypeParameterType().HasNewConstraint())
            {
                return !fError;
            }

            if (fReportErrors)
            {
                errHandling.ErrorRef(ErrorCode.ERR_NewConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
            }

            return false;
        }