/// <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); } } }
// C# does not let you declare a type in which it would be possible for distinct base interfaces // to unify under some instantiations. But such ill-formed classes can come in through // metadata and be instantiated in C#. We check to see if that's happened. private static bool HasDuplicateInterfaces(NamedTypeSymbol type, ConsList <Symbol> basesBeingResolved) { // PERF: avoid instantiating all interfaces here // Ex: if class implements just IEnumerable<> and IComparable<> it cannot have conflicting implementations var array = type.OriginalDefinition.InterfacesNoUseSiteDiagnostics(basesBeingResolved); switch (array.Length) { case 0: case 1: // less than 2 interfaces return(false); case 2: if ((object)array[0].OriginalDefinition == array[1].OriginalDefinition) { break; } // two unrelated interfaces return(false); default: var set = new HashSet <NamedTypeSymbol>(ReferenceEqualityComparer.Instance); foreach (var i in array) { if (!set.Add(i.OriginalDefinition)) { goto hasRelatedInterfaces; } } // all interfaces are unrelated return(false); } // very rare case. // some implemented interfaces are related // will have to instantiate interfaces and check hasRelatedInterfaces: return(type.InterfacesNoUseSiteDiagnostics(basesBeingResolved).HasDuplicates(TypeSymbol.EqualsIgnoringDynamicComparer)); }
/// <summary> /// Accumulate diagnostics related to the variance safety of an interface. /// </summary> internal static void CheckInterfaceVarianceSafety(this NamedTypeSymbol interfaceType, DiagnosticBag diagnostics) { Debug.Assert((object)interfaceType != null && interfaceType.IsInterface); foreach (NamedTypeSymbol baseInterface in interfaceType.InterfacesNoUseSiteDiagnostics()) { IsVarianceUnsafe( baseInterface, requireOutputSafety: true, requireInputSafety: false, context: baseInterface, locationProvider: i => null, locationArg: baseInterface, diagnostics: diagnostics); } foreach (Symbol member in interfaceType.GetMembersUnordered()) { switch (member.Kind) { case SymbolKind.Method: if (!member.IsAccessor()) { CheckMethodVarianceSafety((MethodSymbol)member, diagnostics); } break; case SymbolKind.Property: CheckPropertyVarianceSafety((PropertySymbol)member, diagnostics); break; case SymbolKind.Event: CheckEventVarianceSafety((EventSymbol)member, diagnostics); break; case SymbolKind.NamedType: CheckNestedTypeVarianceSafety((NamedTypeSymbol)member, diagnostics); break; } } }
// C# does not let you declare a type in which it would be possible for distinct base interfaces // to unify under some instantiations. But such ill-formed classes can come in through // metadata and be instantiated in C#. We check to see if that's happened. private static bool HasDuplicateInterfaces(NamedTypeSymbol type, ConsList<Symbol> basesBeingResolved) { // PERF: avoid instantiating all interfaces here // Ex: if class implements just IEnumerable<> and IComparable<> it cannot have conflicting implementations var array = type.OriginalDefinition.InterfacesNoUseSiteDiagnostics(basesBeingResolved); switch (array.Length) { case 0: case 1: // less than 2 interfaces return false; case 2: if ((object)array[0].OriginalDefinition == array[1].OriginalDefinition) { break; } // two unrelated interfaces return false; default: var set = PooledHashSet<object>.GetInstance(); foreach (var i in array) { if (!set.Add(i.OriginalDefinition)) { set.Free(); goto hasRelatedInterfaces; } } // all interfaces are unrelated set.Free(); return false; } // very rare case. // some implemented interfaces are related // will have to instantiate interfaces and check hasRelatedInterfaces: return type.InterfacesNoUseSiteDiagnostics(basesBeingResolved).HasDuplicates(TypeSymbol.EqualsIgnoringDynamicAndTupleNamesComparer); }
internal sealed override ImmutableArray <NamedTypeSymbol> InterfacesNoUseSiteDiagnostics(ConsList <Symbol> basesBeingResolved) { return(_unbound ? ImmutableArray <NamedTypeSymbol> .Empty : Map.SubstituteNamedTypes(OriginalDefinition.InterfacesNoUseSiteDiagnostics(basesBeingResolved))); }
// C# does not let you declare a type in which it would be possible for distinct base interfaces // to unify under some instantiations. But such ill-formed classes can come in through // metadata and be instantiated in C#. We check to see if that's happened. private static bool InterfacesAreDistinct(NamedTypeSymbol type, ConsList<Symbol> basesBeingResolved) { return !type.InterfacesNoUseSiteDiagnostics(basesBeingResolved).HasDuplicates(TypeSymbol.EqualsIgnoringDynamicComparer); }
private void CheckBaseTypeCompliance(NamedTypeSymbol symbol) { System.Diagnostics.Debug.Assert(IsTrue(GetDeclaredOrInheritedCompliance(symbol)), "Only call on compliant symbols"); // NOTE: implemented interfaces do not have to be CLS-compliant (unless the type itself is an interface). if (symbol.IsInterface) { foreach (NamedTypeSymbol interfaceType in symbol.InterfacesNoUseSiteDiagnostics()) { if (!IsCompliantType(interfaceType, symbol)) { // TODO: it would be nice to report this on the base type clause. this.AddDiagnostic(ErrorCode.WRN_CLS_BadInterface, symbol.Locations[0], symbol, interfaceType); } } } else { NamedTypeSymbol baseType = symbol.EnumUnderlyingType ?? symbol.BaseTypeNoUseSiteDiagnostics; // null for interfaces System.Diagnostics.Debug.Assert((object)baseType != null || symbol.SpecialType == SpecialType.System_Object, "Only object has no base."); if ((object)baseType != null && !IsCompliantType(baseType, symbol)) { // TODO: it would be nice to report this on the base type clause. this.AddDiagnostic(ErrorCode.WRN_CLS_BadBase, symbol.Locations[0], symbol, baseType); } } }
/// <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>(); } if (seen.Add(@interface)) { builder.Add(@interface); InterfacesVisit(@interface, builder, ref seen); } } }
// C# does not let you declare a type in which it would be possible for distinct base interfaces // to unify under some instantiations. But such ill-formed classes can come in through // metadata and be instantiated in C#. We check to see if that's happened. private static bool InterfacesAreDistinct(NamedTypeSymbol type, ConsList <Symbol> basesBeingResolved) { return(!type.InterfacesNoUseSiteDiagnostics(basesBeingResolved).HasDuplicates(TypeSymbol.EqualsIgnoringDynamicComparer)); }