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); }
/// <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)); }
/// <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), }); }