File: Emitter\Model\TypeParameterSymbolAdapter.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.Reflection.Metadata;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Roslyn.Utilities;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Emit;
using System.Collections.Immutable;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    internal partial class
#if DEBUG
        TypeParameterSymbolAdapter : SymbolAdapter,
#else
        TypeParameterSymbol :
#endif 
        Cci.IGenericParameterReference,
        Cci.IGenericMethodParameterReference,
        Cci.IGenericTypeParameterReference,
        Cci.IGenericParameter,
        Cci.IGenericMethodParameter,
        Cci.IGenericTypeParameter
    {
        public bool IsEncDeleted
            => false;
 
        bool Cci.ITypeReference.IsEnum
        {
            get { return false; }
        }
 
        bool Cci.ITypeReference.IsValueType
        {
            get { return false; }
        }
 
        Cci.ITypeDefinition Cci.ITypeReference.GetResolvedType(EmitContext context)
        {
            return null;
        }
 
        Cci.PrimitiveTypeCode Cci.ITypeReference.TypeCode
        {
            get { return Cci.PrimitiveTypeCode.NotPrimitive; }
        }
 
        TypeDefinitionHandle Cci.ITypeReference.TypeDef
        {
            get { return default(TypeDefinitionHandle); }
        }
 
        Cci.IGenericMethodParameter Cci.IGenericParameter.AsGenericMethodParameter
        {
            get
            {
                CheckDefinitionInvariant();
 
                if (AdaptedTypeParameterSymbol.ContainingSymbol.Kind == SymbolKind.Method)
                {
                    return this;
                }
 
                return null;
            }
        }
 
        Cci.IGenericMethodParameterReference Cci.ITypeReference.AsGenericMethodParameterReference
        {
            get
            {
                Debug.Assert(AdaptedTypeParameterSymbol.IsDefinition);
 
                if (AdaptedTypeParameterSymbol.ContainingSymbol.Kind == SymbolKind.Method)
                {
                    return this;
                }
 
                return null;
            }
        }
 
        Cci.IGenericTypeInstanceReference Cci.ITypeReference.AsGenericTypeInstanceReference
        {
            get { return null; }
        }
 
        Cci.IGenericTypeParameter Cci.IGenericParameter.AsGenericTypeParameter
        {
            get
            {
                CheckDefinitionInvariant();
 
                if (AdaptedTypeParameterSymbol.ContainingSymbol.Kind == SymbolKind.NamedType)
                {
                    return this;
                }
 
                return null;
            }
        }
 
        Cci.IGenericTypeParameterReference Cci.ITypeReference.AsGenericTypeParameterReference
        {
            get
            {
                Debug.Assert(AdaptedTypeParameterSymbol.IsDefinition);
 
                if (AdaptedTypeParameterSymbol.ContainingSymbol.Kind == SymbolKind.NamedType)
                {
                    return this;
                }
 
                return null;
            }
        }
 
        Cci.INamespaceTypeDefinition Cci.ITypeReference.AsNamespaceTypeDefinition(EmitContext context)
        {
            return null;
        }
 
        Cci.INamespaceTypeReference Cci.ITypeReference.AsNamespaceTypeReference
        {
            get { return null; }
        }
 
        Cci.INestedTypeDefinition Cci.ITypeReference.AsNestedTypeDefinition(EmitContext context)
        {
            return null;
        }
 
        Cci.INestedTypeReference Cci.ITypeReference.AsNestedTypeReference
        {
            get { return null; }
        }
 
        Cci.ISpecializedNestedTypeReference Cci.ITypeReference.AsSpecializedNestedTypeReference
        {
            get { return null; }
        }
 
        Cci.ITypeDefinition Cci.ITypeReference.AsTypeDefinition(EmitContext context)
        {
            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
            Debug.Assert(this.IsDefinition);
 
            SymbolKind kind = this.ContainingSymbol.Kind;
 
            if (((Module)visitor.Context).SourceModule == this.ContainingModule)
            {
                if (kind == SymbolKind.NamedType)
                {
                    visitor.Visit((IGenericTypeParameter)this);
                }
                else if (kind == SymbolKind.Method)
                {
                    visitor.Visit((IGenericMethodParameter)this);
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
            else
            {
                if (kind == SymbolKind.NamedType)
                {
                    visitor.Visit((IGenericTypeParameterReference)this);
                }
                else if (kind == SymbolKind.Method)
                {
                    visitor.Visit((IGenericMethodParameterReference)this);
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
#endif
        }
 
        Cci.IDefinition Cci.IReference.AsDefinition(EmitContext context)
        {
            Debug.Assert(AdaptedTypeParameterSymbol.IsDefinition);
            return null;
        }
 
        string Cci.INamedEntity.Name
        {
            get { return AdaptedTypeParameterSymbol.MetadataName; }
        }
 
        ushort Cci.IParameterListEntry.Index
        {
            get
            {
                return (ushort)AdaptedTypeParameterSymbol.Ordinal;
            }
        }
 
        Cci.IMethodReference Cci.IGenericMethodParameterReference.DefiningMethod
        {
            get
            {
                Debug.Assert(AdaptedTypeParameterSymbol.IsDefinition);
                return ((MethodSymbol)AdaptedTypeParameterSymbol.ContainingSymbol).GetCciAdapter();
            }
        }
 
        Cci.ITypeReference Cci.IGenericTypeParameterReference.DefiningType
        {
            get
            {
                Debug.Assert(AdaptedTypeParameterSymbol.IsDefinition);
                return ((NamedTypeSymbol)AdaptedTypeParameterSymbol.ContainingSymbol).GetCciAdapter();
            }
        }
 
        IEnumerable<Cci.TypeReferenceWithAttributes> Cci.IGenericParameter.GetConstraints(EmitContext context)
        {
            var moduleBeingBuilt = (PEModuleBuilder)context.Module;
 
            var seenValueType = false;
            if (AdaptedTypeParameterSymbol.HasUnmanagedTypeConstraint)
            {
                var typeRef = moduleBeingBuilt.GetSpecialType(
                    SpecialType.System_ValueType,
                    syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode,
                    diagnostics: context.Diagnostics);
 
                var modifier = CSharpCustomModifier.CreateRequired(
                    moduleBeingBuilt.Compilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_UnmanagedType));
 
                // emit "(class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType" pattern as "unmanaged"
                yield return new Cci.TypeReferenceWithAttributes(new Cci.ModifiedTypeReference(typeRef, ImmutableArray.Create<Cci.ICustomModifier>(modifier)));
 
                // do not emit another one for Dev11 similarities
                seenValueType = true;
            }
 
            foreach (var type in AdaptedTypeParameterSymbol.ConstraintTypesNoUseSiteDiagnostics)
            {
                switch (type.SpecialType)
                {
                    case SpecialType.System_Object:
                        Debug.Assert(!type.NullableAnnotation.IsAnnotated());
                        break;
                    case SpecialType.System_ValueType:
                        seenValueType = true;
                        break;
                }
                var typeRef = moduleBeingBuilt.Translate(type.Type,
                                                            syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode,
                                                            diagnostics: context.Diagnostics);
 
                yield return type.GetTypeRefWithAttributes(
                                                            moduleBeingBuilt,
                                                            declaringSymbol: AdaptedTypeParameterSymbol,
                                                            typeRef);
            }
 
            if (AdaptedTypeParameterSymbol.HasValueTypeConstraint && !seenValueType)
            {
                // Add System.ValueType constraint to comply with Dev11 output
                var typeRef = moduleBeingBuilt.GetSpecialType(SpecialType.System_ValueType,
                                                                syntaxNodeOpt: (CSharpSyntaxNode)context.SyntaxNode,
                                                                diagnostics: context.Diagnostics);
 
                yield return new Cci.TypeReferenceWithAttributes(typeRef);
            }
        }
 
        bool Cci.IGenericParameter.MustBeReferenceType
        {
            get
            {
                return AdaptedTypeParameterSymbol.HasReferenceTypeConstraint;
            }
        }
 
        bool Cci.IGenericParameter.MustBeValueType
        {
            get
            {
                return AdaptedTypeParameterSymbol.HasValueTypeConstraint || AdaptedTypeParameterSymbol.HasUnmanagedTypeConstraint;
            }
        }
 
        bool Cci.IGenericParameter.AllowsRefLikeType
        {
            get
            {
                return AdaptedTypeParameterSymbol.AllowsRefLikeType;
            }
        }
 
        bool Cci.IGenericParameter.MustHaveDefaultConstructor
        {
            get
            {
                //  add constructor constraint for value type constrained 
                //  type parameters to comply with Dev11 output
                //  do this for "unmanaged" constraint too
                return AdaptedTypeParameterSymbol.HasConstructorConstraint || AdaptedTypeParameterSymbol.HasValueTypeConstraint || AdaptedTypeParameterSymbol.HasUnmanagedTypeConstraint;
            }
        }
 
        Cci.TypeParameterVariance Cci.IGenericParameter.Variance
        {
            get
            {
                switch (AdaptedTypeParameterSymbol.Variance)
                {
                    case VarianceKind.None:
                        return Cci.TypeParameterVariance.NonVariant;
                    case VarianceKind.In:
                        return Cci.TypeParameterVariance.Contravariant;
                    case VarianceKind.Out:
                        return Cci.TypeParameterVariance.Covariant;
                    default:
                        throw ExceptionUtilities.UnexpectedValue(AdaptedTypeParameterSymbol.Variance);
                }
            }
        }
 
        Cci.IMethodDefinition Cci.IGenericMethodParameter.DefiningMethod
        {
            get
            {
                CheckDefinitionInvariant();
                return ((MethodSymbol)AdaptedTypeParameterSymbol.ContainingSymbol).GetCciAdapter();
            }
        }
 
        Cci.ITypeDefinition Cci.IGenericTypeParameter.DefiningType
        {
            get
            {
                CheckDefinitionInvariant();
                return ((NamedTypeSymbol)AdaptedTypeParameterSymbol.ContainingSymbol).GetCciAdapter();
            }
        }
    }
 
    internal partial class TypeParameterSymbol
    {
#if DEBUG
        private TypeParameterSymbolAdapter _lazyAdapter;
 
        protected sealed override SymbolAdapter GetCciAdapterImpl() => GetCciAdapter();
 
        internal new TypeParameterSymbolAdapter GetCciAdapter()
        {
            if (_lazyAdapter is null)
            {
                return InterlockedOperations.Initialize(ref _lazyAdapter, new TypeParameterSymbolAdapter(this));
            }
 
            return _lazyAdapter;
        }
#else
        internal TypeParameterSymbol AdaptedTypeParameterSymbol => this;
 
        internal new TypeParameterSymbol GetCciAdapter()
        {
            return this;
        }
#endif
    }
 
#if DEBUG
    internal partial class TypeParameterSymbolAdapter
    {
        internal TypeParameterSymbolAdapter(TypeParameterSymbol underlyingTypeParameterSymbol)
        {
            AdaptedTypeParameterSymbol = underlyingTypeParameterSymbol;
        }
 
        internal sealed override Symbol AdaptedSymbol => AdaptedTypeParameterSymbol;
        internal TypeParameterSymbol AdaptedTypeParameterSymbol { get; }
    }
#endif
}