diff --git a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs index 5cbc7641e3dfe..8128d1ac64217 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs @@ -51,6 +51,7 @@ private class UnionData private sealed class UnionDataForDefinition : UnionData { public NamedTypeSymbol? _lazyMemberProviderInterface = ErrorTypeSymbol.UnknownResultType; + public ImmutableArray _lazyMemberProviderInterfaceAllInterfaces; } private sealed partial class UncommonProperties @@ -1969,7 +1970,7 @@ internal ImmutableArray UnionCaseTypes(ref CompoundUseSiteInfo useSiteInfo) { - AddUseSiteInfoForCachedUnionFactoryMethodsResult(ref useSiteInfo); + AddUseSiteInfoForCachedUnionFactoryMethodsResult(GetMemberProviderInterfaceAllInterfacesForDefinition(), ref useSiteInfo); } } @@ -1982,7 +1983,7 @@ internal ImmutableArray UnionFactoryMethods(ref CompoundUseSiteInf if (!lazyFactoryMethods.IsDefault) { - AddUseSiteInfoForCachedUnionFactoryMethodsResult(ref membersInterfaceForDefinitionInterfacesUseSiteInfo); + AddUseSiteInfoForCachedUnionFactoryMethodsResult(GetMemberProviderInterfaceAllInterfacesForDefinition(), ref membersInterfaceForDefinitionInterfacesUseSiteInfo); return lazyFactoryMethods; } @@ -2067,7 +2068,10 @@ internal ImmutableArray UnionFactoryMethods(ref CompoundUseSiteInf } } - foreach (var baseInterfaceForDefinition in membersInterfaceForDefinition.AllInterfacesWithDefinitionUseSiteDiagnostics(ref membersInterfaceForDefinitionInterfacesUseSiteInfo)) + ImmutableArray memberProviderInterfaceAllInterfaces = GetMemberProviderInterfaceAllInterfacesForDefinition(); + AddUseSiteInfoForCachedUnionFactoryMethodsResult(memberProviderInterfaceAllInterfaces, ref membersInterfaceForDefinitionInterfacesUseSiteInfo); + + foreach (var baseInterfaceForDefinition in memberProviderInterfaceAllInterfaces) { Debug.Assert(shadowingMethods is not null); bool canShadow = !baseInterfaceForDefinition.OriginalDefinition.InterfacesNoUseSiteDiagnostics().IsEmpty; @@ -2153,11 +2157,15 @@ static bool isShadowed(MethodSymbol method, ArrayBuilder shadowing /// Add use site info that would be added during calculation of non-cached result of /// . /// - private void AddUseSiteInfoForCachedUnionFactoryMethodsResult(ref CompoundUseSiteInfo membersInterfaceForDefinitionInterfacesUseSiteInfo) + private void AddUseSiteInfoForCachedUnionFactoryMethodsResult(ImmutableArray memberProviderInterfaceAllInterfaces, ref CompoundUseSiteInfo 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); + } } } @@ -2207,6 +2215,69 @@ private void AddUseSiteInfoForCachedUnionFactoryMethodsResult(ref CompoundUseSit } } + internal ImmutableArray GetMemberProviderInterfaceAllInterfacesForDefinition() + { + if (!this.IsDefinition) + { + return this.OriginalDefinition.GetMemberProviderInterfaceAllInterfacesForDefinition(); + } + + var lazyUnionData = (UnionDataForDefinition)GetUnionData(); + ImmutableArray 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 makeAllInterfaces(NamedTypeSymbol memberProviderInterface) + { + var result = ArrayBuilder.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 visited, ArrayBuilder result) + { + if (visited.Add(@interface)) + { + ImmutableArray 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; @@ -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 @@ -2378,8 +2452,14 @@ void addUseSiteInfoForCachedResult(PropertySymbol? valueProperty, ref CompoundUs } PropertySymbol? match = null; + ImmutableArray 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)) { @@ -2616,7 +2696,7 @@ internal ImmutableArray UnionTryGetValueMethods() { addCandidates(membersInterfaceForDefinition, ref typeSet, result); - foreach (var declaringType in membersInterfaceForDefinition.AllInterfacesNoUseSiteDiagnostics) + foreach (var declaringType in GetMemberProviderInterfaceAllInterfacesForDefinition()) { addCandidates(declaringType, ref typeSet, result); } diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs index eb4fb54c8ce6a..10004749accbd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs @@ -336,7 +336,7 @@ protected virtual ImmutableArray 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 MakeAllInterfaces() + protected ImmutableArray MakeAllInterfaces() { var result = ArrayBuilder.GetInstance(); var visited = new HashSet(SymbolEqualityComparer.ConsiderEverything); diff --git a/src/Compilers/CSharp/Test/CSharp15/UnionsTests.cs b/src/Compilers/CSharp/Test/CSharp15/UnionsTests.cs index 0747ae7db13c7..9c05ca0d820bd 100644 --- a/src/Compilers/CSharp/Test/CSharp15/UnionsTests.cs +++ b/src/Compilers/CSharp/Test/CSharp15/UnionsTests.cs @@ -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(