Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,19 @@ public static bool DerivesFrom([NotNullWhen(returnValue: true)] this ITypeSymbol

if (!baseTypesOnly && candidateBaseType.TypeKind == TypeKind.Interface)
{
IEnumerable<ITypeSymbol> allInterfaces = symbol.AllInterfaces.OfType<ITypeSymbol>();
if (SymbolEqualityComparer.Default.Equals(candidateBaseType.OriginalDefinition, candidateBaseType))
// Avoid OfType<ITypeSymbol>() + optional Select() + Contains() chain — each creates a heap-allocated
// LINQ iterator state machine. AllInterfaces is ImmutableArray<INamedTypeSymbol>; iterating it
// directly uses the struct enumerator (zero heap allocation).
bool useOriginalDefinition = SymbolEqualityComparer.Default.Equals(candidateBaseType.OriginalDefinition, candidateBaseType);
foreach (INamedTypeSymbol iface in symbol.AllInterfaces)
{
// Candidate base type is not a constructed generic type, so use original definition for interfaces.
allInterfaces = allInterfaces.Select(i => i.OriginalDefinition);
}

if (allInterfaces.Contains(candidateBaseType, SymbolEqualityComparer.Default))
{
return true;
// When the candidate is not a constructed generic type, compare via OriginalDefinition
// (mirrors the original Select(i => i.OriginalDefinition) projection).
Comment thread
Evangelink marked this conversation as resolved.
ITypeSymbol candidate = useOriginalDefinition ? iface.OriginalDefinition : iface;
if (SymbolEqualityComparer.Default.Equals(candidate, candidateBaseType))
{
return true;
}
}
}

Expand Down