diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ExtensionGroupingInfo.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ExtensionGroupingInfo.cs index 8acf92b0a5d04..9d1f2c5224adb 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ExtensionGroupingInfo.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ExtensionGroupingInfo.cs @@ -21,16 +21,13 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal sealed class ExtensionGroupingInfo { - /// - /// Extension block symbols declared in a class are grouped by their corresponding grouping type metadata name (top level key), - /// then grouped by their corresponding extension marker type metadata name (the secondary key used by MultiDictionary). - /// s are the extension blocks. - /// - private readonly Dictionary> _groupingMap; - private ImmutableArray _lazyGroupingTypes; + private readonly ImmutableArray _groupingTypes; public ExtensionGroupingInfo(SourceMemberContainerTypeSymbol container) { + // Extension block symbols declared in a class are grouped by their corresponding grouping type metadata name (top level key), + // then grouped by their corresponding extension marker type metadata name (the secondary key used by MultiDictionary). + // SourceNamedTypeSymbols are the extension blocks. var groupingMap = new Dictionary>(EqualityComparer.Default); foreach (var type in container.GetTypeMembers("")) @@ -54,7 +51,16 @@ public ExtensionGroupingInfo(SourceMemberContainerTypeSymbol container) markerMap.Add(sourceNamedType.ExtensionMarkerName, sourceNamedType); } - _groupingMap = groupingMap; + var builder = ArrayBuilder.GetInstance(groupingMap.Count); + + foreach (KeyValuePair> pair in groupingMap) + { + builder.Add(new ExtensionGroupingType(pair.Key, pair.Value)); + } + + builder.Sort(); + + _groupingTypes = builder.ToImmutableAndFree(); AssertInvariants(container); } @@ -94,21 +100,7 @@ private void AssertInvariants(SourceMemberContainerTypeSymbol container) public ImmutableArray GetGroupingTypes() { - if (_lazyGroupingTypes.IsDefault) - { - var builder = ArrayBuilder.GetInstance(_groupingMap.Count); - - foreach (KeyValuePair> pair in _groupingMap) - { - builder.Add(new ExtensionGroupingType(pair.Key, pair.Value)); - } - - builder.Sort(); - - ImmutableInterlocked.InterlockedInitialize(ref _lazyGroupingTypes, builder.ToImmutableAndFree()); - } - - return ImmutableArray.CastUp(_lazyGroupingTypes); + return ImmutableArray.CastUp(_groupingTypes); } public Cci.ITypeDefinition GetCorrespondingMarkerType(SynthesizedExtensionMarker markerMethod) @@ -119,13 +111,12 @@ public Cci.ITypeDefinition GetCorrespondingMarkerType(SynthesizedExtensionMarker private ExtensionMarkerType GetCorrespondingMarkerType(SourceNamedTypeSymbol extension) { Debug.Assert(extension.IsExtension); - GetGroupingTypes(); // Tracked by https://github.com/dotnet/roslyn/issues/78827 : Optimize lookup with side dictionaries? var groupingName = extension.ExtensionGroupingName; var markerName = extension.ExtensionMarkerName; - foreach (var groupingType in _lazyGroupingTypes) + foreach (var groupingType in _groupingTypes) { if (groupingType.Name != groupingName) { @@ -180,12 +171,11 @@ public Cci.TypeMemberVisibility GetCorrespondingMarkerMethodVisibility(Synthesiz public Cci.ITypeDefinition GetCorrespondingGroupingType(SourceNamedTypeSymbol extension) { Debug.Assert(extension.IsExtension); - GetGroupingTypes(); // Tracked by https://github.com/dotnet/roslyn/issues/78827 : Optimize lookup with a side dictionary? var groupingName = extension.ExtensionGroupingName; - foreach (var groupingType in _lazyGroupingTypes) + foreach (var groupingType in _groupingTypes) { if (groupingType.Name == groupingName) { @@ -210,8 +200,7 @@ internal ImmutableArray GetMergedExtensions(SourceNamedTy /// internal IEnumerable> EnumerateMergedExtensionBlocks() { - GetGroupingTypes(); - foreach (var groupingType in _lazyGroupingTypes) + foreach (var groupingType in _groupingTypes) { foreach (var markerType in groupingType.ExtensionMarkerTypes) { @@ -436,10 +425,9 @@ static void substituteConstraintTypes(ImmutableArray types, /// internal void CheckSignatureCollisions(BindingDiagnosticBag diagnostics) { - GetGroupingTypes(); PooledHashSet? alreadyReportedExtensions = null; - foreach (ExtensionGroupingType groupingType in _lazyGroupingTypes) + foreach (ExtensionGroupingType groupingType in _groupingTypes) { checkCollisions(enumerateExtensionsInGrouping(groupingType), HaveSameILSignature, ref alreadyReportedExtensions, diagnostics); } @@ -691,7 +679,7 @@ private sealed class ExtensionGroupingType : ExtensionGroupingOrMarkerType, ICom { private readonly string _name; public readonly ImmutableArray ExtensionMarkerTypes; - private readonly ImmutableArray _typeParameters; + private ImmutableArray _lazyTypeParameters; public ExtensionGroupingType(string name, MultiDictionary extensionMarkerTypes) { @@ -706,10 +694,6 @@ public ExtensionGroupingType(string name, MultiDictionary new ExtensionGroupingTypeTypeParameter(@this, p), this) : - []; } int IComparable.CompareTo(ExtensionGroupingType? other) @@ -718,7 +702,21 @@ int IComparable.CompareTo(ExtensionGroupingType? other) return ExtensionMarkerTypes[0].CompareTo(other.ExtensionMarkerTypes[0]); } - protected override IEnumerable GenericParameters => _typeParameters; + protected override IEnumerable GenericParameters + { + get + { + if (_lazyTypeParameters.IsDefault) + { + var typeParameters = ExtensionMarkerTypes[0].UnderlyingExtensions[0].Arity != 0 ? + ((INestedTypeDefinition)ExtensionMarkerTypes[0].UnderlyingExtensions[0].GetCciAdapter()).GenericParameters.SelectAsArray(static (p, @this) => new ExtensionGroupingTypeTypeParameter(@this, p), this) : + []; + ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameters, typeParameters); + } + + return _lazyTypeParameters; + } + } protected override ushort GenericParameterCount => (ushort)ExtensionMarkerTypes[0].UnderlyingExtensions[0].Arity; @@ -841,7 +839,7 @@ private sealed class ExtensionMarkerType : ExtensionGroupingOrMarkerType, ICompa public readonly ExtensionGroupingType GroupingType; private readonly string _name; public readonly ImmutableArray UnderlyingExtensions; - private readonly ImmutableArray _typeParameters; + private ImmutableArray _lazyTypeParameters; public ExtensionMarkerType(ExtensionGroupingType groupingType, string name, MultiDictionary.ValueSet extensions) { @@ -852,10 +850,6 @@ public ExtensionMarkerType(ExtensionGroupingType groupingType, string name, Mult builder.AddRange(extensions); builder.Sort(LexicalOrderSymbolComparer.Instance); UnderlyingExtensions = builder.ToImmutableAndFree(); - - _typeParameters = UnderlyingExtensions[0].Arity != 0 ? - ((INestedTypeDefinition)UnderlyingExtensions[0].GetCciAdapter()).GenericParameters.SelectAsArray(static (p, @this) => new InheritedTypeParameter(p.Index, @this, p), this) : - []; } public int CompareTo(ExtensionMarkerType? other) @@ -864,7 +858,21 @@ public int CompareTo(ExtensionMarkerType? other) return LexicalOrderSymbolComparer.Instance.Compare(UnderlyingExtensions[0], other.UnderlyingExtensions[0]); } - protected override IEnumerable GenericParameters => _typeParameters; + protected override IEnumerable GenericParameters + { + get + { + if (_lazyTypeParameters.IsDefault) + { + var typeParameters = UnderlyingExtensions[0].Arity != 0 ? + ((INestedTypeDefinition)UnderlyingExtensions[0].GetCciAdapter()).GenericParameters.SelectAsArray(static (p, @this) => new InheritedTypeParameter(p.Index, @this, p), this) : + []; + ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameters, typeParameters); + } + + return _lazyTypeParameters; + } + } protected override ushort GenericParameterCount => (ushort)UnderlyingExtensions[0].Arity;