Beispiel #1
0
 internal GenericArgumentCollection(uint argumentCount, EETypeRef *arguments)
 {
     _argumentCount = argumentCount;
     _arguments     = arguments;
 }
Beispiel #2
0
        private static bool FindImplSlotInSimpleMap(EEType *pTgtType,
                                                    EEType *pItfType,
                                                    uint itfSlotNumber,
                                                    ushort *pImplSlotNumber,
                                                    bool actuallyCheckVariance)
        {
            Debug.Assert(pTgtType->HasDispatchMap, "Missing dispatch map");

            EEType *         pItfOpenGenericType = null;
            EETypeRef *      pItfInstantiation   = null;
            int              itfArity            = 0;
            GenericVariance *pItfVarianceInfo    = null;

            bool fCheckVariance   = false;
            bool fArrayCovariance = false;

            if (actuallyCheckVariance)
            {
                fCheckVariance   = pItfType->HasGenericVariance;
                fArrayCovariance = pTgtType->IsArray;

                // Non-arrays can follow array variance rules iff
                // 1. They have one generic parameter
                // 2. That generic parameter is array covariant.
                //
                // This special case is to allow array enumerators to work
                if (!fArrayCovariance && pTgtType->HasGenericVariance)
                {
                    int tgtEntryArity = (int)pTgtType->GenericArity;
                    GenericVariance *pTgtVarianceInfo = pTgtType->GenericVariance;

                    if ((tgtEntryArity == 1) && pTgtVarianceInfo[0] == GenericVariance.ArrayCovariant)
                    {
                        fArrayCovariance = true;
                    }
                }

                // Arrays are covariant even though you can both get and set elements (type safety is maintained by
                // runtime type checks during set operations). This extends to generic interfaces implemented on those
                // arrays. We handle this by forcing all generic interfaces on arrays to behave as though they were
                // covariant (over their one type parameter corresponding to the array element type).
                if (fArrayCovariance && pItfType->IsGeneric)
                {
                    fCheckVariance = true;
                }

                // If there is no variance checking, there is no operation to perform. (The non-variance check loop
                // has already completed)
                if (!fCheckVariance)
                {
                    return(false);
                }
            }

            DispatchMap *pMap = pTgtType->DispatchMap;

            DispatchMap.DispatchMapEntry *i    = (*pMap)[0];
            DispatchMap.DispatchMapEntry *iEnd = (*pMap)[(int)pMap->NumEntries];
            for (; i != iEnd; ++i)
            {
                if (i->_usInterfaceMethodSlot == itfSlotNumber)
                {
                    EEType *pCurEntryType =
                        pTgtType->InterfaceMap[i->_usInterfaceIndex].InterfaceType;

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

                    if (pCurEntryType == pItfType)
                    {
                        *pImplSlotNumber = i->_usImplMethodSlot;
                        return(true);
                    }
                    else if (fCheckVariance && ((fArrayCovariance && pCurEntryType->IsGeneric) || pCurEntryType->HasGenericVariance))
                    {
                        // Interface types don't match exactly but both the target interface and the current interface
                        // in the map are marked as being generic with at least one co- or contra- variant type
                        // parameter. So we might still have a compatible match.

                        // Retrieve the unified generic instance for the callsite interface if we haven't already (we
                        // lazily get this then cache the result since the lookup isn't necessarily cheap).
                        if (pItfOpenGenericType == null)
                        {
                            pItfOpenGenericType = pItfType->GenericDefinition;
                            itfArity            = (int)pItfType->GenericArity;
                            pItfInstantiation   = pItfType->GenericArguments;
                            pItfVarianceInfo    = pItfType->GenericVariance;
                        }

                        // Retrieve the unified generic instance for the interface we're looking at in the map.
                        EEType *pCurEntryGenericType = pCurEntryType->GenericDefinition;

                        // If the generic types aren't the same then the types aren't compatible.
                        if (pItfOpenGenericType != pCurEntryGenericType)
                        {
                            continue;
                        }

                        // Grab instantiation details for the candidate interface.
                        EETypeRef *pCurEntryInstantiation = pCurEntryType->GenericArguments;

                        // The types represent different instantiations of the same generic type. The
                        // arity of both had better be the same.
                        Debug.Assert(itfArity == (int)pCurEntryType->GenericArity, "arity mismatch betweeen generic instantiations");

                        if (TypeCast.TypeParametersAreCompatible(itfArity, pCurEntryInstantiation, pItfInstantiation, pItfVarianceInfo, fArrayCovariance, null))
                        {
                            *pImplSlotNumber = i->_usImplMethodSlot;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Beispiel #3
0
        // Compare two sets of generic type parameters to see if they're assignment compatible taking generic
        // variance into account. It's assumed they've already had their type definition matched (which
        // implies their arities are the same as well). The fForceCovariance argument tells the method to
        // override the defined variance of each parameter and instead assume it is covariant. This is used to
        // implement covariant array interfaces.
        static internal unsafe bool TypeParametersAreCompatible(int arity,
                                                                EETypeRef *pSourceInstantiation,
                                                                EETypeRef *pTargetInstantiation,
                                                                GenericVariance *pVarianceInfo,
                                                                bool fForceCovariance)
        {
            // Walk through the instantiations comparing the cast compatibility of each pair
            // of type args.
            for (int i = 0; i < arity; i++)
            {
                EEType *pTargetArgType = pTargetInstantiation[i].Value;
                EEType *pSourceArgType = pSourceInstantiation[i].Value;

                GenericVariance varType;
                if (fForceCovariance)
                {
                    varType = GenericVariance.ArrayCovariant;
                }
                else
                {
                    varType = pVarianceInfo[i];
                }

                switch (varType)
                {
                case GenericVariance.NonVariant:
                    // Non-variant type params need to be identical.

                    if (!AreTypesEquivalentInternal(pSourceArgType, pTargetArgType))
                    {
                        return(false);
                    }

                    break;

                case GenericVariance.Covariant:
                    // For covariance (or out type params in C#) the object must implement an
                    // interface with a more derived type arg than the target interface. Or
                    // the object interface can have a type arg that is an interface
                    // implemented by the target type arg.
                    // For instance:
                    //   class Foo : ICovariant<String> is ICovariant<Object>
                    //   class Foo : ICovariant<Bar> is ICovariant<IBar>
                    //   class Foo : ICovariant<IBar> is ICovariant<Object>

                    if (!AreTypesAssignableInternal(pSourceArgType, pTargetArgType, false, false))
                    {
                        return(false);
                    }

                    break;

                case GenericVariance.ArrayCovariant:
                    // For array covariance the object must be an array with a type arg
                    // that is more derived than that the target interface, or be a primitive
                    // (or enum) with the same size.
                    // For instance:
                    //   string[,,] is object[,,]
                    //   int[,,] is uint[,,]

                    // This call is just like the call for Covariance above except true is passed
                    // to the fAllowSizeEquivalence parameter to allow the int/uint matching to work
                    if (!AreTypesAssignableInternal(pSourceArgType, pTargetArgType, false, true))
                    {
                        return(false);
                    }

                    break;

                case GenericVariance.Contravariant:
                    // For contravariance (or in type params in C#) the object must implement
                    // an interface with a less derived type arg than the target interface. Or
                    // the object interface can have a type arg that is a class implementing
                    // the interface that is the target type arg.
                    // For instance:
                    //   class Foo : IContravariant<Object> is IContravariant<String>
                    //   class Foo : IContravariant<IBar> is IContravariant<Bar>
                    //   class Foo : IContravariant<Object> is IContravariant<IBar>

                    if (!AreTypesAssignableInternal(pTargetArgType, pSourceArgType, false, false))
                    {
                        return(false);
                    }

                    break;

                default:
                    Debug.Assert(false, "unknown generic variance type");
                    break;
                }
            }

            return(true);
        }