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