Skip to content
Merged
Show file tree
Hide file tree
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
98 changes: 89 additions & 9 deletions src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ private class UnionData
private sealed class UnionDataForDefinition : UnionData
{
public NamedTypeSymbol? _lazyMemberProviderInterface = ErrorTypeSymbol.UnknownResultType;
public ImmutableArray<NamedTypeSymbol> _lazyMemberProviderInterfaceAllInterfaces;
}

private sealed partial class UncommonProperties
Expand Down Expand Up @@ -1969,7 +1970,7 @@ internal ImmutableArray<TypeSymbol> UnionCaseTypes(ref CompoundUseSiteInfo<Assem

void addUseSiteInfoForCachedResult(ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
AddUseSiteInfoForCachedUnionFactoryMethodsResult(ref useSiteInfo);
AddUseSiteInfoForCachedUnionFactoryMethodsResult(GetMemberProviderInterfaceAllInterfacesForDefinition(), ref useSiteInfo);
}
}

Expand All @@ -1982,7 +1983,7 @@ internal ImmutableArray<MethodSymbol> UnionFactoryMethods(ref CompoundUseSiteInf

if (!lazyFactoryMethods.IsDefault)
{
AddUseSiteInfoForCachedUnionFactoryMethodsResult(ref membersInterfaceForDefinitionInterfacesUseSiteInfo);
AddUseSiteInfoForCachedUnionFactoryMethodsResult(GetMemberProviderInterfaceAllInterfacesForDefinition(), ref membersInterfaceForDefinitionInterfacesUseSiteInfo);
return lazyFactoryMethods;
}

Expand Down Expand Up @@ -2067,7 +2068,10 @@ internal ImmutableArray<MethodSymbol> UnionFactoryMethods(ref CompoundUseSiteInf
}
}

foreach (var baseInterfaceForDefinition in membersInterfaceForDefinition.AllInterfacesWithDefinitionUseSiteDiagnostics(ref membersInterfaceForDefinitionInterfacesUseSiteInfo))
ImmutableArray<NamedTypeSymbol> memberProviderInterfaceAllInterfaces = GetMemberProviderInterfaceAllInterfacesForDefinition();
AddUseSiteInfoForCachedUnionFactoryMethodsResult(memberProviderInterfaceAllInterfaces, ref membersInterfaceForDefinitionInterfacesUseSiteInfo);

foreach (var baseInterfaceForDefinition in memberProviderInterfaceAllInterfaces)
{
Debug.Assert(shadowingMethods is not null);
bool canShadow = !baseInterfaceForDefinition.OriginalDefinition.InterfacesNoUseSiteDiagnostics().IsEmpty;
Expand Down Expand Up @@ -2153,11 +2157,15 @@ static bool isShadowed(MethodSymbol method, ArrayBuilder<MethodSymbol> shadowing
/// Add use site info that would be added during calculation of non-cached result of
/// <see cref="UnionFactoryMethods"/>.
/// </summary>
private void AddUseSiteInfoForCachedUnionFactoryMethodsResult(ref CompoundUseSiteInfo<AssemblySymbol> membersInterfaceForDefinitionInterfacesUseSiteInfo)
private void AddUseSiteInfoForCachedUnionFactoryMethodsResult(ImmutableArray<NamedTypeSymbol> memberProviderInterfaceAllInterfaces, ref CompoundUseSiteInfo<AssemblySymbol> membersInterfaceForDefinitionInterfacesUseSiteInfo)
{
if (membersInterfaceForDefinitionInterfacesUseSiteInfo.AccumulatesDependencies || membersInterfaceForDefinitionInterfacesUseSiteInfo.AccumulatesDiagnostics)
if (!memberProviderInterfaceAllInterfaces.IsDefault &&
(membersInterfaceForDefinitionInterfacesUseSiteInfo.AccumulatesDependencies || membersInterfaceForDefinitionInterfacesUseSiteInfo.AccumulatesDiagnostics))
{
GetMemberProviderInterfaceForDefinition()?.AllInterfacesWithDefinitionUseSiteDiagnostics(ref membersInterfaceForDefinitionInterfacesUseSiteInfo);
foreach (var iface in memberProviderInterfaceAllInterfaces)
{
iface.OriginalDefinition.AddUseSiteInfo(ref membersInterfaceForDefinitionInterfacesUseSiteInfo);
}
}
}

Expand Down Expand Up @@ -2207,6 +2215,69 @@ private void AddUseSiteInfoForCachedUnionFactoryMethodsResult(ref CompoundUseSit
}
}

internal ImmutableArray<NamedTypeSymbol> GetMemberProviderInterfaceAllInterfacesForDefinition()
{
if (!this.IsDefinition)
{
return this.OriginalDefinition.GetMemberProviderInterfaceAllInterfacesForDefinition();
}

var lazyUnionData = (UnionDataForDefinition)GetUnionData();
ImmutableArray<NamedTypeSymbol> lazyAllInterfaces = lazyUnionData._lazyMemberProviderInterfaceAllInterfaces;

if (!lazyAllInterfaces.IsDefault)
{
return lazyAllInterfaces;
}

NamedTypeSymbol? memberProviderInterface = GetMemberProviderInterfaceForDefinition();
if (memberProviderInterface is null)
{
return default;
}

ImmutableInterlocked.InterlockedInitialize(ref lazyUnionData._lazyMemberProviderInterfaceAllInterfaces, makeAllInterfaces(memberProviderInterface));
return lazyUnionData._lazyMemberProviderInterfaceAllInterfaces;

// Produce all implemented interfaces in topologically sorted order.
static ImmutableArray<NamedTypeSymbol> makeAllInterfaces(NamedTypeSymbol memberProviderInterface)
{
var result = ArrayBuilder<NamedTypeSymbol>.GetInstance();
var visited = TypeSymbol.AllIgnoreOptionsSetPool.Allocate();

var interfaces = memberProviderInterface.GetInterfacesToEmit();
for (int i = interfaces.Length - 1; i >= 0; i--)
{
addAllInterfaces(interfaces[i], visited, result);
}

visited.Free();
result.ReverseContents();
return result.ToImmutableAndFree();

static void addAllInterfaces(NamedTypeSymbol @interface, HashSet<TypeSymbol> visited, ArrayBuilder<NamedTypeSymbol> result)
{
if (visited.Add(@interface))
{
ImmutableArray<NamedTypeSymbol> baseInterfaces = @interface.OriginalDefinition.GetInterfacesToEmit();
for (int i = baseInterfaces.Length - 1; i >= 0; i--)
{
var baseInterface = baseInterfaces[i];

if (!@interface.IsDefinition)
{
baseInterface = @interface.TypeSubstitution.SubstituteNamedType(baseInterface);
}

addAllInterfaces(baseInterface, visited, result);
}

result.Add(@interface);
}
}
}
}

private UncommonProperties GetUncommonProperties()
{
UncommonProperties? lazyUncommonProperties = _lazyUncommonProperties;
Expand Down Expand Up @@ -2336,7 +2407,10 @@ void addUseSiteInfoForCachedResult(PropertySymbol? valueProperty, ref CompoundUs
{
if (valueProperty?.ContainingType.OriginalDefinition != (object)memberProviderInterface)
{
memberProviderInterface.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteInfo);
foreach (var iface in GetMemberProviderInterfaceAllInterfacesForDefinition())
{
iface.OriginalDefinition.AddUseSiteInfo(ref useSiteInfo);
}
}
}
else
Expand Down Expand Up @@ -2378,8 +2452,14 @@ void addUseSiteInfoForCachedResult(PropertySymbol? valueProperty, ref CompoundUs
}

PropertySymbol? match = null;
ImmutableArray<NamedTypeSymbol> memberProviderInterfaceAllInterfaces = GetMemberProviderInterfaceAllInterfacesForDefinition();

foreach (var iface in memberProviderInterfaceAllInterfaces)
{
iface.OriginalDefinition.AddUseSiteInfo(ref membersProviderForDefinitionBasesUseSiteInfo);
}

foreach (var baseInterfaceForDefinition in membersInterfaceForDefinition.AllInterfacesWithDefinitionUseSiteDiagnostics(ref membersProviderForDefinitionBasesUseSiteInfo))
foreach (var baseInterfaceForDefinition in memberProviderInterfaceAllInterfaces)
{
if (getMemberDeclaredInType(baseInterfaceForDefinition, memberName, isSuitableUnionMember, out member))
{
Expand Down Expand Up @@ -2616,7 +2696,7 @@ internal ImmutableArray<MethodSymbol> UnionTryGetValueMethods()
{
addCandidates(membersInterfaceForDefinition, ref typeSet, result);

foreach (var declaringType in membersInterfaceForDefinition.AllInterfacesNoUseSiteDiagnostics)
foreach (var declaringType in GetMemberProviderInterfaceAllInterfacesForDefinition())
{
addCandidates(declaringType, ref typeSet, result);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ protected virtual ImmutableArray<NamedTypeSymbol> GetAllInterfaces()
/// TypeSymbol.Interfaces as the source of edge data, which has had cycles and infinitely
/// long dependency cycles removed. Consequently, it is possible (and we do) use the
/// simplest version of Tarjan's topological sorting algorithm.
protected virtual ImmutableArray<NamedTypeSymbol> MakeAllInterfaces()
protected ImmutableArray<NamedTypeSymbol> MakeAllInterfaces()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we should keep TypeSymbol.cs and TypeSymbol.vb in sync per a comment near the top of the file, should we make a similar change in VB?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you are referring to a comment about public API surface. First, this isn't a public method. Second, C# and VB symbols are no longer public.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevertheless, it feels like if we can make the same change on the VB side, perhaps we should?

{
var result = ArrayBuilder<NamedTypeSymbol>.GetInstance();
var visited = new HashSet<NamedTypeSymbol>(SymbolEqualityComparer.ConsiderEverything);
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Test/CSharp15/UnionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40058,7 +40058,7 @@ static bool Test1(S1 u)
CompileAndVerify(comp2, expectedOutput: "FalseFalseTrue").VerifyDiagnostics();
}

[Theory(Skip = "There is metadata vs. source difference for this scenario")] // https://github.com/dotnet/roslyn/issues/82636
[Theory]
[CombinatorialData]
[WorkItem("https://github.com/dotnet/roslyn/issues/82636")]
public void NonBoxingUnionMatching_MemberProvider_TryGetValue_Inheritance_37_ImplicitReferenceConversion_Determinism(
Expand Down
Loading