private static void GrowPool(ref TypeParameterSymbol[] parameterPool, int count, bool hasValueTypeConstraint)
        {
            var initialPool = parameterPool;

            while (count > initialPool.Length)
            {
                var newPoolSize = ((count + 0x0F) & ~0xF); // grow in increments of 16
                var newPool     = new TypeParameterSymbol[newPoolSize];

                Array.Copy(initialPool, newPool, initialPool.Length);

                for (int i = initialPool.Length; i < newPool.Length; i++)
                {
                    newPool[i] = new IndexedTypeParameterSymbolForOverriding(i, hasValueTypeConstraint);
                }

                Interlocked.CompareExchange(ref parameterPool, newPool, initialPool);

                // repeat if race condition occurred and someone else resized the pool before us
                // and the new pool is still too small
                initialPool = parameterPool;
            }
        }
        public bool Equals(Symbol member1, Symbol member2)
        {
            if (ReferenceEquals(member1, member2))
            {
                return(true);
            }

            if ((object)member1 == null || (object)member2 == null || member1.Kind != member2.Kind)
            {
                return(false);
            }

            bool sawInterfaceInName1 = false;
            bool sawInterfaceInName2 = false;

            if (_considerName)
            {
                string name1 = ExplicitInterfaceHelpers.GetMemberNameWithoutInterfaceName(member1.Name);
                string name2 = ExplicitInterfaceHelpers.GetMemberNameWithoutInterfaceName(member2.Name);

                sawInterfaceInName1 = name1 != member1.Name;
                sawInterfaceInName2 = name2 != member2.Name;

                if (name1 != name2)
                {
                    return(false);
                }
            }

            // NB: up to, and including, this check, we have not actually forced the (type) parameters
            // to be expanded - we're only using the counts.
            int arity = member1.GetMemberArity();

            if ((arity != member2.GetMemberArity()) ||
                (member1.GetParameterCount() != member2.GetParameterCount()))
            {
                return(false);
            }

            TypeMap typeMap1;
            TypeMap typeMap2;

            if (arity > 0 && _useSpecialHandlingForNullableTypes)
            {
                // We need this special handling in order to avoid forcing resolution of nullable types
                // in signature of an overriding member while we are looking for a matching overridden member.
                // Doing the resolution in the original signature can send us into an infinite cycle because
                // constraints must be inherited from the member we are looking for.
                // It is important to ensure that the fact whether an indexed type parameter we are about to use
                // is a reference type is inherited from the corresponding type parameter of the possibly overridden
                // member (which is member2 when _useSpecialHandlingForNullableTypes is true). This will ensure
                // proper resolution for nullable types in substituted signature of member1, ensuring proper
                // comparison of types across both members.
                ArrayBuilder <TypeParameterSymbol> builder = ArrayBuilder <TypeParameterSymbol> .GetInstance(arity);

                var typeParameters2 = member2.GetMemberTypeParameters();

                for (int i = arity - 1; i >= 0; i--)
                {
                    builder.Add(IndexedTypeParameterSymbolForOverriding.GetTypeParameter(i, typeParameters2[i].IsValueType));
                }

                var indexed = builder.ToImmutableAndFree();

                typeMap1 = new TypeMap(member1.GetMemberTypeParameters(), indexed, true);
                typeMap2 = new TypeMap(typeParameters2, indexed, true);
            }
            else
            {
                typeMap1 = GetTypeMap(member1);
                typeMap2 = GetTypeMap(member2);
            }

            if (_considerReturnType && !HaveSameReturnTypes(member1, typeMap1, member2, typeMap2, _typeComparison))
            {
                return(false);
            }

            if (member1.GetParameterCount() > 0 && !HaveSameParameterTypes(member1.GetParameters(), typeMap1, member2.GetParameters(), typeMap2,
                                                                           _considerRefKindDifferences, _typeComparison))
            {
                return(false);
            }

            if (_considerCallingConvention)
            {
                if (GetCallingConvention(member1) != GetCallingConvention(member2))
                {
                    return(false);
                }
            }
            else
            {
                if (IsVarargMethod(member1) != IsVarargMethod(member2))
                {
                    return(false);
                }
            }

            if (_considerExplicitlyImplementedInterfaces)
            {
                if (sawInterfaceInName1 != sawInterfaceInName2)
                {
                    return(false);
                }

                // The purpose of this check is to determine whether the interface parts of the member names agree,
                // but to do so using robust symbolic checks, rather than syntactic ones.  Therefore, if neither member
                // name contains an interface name, this check is not relevant.
                // Phrased differently, the explicitly implemented interface is not part of the signature unless it's
                // part of the name.
                if (sawInterfaceInName1)
                {
                    Debug.Assert(sawInterfaceInName2);

                    // May avoid realizing interface members.
                    if (member1.IsExplicitInterfaceImplementation() != member2.IsExplicitInterfaceImplementation())
                    {
                        return(false);
                    }

                    // By comparing symbols, rather than syntax, we gain the flexibility of ignoring whitespace
                    // and gracefully accepting multiple names for the same (or equivalent) types (e.g. "I<int>.M"
                    // vs "I<System.Int32>.M"), but we lose the connection with the name.  For example, in metadata,
                    // a method name "I.M" could have nothing to do with "I" but explicitly implement interface "I2".
                    // We will behave as if the method was really named "I2.M".  Furthermore, in metadata, a method
                    // can explicitly implement more than one interface method, in which case it doesn't really
                    // make sense to pretend that all of them are part of the signature.

                    var explicitInterfaceImplementations1 = member1.GetExplicitInterfaceImplementations();
                    var explicitInterfaceImplementations2 = member2.GetExplicitInterfaceImplementations();

                    if (!explicitInterfaceImplementations1.SetEquals(explicitInterfaceImplementations2, EqualityComparer <Symbol> .Default))
                    {
                        return(false);
                    }
                }
            }

            return(!_considerTypeConstraints || HaveSameConstraints(member1, typeMap1, member2, typeMap2));
        }