private static void StructDependsClosure(NamedTypeSymbol type, HashSet <Symbol> partialClosure, NamedTypeSymbol on) { Debug.Assert((object)type != null); if ((object)type.OriginalDefinition == on) { // found a possibly expanding cycle, for example // struct X<T> { public T t; } // struct W<T> { X<W<W<T>>> x; } // while not explicitly forbidden by the spec, it should be. partialClosure.Add(on); return; } if (partialClosure.Add(type)) { foreach (var member in type.GetMembersUnordered()) { var field = member as FieldSymbol; if ((object)field == null || field.Type.TypeKind != TypeKind.Struct || field.IsStatic) { continue; } StructDependsClosure((NamedTypeSymbol)field.Type.TypeSymbol, partialClosure, on); } } }
/// <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; } } }