File: Emitter\Model\NamedTypeSymbolAdapter.cs
Web Access
Project: src\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using Microsoft.Cci;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    internal partial class
#if DEBUG
        NamedTypeSymbolAdapter : SymbolAdapter,
#else
        NamedTypeSymbol :
#endif 
        Cci.ITypeReference,
        Cci.ITypeDefinition,
        Cci.INamedTypeReference,
        Cci.INamedTypeDefinition,
        Cci.INamespaceTypeReference,
        Cci.INamespaceTypeDefinition,
        Cci.INestedTypeReference,
        Cci.INestedTypeDefinition,
        Cci.IGenericTypeInstanceReference,
        Cci.ISpecializedNestedTypeReference
    {
        bool Cci.IDefinition.IsEncDeleted
            => false;
 
        bool Cci.ITypeReference.IsEnum
        {
            get { return AdaptedNamedTypeSymbol.TypeKind == TypeKind.Enum; }
        }
 
        bool Cci.ITypeReference.IsValueType
        {
            get { return AdaptedNamedTypeSymbol.IsValueType; }
        }
 
        Cci.ITypeDefinition Cci.ITypeReference.GetResolvedType(EmitContext context)
        {
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            return AsTypeDefinitionImpl(moduleBeingBuilt);
        }
 
        Cci.PrimitiveTypeCode Cci.ITypeReference.TypeCode
        {
            get
            {
                Debug.Assert(this.IsDefinitionOrDistinct());
 
                if (AdaptedNamedTypeSymbol.IsDefinition)
                {
                    return AdaptedNamedTypeSymbol.PrimitiveTypeCode;
                }
 
                return Cci.PrimitiveTypeCode.NotPrimitive;
            }
        }
 
        TypeDefinitionHandle Cci.ITypeReference.TypeDef
        {
            get
            {
                PENamedTypeSymbol peNamedType = AdaptedNamedTypeSymbol as PENamedTypeSymbol;
                if ((object)peNamedType != null)
                {
                    return peNamedType.Handle;
                }
 
                return default(TypeDefinitionHandle);
            }
        }
 
        Cci.IGenericMethodParameterReference Cci.ITypeReference.AsGenericMethodParameterReference
        {
            get { return null; }
        }
 
        Cci.IGenericTypeInstanceReference Cci.ITypeReference.AsGenericTypeInstanceReference
        {
            get
            {
                Debug.Assert(this.IsDefinitionOrDistinct());
 
                if (!AdaptedNamedTypeSymbol.IsDefinition &&
                    AdaptedNamedTypeSymbol.Arity > 0)
                {
                    return this;
                }
 
                return null;
            }
        }
 
        Cci.IGenericTypeParameterReference Cci.ITypeReference.AsGenericTypeParameterReference
        {
            get { return null; }
        }
 
        Cci.INamespaceTypeReference Cci.ITypeReference.AsNamespaceTypeReference
        {
            get
            {
                Debug.Assert(this.IsDefinitionOrDistinct());
 
                if (AdaptedNamedTypeSymbol.IsDefinition &&
                    (object)AdaptedNamedTypeSymbol.ContainingType == null)
                {
                    return this;
                }
 
                return null;
            }
        }
 
        Cci.INamespaceTypeDefinition Cci.ITypeReference.AsNamespaceTypeDefinition(EmitContext context)
        {
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            Debug.Assert(this.IsDefinitionOrDistinct());
 
            if ((object)AdaptedNamedTypeSymbol.ContainingType == null &&
                AdaptedNamedTypeSymbol.IsDefinition &&
                AdaptedNamedTypeSymbol.ContainingModule == moduleBeingBuilt.SourceModule)
            {
                return this;
            }
 
            return null;
        }
 
        Cci.INestedTypeReference Cci.ITypeReference.AsNestedTypeReference
        {
            get
            {
                if ((object)AdaptedNamedTypeSymbol.ContainingType != null)
                {
                    return this;
                }
 
                return null;
            }
        }
 
        Cci.INestedTypeDefinition Cci.ITypeReference.AsNestedTypeDefinition(EmitContext context)
        {
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            return AsNestedTypeDefinitionImpl(moduleBeingBuilt);
        }
 
        private Cci.INestedTypeDefinition AsNestedTypeDefinitionImpl(PEModuleBuilder moduleBeingBuilt)
        {
            Debug.Assert(this.IsDefinitionOrDistinct());
 
            if ((object)AdaptedNamedTypeSymbol.ContainingType != null &&
                AdaptedNamedTypeSymbol.IsDefinition &&
                AdaptedNamedTypeSymbol.ContainingModule == moduleBeingBuilt.SourceModule)
            {
                return this;
            }
 
            return null;
        }
 
        Cci.ISpecializedNestedTypeReference Cci.ITypeReference.AsSpecializedNestedTypeReference
        {
            get
            {
                Debug.Assert(this.IsDefinitionOrDistinct());
 
                if (!AdaptedNamedTypeSymbol.IsDefinition &&
                    (AdaptedNamedTypeSymbol.Arity == 0 || PEModuleBuilder.IsGenericType(AdaptedNamedTypeSymbol.ContainingType)))
                {
                    Debug.Assert((object)AdaptedNamedTypeSymbol.ContainingType != null &&
                            PEModuleBuilder.IsGenericType(AdaptedNamedTypeSymbol.ContainingType));
                    return this;
                }
 
                return null;
            }
        }
 
        Cci.ITypeDefinition Cci.ITypeReference.AsTypeDefinition(EmitContext context)
        {
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            return AsTypeDefinitionImpl(moduleBeingBuilt);
        }
 
        private Cci.ITypeDefinition AsTypeDefinitionImpl(PEModuleBuilder moduleBeingBuilt)
        {
            Debug.Assert(this.IsDefinitionOrDistinct());
 
            if (AdaptedNamedTypeSymbol.IsDefinition && // can't be generic instantiation
                AdaptedNamedTypeSymbol.ContainingModule == moduleBeingBuilt.SourceModule) // must be declared in the module we are building
            {
                return this;
            }
 
            return null;
        }
 
        void Cci.IReference.Dispatch(Cci.MetadataVisitor visitor)
        {
            throw ExceptionUtilities.Unreachable();
            //We've not yet discovered a scenario in which we need this.
            //If you're hitting this exception. Uncomment the code below
            //and add a unit test.
#if false
            Module moduleBeingBuilt = (Module)visitor.Context;
 
            Debug.Assert(this.IsDefinitionOrDistinct());
 
            if (!this.IsDefinition)
            {
                if (this.Arity > 0)
                {
                    Debug.Assert(((ITypeReference)this).AsGenericTypeInstanceReference != null);
                    visitor.Visit((IGenericTypeInstanceReference)this);
                }
                else
                {
                    Debug.Assert(((ITypeReference)this).AsSpecializedNestedTypeReference != null);
                    visitor.Visit((ISpecializedNestedTypeReference)this);
                }
            }
            else
            {
                bool asDefinition = (this.ContainingModule == moduleBeingBuilt.SourceModule);
 
                if (this.ContainingType == null)
                {
                    if (asDefinition)
                    {
                        Debug.Assert(((ITypeReference)this).AsNamespaceTypeDefinition(moduleBeingBuilt) != null);
                        visitor.Visit((INamespaceTypeDefinition)this);
                    }
                    else
                    {
                        Debug.Assert(((ITypeReference)this).AsNamespaceTypeReference != null);
                        visitor.Visit((INamespaceTypeReference)this);
                    }
                }
                else
                {
                    if (asDefinition)
                    {
                        Debug.Assert(((ITypeReference)this).AsNestedTypeDefinition(moduleBeingBuilt) != null);
                        visitor.Visit((INestedTypeDefinition)this);
                    }
                    else
                    {
                        Debug.Assert(((ITypeReference)this).AsNestedTypeReference != null);
                        visitor.Visit((INestedTypeReference)this);
                    }
                }
            }
#endif
        }
 
        Cci.IDefinition Cci.IReference.AsDefinition(EmitContext context)
        {
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            return AsTypeDefinitionImpl(moduleBeingBuilt);
        }
 
        Cci.ITypeReference Cci.ITypeDefinition.GetBaseClass(EmitContext context)
        {
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            Debug.Assert(((Cci.ITypeReference)this).AsTypeDefinition(context) != null);
            NamedTypeSymbol baseType = AdaptedNamedTypeSymbol.BaseTypeNoUseSiteDiagnostics;
 
            if (AdaptedNamedTypeSymbol.IsScriptClass)
            {
                // although submission and scripts semantically doesn't have a base we need to emit one into metadata:
                Debug.Assert((object)baseType == null);
                baseType = AdaptedNamedTypeSymbol.ContainingAssembly.GetSpecialType(Microsoft.CodeAnalysis.SpecialType.System_Object);
            }
 
            return ((object)baseType != null) ? moduleBeingBuilt.Translate(baseType,
                                                                   syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode,
                                                                   diagnostics: context.Diagnostics) : null;
        }
 
        IEnumerable<Cci.IEventDefinition> Cci.ITypeDefinition.GetEvents(EmitContext context)
        {
            CheckDefinitionInvariant();
            foreach (EventSymbol e in AdaptedNamedTypeSymbol.GetEventsToEmit())
            {
                IEventDefinition definition = e.GetCciAdapter();
 
                // If any accessor should be included, then the event should be included too
                if (definition.ShouldInclude(context) || !definition.GetAccessors(context).IsEmpty())
                {
                    yield return definition;
                }
            }
        }
 
        IEnumerable<Cci.MethodImplementation> Cci.ITypeDefinition.GetExplicitImplementationOverrides(EmitContext context)
        {
            CheckDefinitionInvariant();
 
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            foreach (var member in AdaptedNamedTypeSymbol.GetMembers())
            {
                if (member.Kind == SymbolKind.Method)
                {
                    var method = (MethodSymbol)member;
                    Debug.Assert((object)method.PartialDefinitionPart == null); // must be definition
 
                    var explicitImplementations = method.ExplicitInterfaceImplementations;
                    if (explicitImplementations.Length != 0)
                    {
                        var adapter = method.GetCciAdapter();
 
                        foreach (var implemented in method.ExplicitInterfaceImplementations)
                        {
                            yield return new Microsoft.Cci.MethodImplementation(adapter, moduleBeingBuilt.TranslateOverriddenMethodReference(implemented, (CSharpSyntaxNode)context.SyntaxNode, context.Diagnostics));
                        }
                    }
 
                    if (AdaptedNamedTypeSymbol.IsInterface)
                    {
                        continue;
                    }
 
                    if (method.RequiresExplicitOverride(out _))
                    {
                        // If C# and the runtime don't agree on the overridden method, then 
                        // we will mark the method as newslot (see MethodSymbolAdapter) and
                        // specify the override explicitly.
                        // This affects accessors - C# ignores method interactions
                        // between accessors and non-accessors, whereas the runtime does not.
                        // It also affects covariant returns - C# ignores the return type in
                        // determining if one method overrides another, while the runtime considers
                        // the return type part of the signature.
                        yield return new Microsoft.Cci.MethodImplementation(method.GetCciAdapter(), moduleBeingBuilt.TranslateOverriddenMethodReference(method.OverriddenMethod, (CSharpSyntaxNode)context.SyntaxNode, context.Diagnostics));
                    }
                    else if (method.MethodKind == MethodKind.Destructor && AdaptedNamedTypeSymbol.SpecialType != SpecialType.System_Object)
                    {
                        // New in Roslyn: all destructors explicitly override (or are) System.Object.Finalize so that
                        // they are guaranteed to be runtime finalizers.  As a result, it is no longer possible to create
                        // a destructor that will never be invoked by the runtime.
                        // NOTE: If System.Object doesn't contain a destructor, you're on your own - this destructor may
                        // or not be called by the runtime.
                        TypeSymbol objectType = AdaptedNamedTypeSymbol.DeclaringCompilation.GetSpecialType(CodeAnalysis.SpecialType.System_Object);
                        foreach (Symbol objectMember in objectType.GetMembers(WellKnownMemberNames.DestructorName))
                        {
                            MethodSymbol objectMethod = objectMember as MethodSymbol;
                            if ((object)objectMethod != null && objectMethod.MethodKind == MethodKind.Destructor)
                            {
                                yield return new Microsoft.Cci.MethodImplementation(method.GetCciAdapter(), moduleBeingBuilt.TranslateOverriddenMethodReference(objectMethod, (CSharpSyntaxNode)context.SyntaxNode, context.Diagnostics));
                            }
                        }
                    }
                }
            }
 
            if (AdaptedNamedTypeSymbol.IsInterface)
            {
                yield break;
            }
 
            if (AdaptedNamedTypeSymbol is SourceMemberContainerTypeSymbol container)
            {
                var interfaces = container.GetInterfacesToEmit();
 
                foreach ((MethodSymbol body, MethodSymbol implemented) in container.GetSynthesizedExplicitImplementations(cancellationToken: default).MethodImpls)
                {
                    Debug.Assert(body.ContainingType == (object)container);
 
                    // Avoid emitting duplicate methodimpl entries (e.g., when the class implements the same interface twice with different nullability).
                    if (!interfaces.Contains(implemented.ContainingType, SymbolEqualityComparer.ConsiderEverything))
                    {
                        continue;
                    }
 
                    yield return new Microsoft.Cci.MethodImplementation(body.GetCciAdapter(), moduleBeingBuilt.TranslateOverriddenMethodReference(implemented, (CSharpSyntaxNode)context.SyntaxNode, context.Diagnostics));
                }
            }
 
            var syntheticMethods = moduleBeingBuilt.GetSynthesizedMethods(AdaptedNamedTypeSymbol);
            if (syntheticMethods != null)
            {
                foreach (var m in syntheticMethods)
                {
                    var method = m.GetInternalSymbol() as MethodSymbol;
                    if ((object)method != null)
                    {
                        Debug.Assert((object)method.PartialDefinitionPart == null); // must be definition
 
                        foreach (var implemented in method.ExplicitInterfaceImplementations)
                        {
                            yield return new Microsoft.Cci.MethodImplementation(m, moduleBeingBuilt.TranslateOverriddenMethodReference(implemented, (CSharpSyntaxNode)context.SyntaxNode, context.Diagnostics));
                        }
 
                        Debug.Assert(!method.RequiresExplicitOverride(out _));
                    }
                }
            }
        }
 
        IEnumerable<Cci.IFieldDefinition> Cci.ITypeDefinition.GetFields(EmitContext context)
        {
            CheckDefinitionInvariant();
 
            // All fields in a struct should be emitted
            bool isStruct = AdaptedNamedTypeSymbol.IsStructType();
 
            foreach (var f in AdaptedNamedTypeSymbol.GetFieldsToEmit())
            {
                Debug.Assert((object)(f.TupleUnderlyingField ?? f) == f);
                Debug.Assert(!(f is TupleErrorFieldSymbol));
                if (isStruct || f.GetCciAdapter().ShouldInclude(context))
                {
                    yield return f.GetCciAdapter();
                }
            }
 
            IEnumerable<Cci.IFieldDefinition> generated = ((PEModuleBuilder)context.Module).GetSynthesizedFields(AdaptedNamedTypeSymbol);
 
            if (generated != null)
            {
                foreach (var f in generated)
                {
                    if (isStruct || f.ShouldInclude(context))
                    {
                        yield return f;
                    }
                }
            }
        }
 
        IEnumerable<Cci.IGenericTypeParameter> Cci.ITypeDefinition.GenericParameters
        {
            get
            {
                CheckDefinitionInvariant();
 
                foreach (var t in AdaptedNamedTypeSymbol.TypeParameters)
                {
                    yield return t.GetCciAdapter();
                }
            }
        }
 
        ushort Cci.ITypeDefinition.GenericParameterCount
        {
            get
            {
                CheckDefinitionInvariant();
 
                return GenericParameterCountImpl;
            }
        }
 
        private ushort GenericParameterCountImpl
        {
            get { return (ushort)AdaptedNamedTypeSymbol.Arity; }
        }
 
        IEnumerable<Cci.TypeReferenceWithAttributes> Cci.ITypeDefinition.Interfaces(EmitContext context)
        {
            Debug.Assert(((Cci.ITypeReference)this).AsTypeDefinition(context) != null);
 
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            foreach (NamedTypeSymbol @interface in AdaptedNamedTypeSymbol.GetInterfacesToEmit())
            {
                var typeRef = moduleBeingBuilt.Translate(
                    @interface,
                    syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode,
                    diagnostics: context.Diagnostics,
                    fromImplements: true);
 
                var type = TypeWithAnnotations.Create(@interface);
                yield return type.GetTypeRefWithAttributes(
                    moduleBeingBuilt,
                    declaringSymbol: AdaptedNamedTypeSymbol,
                    typeRef);
            }
        }
 
        bool Cci.ITypeDefinition.IsAbstract
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.IsMetadataAbstract;
            }
        }
 
        bool Cci.ITypeDefinition.IsBeforeFieldInit
        {
            get
            {
                CheckDefinitionInvariant();
 
                switch (AdaptedNamedTypeSymbol.TypeKind)
                {
                    case TypeKind.Enum:
                    case TypeKind.Delegate:
                        return false;
                }
 
                //apply the beforefieldinit attribute unless there is an explicitly specified static constructor
                foreach (var member in AdaptedNamedTypeSymbol.GetMembers(WellKnownMemberNames.StaticConstructorName))
                {
                    if (!member.IsImplicitlyDeclared)
                    {
                        return false;
                    }
                }
 
                return true;
            }
        }
 
        bool Cci.ITypeDefinition.IsComObject
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.IsComImport;
            }
        }
 
        bool Cci.ITypeDefinition.IsGeneric
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.Arity != 0;
            }
        }
 
        bool Cci.ITypeDefinition.IsInterface
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.IsInterface;
            }
        }
 
        bool Cci.ITypeDefinition.IsDelegate
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.IsDelegateType();
            }
        }
 
        bool Cci.ITypeDefinition.IsRuntimeSpecial
        {
            get
            {
                CheckDefinitionInvariant();
                return false;
            }
        }
 
        bool Cci.ITypeDefinition.IsSerializable
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.IsSerializable;
            }
        }
 
        bool Cci.ITypeDefinition.IsSpecialName
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.HasSpecialName;
            }
        }
 
        bool Cci.ITypeDefinition.IsWindowsRuntimeImport
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.IsWindowsRuntimeImport;
            }
        }
 
        bool Cci.ITypeDefinition.IsSealed
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.IsMetadataSealed;
            }
        }
 
        IEnumerable<Cci.IMethodDefinition> Cci.ITypeDefinition.GetMethods(EmitContext context)
        {
            CheckDefinitionInvariant();
 
            // All constructors in attributes should be emitted.
            // Don't compute IsAttributeType if IncludePrivateMembers is true, as we'll include it anyway.
            bool alwaysIncludeConstructors = context.IncludePrivateMembers || AdaptedNamedTypeSymbol.DeclaringCompilation.IsAttributeType(AdaptedNamedTypeSymbol);
 
            foreach (var method in AdaptedNamedTypeSymbol.GetMethodsToEmit())
            {
                Debug.Assert((object)method != null);
 
                if ((alwaysIncludeConstructors && method.MethodKind == MethodKind.Constructor) || method.GetCciAdapter().ShouldInclude(context))
                {
                    yield return method.GetCciAdapter();
                }
            }
 
            IEnumerable<Cci.IMethodDefinition> generated = ((PEModuleBuilder)context.Module).GetSynthesizedMethods(AdaptedNamedTypeSymbol);
 
            if (generated != null)
            {
                foreach (var m in generated)
                {
                    if ((alwaysIncludeConstructors && m.IsConstructor) || m.ShouldInclude(context))
                    {
                        yield return m;
                    }
                }
            }
        }
 
        IEnumerable<Cci.INestedTypeDefinition> Cci.ITypeDefinition.GetNestedTypes(EmitContext context)
        {
            CheckDefinitionInvariant();
 
            foreach (NamedTypeSymbol type in AdaptedNamedTypeSymbol.GetTypeMembers()) // Ordered.
            {
                yield return type.GetCciAdapter();
            }
 
            IEnumerable<Cci.INestedTypeDefinition> generated = ((PEModuleBuilder)context.Module).GetSynthesizedTypes(AdaptedNamedTypeSymbol);
 
            if (generated != null)
            {
                foreach (var t in generated)
                {
                    yield return t;
                }
            }
        }
 
        IEnumerable<Cci.IPropertyDefinition> Cci.ITypeDefinition.GetProperties(EmitContext context)
        {
            CheckDefinitionInvariant();
 
            foreach (PropertySymbol property in AdaptedNamedTypeSymbol.GetPropertiesToEmit())
            {
                Debug.Assert((object)property != null);
                IPropertyDefinition definition = property.GetCciAdapter();
                // If any accessor should be included, then the property should be included too
                if (definition.ShouldInclude(context) || !definition.GetAccessors(context).IsEmpty())
                {
                    yield return definition;
                }
            }
 
            IEnumerable<Cci.IPropertyDefinition> generated = ((PEModuleBuilder)context.Module).GetSynthesizedProperties(AdaptedNamedTypeSymbol);
 
            if (generated != null)
            {
                foreach (IPropertyDefinition m in generated)
                {
                    if (m.ShouldInclude(context) || !m.GetAccessors(context).IsEmpty())
                    {
                        yield return m;
                    }
                }
            }
        }
 
        bool Cci.ITypeDefinition.HasDeclarativeSecurity
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.HasDeclarativeSecurity;
            }
        }
 
        IEnumerable<Cci.SecurityAttribute> Cci.ITypeDefinition.SecurityAttributes
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.GetSecurityInformation() ?? SpecializedCollections.EmptyEnumerable<Cci.SecurityAttribute>();
            }
        }
 
        ushort Cci.ITypeDefinition.Alignment
        {
            get
            {
                CheckDefinitionInvariant();
                var layout = AdaptedNamedTypeSymbol.Layout;
                return (ushort)layout.Alignment;
            }
        }
 
        LayoutKind Cci.ITypeDefinition.Layout
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.Layout.Kind;
            }
        }
 
        uint Cci.ITypeDefinition.SizeOf
        {
            get
            {
                CheckDefinitionInvariant();
                return (uint)AdaptedNamedTypeSymbol.Layout.Size;
            }
        }
 
        CharSet Cci.ITypeDefinition.StringFormat
        {
            get
            {
                CheckDefinitionInvariant();
                return AdaptedNamedTypeSymbol.MarshallingCharSet;
            }
        }
 
        ushort Cci.INamedTypeReference.GenericParameterCount
        {
            get { return GenericParameterCountImpl; }
        }
 
        bool Cci.INamedTypeReference.MangleName
        {
            get
            {
                return AdaptedNamedTypeSymbol.MangleName;
            }
        }
 
#nullable enable
        string? Cci.INamedTypeReference.AssociatedFileIdentifier
        {
            get
            {
                return AdaptedNamedTypeSymbol.GetFileLocalTypeMetadataNamePrefix();
            }
        }
#nullable disable
 
        string Cci.INamedEntity.Name
        {
            get
            {
                string unsuffixedName = AdaptedNamedTypeSymbol.Name;
 
                // CLR generally allows names with dots, however some APIs like IMetaDataImport
                // can only return full type names combined with namespaces. 
                // see: http://msdn.microsoft.com/en-us/library/ms230143.aspx (IMetaDataImport::GetTypeDefProps)
                // When working with such APIs, names with dots become ambiguous since metadata 
                // consumer cannot figure where namespace ends and actual type name starts.
                // Therefore it is a good practice to avoid type names with dots.
                // Exception: The EE copies type names from metadata, which may contain dots already.
                Debug.Assert(AdaptedNamedTypeSymbol.IsErrorType() ||
                    !unsuffixedName.Contains(".") ||
                    AdaptedNamedTypeSymbol.OriginalDefinition is PENamedTypeSymbol, "type name contains dots: " + unsuffixedName);
 
                return unsuffixedName;
            }
        }
 
        Cci.IUnitReference Cci.INamespaceTypeReference.GetUnit(EmitContext context)
        {
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            Debug.Assert(((Cci.ITypeReference)this).AsNamespaceTypeReference != null);
            return moduleBeingBuilt.Translate(AdaptedNamedTypeSymbol.ContainingModule, context.Diagnostics);
        }
 
        string Cci.INamespaceTypeReference.NamespaceName
        {
            get
            {
                // INamespaceTypeReference is a type contained in a namespace
                // if this method is called for a nested type, we are in big trouble.
                Debug.Assert(((Cci.ITypeReference)this).AsNamespaceTypeReference != null);
 
                return AdaptedNamedTypeSymbol.ContainingNamespace.QualifiedName;
            }
        }
 
        bool Cci.INamespaceTypeDefinition.IsPublic
        {
            get
            {
                Debug.Assert((object)AdaptedNamedTypeSymbol.ContainingType == null && AdaptedNamedTypeSymbol.ContainingModule is SourceModuleSymbol);
 
                return AdaptedNamedTypeSymbol.MetadataVisibility == Cci.TypeMemberVisibility.Public;
            }
        }
 
        Cci.ITypeReference Cci.ITypeMemberReference.GetContainingType(EmitContext context)
        {
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            Debug.Assert(((Cci.ITypeReference)this).AsNestedTypeReference != null);
 
            Debug.Assert(this.IsDefinitionOrDistinct());
 
            return moduleBeingBuilt.Translate(AdaptedNamedTypeSymbol.ContainingType,
                                              syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode,
                                              diagnostics: context.Diagnostics,
                                              needDeclaration: AdaptedNamedTypeSymbol.IsDefinition);
        }
 
        Cci.ITypeDefinition Cci.ITypeDefinitionMember.ContainingTypeDefinition
        {
            get
            {
                Debug.Assert((object)AdaptedNamedTypeSymbol.ContainingType != null);
                CheckDefinitionInvariant();
 
                return AdaptedNamedTypeSymbol.ContainingType.GetCciAdapter();
            }
        }
 
        Cci.TypeMemberVisibility Cci.ITypeDefinitionMember.Visibility
        {
            get
            {
                Debug.Assert((object)AdaptedNamedTypeSymbol.ContainingType != null);
                CheckDefinitionInvariant();
 
                return AdaptedNamedTypeSymbol.MetadataVisibility;
            }
        }
 
        ImmutableArray<Cci.ITypeReference> Cci.IGenericTypeInstanceReference.GetGenericArguments(EmitContext context)
        {
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
            var builder = ArrayBuilder<Microsoft.Cci.ITypeReference>.GetInstance();
            Debug.Assert(((Cci.ITypeReference)this).AsGenericTypeInstanceReference != null);
 
            var arguments = AdaptedNamedTypeSymbol.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics;
 
            for (int i = 0; i < arguments.Length; i++)
            {
                var arg = moduleBeingBuilt.Translate(arguments[i].Type, syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode, diagnostics: context.Diagnostics);
                var modifiers = arguments[i].CustomModifiers;
                if (!modifiers.IsDefaultOrEmpty)
                {
                    arg = new Cci.ModifiedTypeReference(arg, ImmutableArray<Cci.ICustomModifier>.CastUp(modifiers));
                }
 
                builder.Add(arg);
            }
 
            return builder.ToImmutableAndFree();
        }
 
        Cci.INamedTypeReference Cci.IGenericTypeInstanceReference.GetGenericType(EmitContext context)
        {
            Debug.Assert(((Cci.ITypeReference)this).AsGenericTypeInstanceReference != null);
            return GenericTypeImpl(context);
        }
 
        private Cci.INamedTypeReference GenericTypeImpl(EmitContext context)
        {
            PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module;
            return moduleBeingBuilt.Translate(AdaptedNamedTypeSymbol.OriginalDefinition, syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode,
                                              diagnostics: context.Diagnostics, needDeclaration: true);
        }
 
        Cci.INestedTypeReference Cci.ISpecializedNestedTypeReference.GetUnspecializedVersion(EmitContext context)
        {
            Debug.Assert(((Cci.ITypeReference)this).AsSpecializedNestedTypeReference != null);
            var result = GenericTypeImpl(context).AsNestedTypeReference;
 
            Debug.Assert(result != null);
            return result;
        }
    }
 
    internal partial class NamedTypeSymbol
    {
#if DEBUG
        private NamedTypeSymbolAdapter _lazyAdapter;
 
        protected sealed override SymbolAdapter GetCciAdapterImpl() => GetCciAdapter();
 
        internal new NamedTypeSymbolAdapter GetCciAdapter()
        {
            Debug.Assert(this is not SynthesizedPrivateImplementationDetailsType);
 
            if (_lazyAdapter is null)
            {
                return InterlockedOperations.Initialize(ref _lazyAdapter, new NamedTypeSymbolAdapter(this));
            }
 
            return _lazyAdapter;
        }
#else
        internal NamedTypeSymbol AdaptedNamedTypeSymbol => this;
 
        internal new NamedTypeSymbol GetCciAdapter()
        {
            return this;
        }
#endif
 
        internal virtual IEnumerable<EventSymbol> GetEventsToEmit()
        {
            CheckDefinitionInvariant();
 
            foreach (var m in this.GetMembers())
            {
                if (m.Kind == SymbolKind.Event)
                {
                    yield return (EventSymbol)m;
                }
            }
        }
 
        internal abstract IEnumerable<FieldSymbol> GetFieldsToEmit();
 
        /// <summary>
        /// Gets the set of interfaces to emit on this type. This set can be different from the set returned by Interfaces property.
        /// </summary>
        internal abstract ImmutableArray<NamedTypeSymbol> GetInterfacesToEmit();
 
        protected ImmutableArray<NamedTypeSymbol> CalculateInterfacesToEmit()
        {
            Debug.Assert(this.IsDefinition);
            Debug.Assert(this.ContainingModule is SourceModuleSymbol);
 
            ArrayBuilder<NamedTypeSymbol> builder = ArrayBuilder<NamedTypeSymbol>.GetInstance();
            HashSet<NamedTypeSymbol> seen = null;
            InterfacesVisit(this, builder, ref seen);
            return builder.ToImmutableAndFree();
        }
 
        /// <summary>
        /// Add the type to the builder and then recurse on its interfaces.
        /// </summary>
        /// <remarks>
        /// Pre-order depth-first search.
        /// </remarks>
        private static void InterfacesVisit(NamedTypeSymbol namedType, ArrayBuilder<NamedTypeSymbol> builder, ref HashSet<NamedTypeSymbol> seen)
        {
            // It's not clear how important the order of these interfaces is, but Dev10
            // maintains pre-order depth-first/declaration order, so we probably should as well.
            // That's why we're not using InterfacesAndTheirBaseInterfaces - it's an unordered set.
            foreach (NamedTypeSymbol @interface in namedType.InterfacesNoUseSiteDiagnostics())
            {
                if (seen == null)
                {
                    // Don't allocate until we see at least one interface.
                    seen = new HashSet<NamedTypeSymbol>(Symbols.SymbolEqualityComparer.CLRSignature);
                }
                if (seen.Add(@interface))
                {
                    builder.Add(@interface);
                    InterfacesVisit(@interface, builder, ref seen);
                }
            }
        }
 
        internal virtual bool IsMetadataAbstract
        {
            get
            {
                CheckDefinitionInvariant();
                return this.IsAbstract || this.IsStatic;
            }
        }
 
        internal virtual bool IsMetadataSealed
        {
            get
            {
                CheckDefinitionInvariant();
                return this.IsSealed || this.IsStatic;
            }
        }
 
        /// <summary>
        /// To represent a gap in interface's v-table null value should be returned in the appropriate position,
        /// unless the gap has a symbol (happens if it is declared in source, for example).
        /// </summary>
        internal virtual IEnumerable<MethodSymbol> GetMethodsToEmit()
        {
            CheckDefinitionInvariant();
 
            foreach (var m in this.GetMembers())
            {
                if (m.Kind == SymbolKind.Method)
                {
                    var method = (MethodSymbol)m;
                    if (method.ShouldEmit())
                    {
                        yield return method;
                    }
                }
            }
        }
 
        internal virtual IEnumerable<PropertySymbol> GetPropertiesToEmit()
        {
            CheckDefinitionInvariant();
 
            foreach (var m in this.GetMembers())
            {
                if (m.Kind == SymbolKind.Property)
                {
                    yield return (PropertySymbol)m;
                }
            }
        }
    }
 
#if DEBUG
    internal partial class NamedTypeSymbolAdapter
    {
        internal NamedTypeSymbolAdapter(NamedTypeSymbol underlyingNamedTypeSymbol)
        {
            AdaptedNamedTypeSymbol = underlyingNamedTypeSymbol;
 
            if (underlyingNamedTypeSymbol is NativeIntegerTypeSymbol)
            {
                // Emit should use underlying symbol only.
                throw ExceptionUtilities.Unreachable();
            }
        }
 
        internal sealed override Symbol AdaptedSymbol => AdaptedNamedTypeSymbol;
        internal NamedTypeSymbol AdaptedNamedTypeSymbol { get; }
    }
#endif
}