예제 #1
0
        private EntityHandle MakeTypeRefHandle(TypeDesc type)
        {
            Debug.Assert(type.IsTypeDefinition);
            Debug.Assert((type is EcmaType) || _typeSystemContext.IsCanonicalDefinitionType(type, CanonicalFormKind.Any));

            EntityHandle handle;

            if (!_typeRefOrSpecHandles.TryGetValue(type, out handle))
            {
                if (_typeSystemContext.IsCanonicalDefinitionType(type, CanonicalFormKind.Any))
                {
                    CanonBaseType canonType = (CanonBaseType)type;

                    handle = _metadataBuilder.AddTypeReference(
                        MakeCorlibAssemblyReferenceHandle(),
                        _metadataBuilder.GetOrAddString(canonType.Namespace),
                        _metadataBuilder.GetOrAddString(canonType.Name));
                }
                else
                {
                    EntityHandle scope;
                    EcmaType     typeAsEcmaType = (EcmaType)type;

                    if (typeAsEcmaType.ContainingType != null)
                    {
                        scope = MakeTypeRefHandle(typeAsEcmaType.ContainingType);
                    }
                    else
                    {
                        scope = MakeAssemblyReferenceHandle((EcmaAssembly)typeAsEcmaType.EcmaModule);
                    }

                    handle = _metadataBuilder.AddTypeReference(
                        scope,
                        _metadataBuilder.GetOrAddString(typeAsEcmaType.Namespace),
                        _metadataBuilder.GetOrAddString(typeAsEcmaType.Name));
                }

                _typeRefOrSpecHandles[type] = handle;
            }

            return(handle);
        }
예제 #2
0
        /// <summary>
        /// Gets the comparer type that is suitable to compare instances of <paramref name="type"/>
        /// or null if such comparer cannot be determined at compile time.
        /// </summary>
        private static TypeDesc GetComparerForType(TypeDesc type, string flavor, string interfaceName)
        {
            TypeSystemContext context = type.Context;

            if (context.IsCanonicalDefinitionType(type, CanonicalFormKind.Any) ||
                (type.IsRuntimeDeterminedSubtype && !type.HasInstantiation))
            {
                // The comparer will be determined at runtime. We can't tell the exact type at compile time.
                return(null);
            }
            else if (type.IsNullable)
            {
                TypeDesc nullableType = type.Instantiation[0];

                if (context.IsCanonicalDefinitionType(nullableType, CanonicalFormKind.Universal))
                {
                    // We can't tell at compile time either.
                    return(null);
                }
                else if (ImplementsInterfaceOfSelf(nullableType, interfaceName))
                {
                    return(context.SystemModule.GetKnownType("System.Collections.Generic", $"Nullable{flavor}`1")
                           .MakeInstantiatedType(nullableType));
                }
            }
            else if (flavor == "EqualityComparer" && type.IsEnum)
            {
                // Enums have a specialized comparer that avoids boxing
                return(context.SystemModule.GetKnownType("System.Collections.Generic", $"Enum{flavor}`1")
                       .MakeInstantiatedType(type));
            }
            else if (ImplementsInterfaceOfSelf(type, interfaceName))
            {
                return(context.SystemModule.GetKnownType("System.Collections.Generic", $"Generic{flavor}`1")
                       .MakeInstantiatedType(type));
            }

            return(context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1")
                   .MakeInstantiatedType(type));
        }
예제 #3
0
        /// <summary>
        /// Gets the set of template types needed to support loading comparers for the give canonical type at runtime.
        /// </summary>
        private static TypeDesc[] GetPotentialComparersForTypeCommon(TypeDesc type, string flavor, string interfaceName)
        {
            Debug.Assert(type.IsCanonicalSubtype(CanonicalFormKind.Any));

            TypeDesc exactComparer = GetComparerForType(type, flavor, interfaceName);

            if (exactComparer != null)
            {
                // If we have a comparer that is exactly known at runtime, we're done.
                // This will typically be if type is a generic struct, generic enum, or a nullable.
                return(new TypeDesc[] { exactComparer });
            }

            TypeSystemContext context = type.Context;

            if (context.IsCanonicalDefinitionType(type, CanonicalFormKind.Universal))
            {
                // This can be any of the comparers we have.

                ArrayBuilder <TypeDesc> universalComparers = new ArrayBuilder <TypeDesc>();

                universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Nullable{flavor}`1")
                                       .MakeInstantiatedType(type));

                if (flavor == "EqualityComparer")
                {
                    universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Enum{flavor}`1")
                                           .MakeInstantiatedType(type));
                }

                universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Generic{flavor}`1")
                                       .MakeInstantiatedType(type));

                universalComparers.Add(context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1")
                                       .MakeInstantiatedType(type));

                return(universalComparers.ToArray());
            }

            // This mirrors exactly what GetUnknownEquatableComparer and GetUnknownComparer (in the class library)
            // will need at runtime. This is the general purpose code path that can be used to compare
            // anything.

            if (type.IsNullable)
            {
                TypeDesc nullableType = type.Instantiation[0];

                // This should only be reachabe for universal canon code.
                // For specific canon, this should have been an exact match above.
                Debug.Assert(context.IsCanonicalDefinitionType(nullableType, CanonicalFormKind.Universal));

                return(new TypeDesc[]
                {
                    context.SystemModule.GetKnownType("System.Collections.Generic", $"Nullable{flavor}`1")
                    .MakeInstantiatedType(nullableType),
                    context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1")
                    .MakeInstantiatedType(type),
                });
            }

            return(new TypeDesc[]
            {
                context.SystemModule.GetKnownType("System.Collections.Generic", $"Generic{flavor}`1")
                .MakeInstantiatedType(type),
                context.SystemModule.GetKnownType("System.Collections.Generic", $"Object{flavor}`1")
                .MakeInstantiatedType(type),
            });
        }