Skip to content

Commit 8ec786e

Browse files
committed
Extensions: allow more CREFs
1 parent 502420d commit 8ec786e

File tree

3 files changed

+323
-47
lines changed

3 files changed

+323
-47
lines changed

src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System;
56
using System.Collections.Generic;
67
using System.Collections.Immutable;
78
using System.Diagnostics;
@@ -224,12 +225,6 @@ private ImmutableArray<Symbol> BindExtensionMemberCref(ExtensionMemberCrefSyntax
224225
{
225226
CheckFeatureAvailability(syntax, MessageID.IDS_FeatureExtensions, diagnostics);
226227

227-
if (containerOpt is not NamedTypeSymbol namedContainer)
228-
{
229-
ambiguityWinner = null;
230-
return ImmutableArray<Symbol>.Empty;
231-
}
232-
233228
int arity = 0;
234229
TypeArgumentListSyntax? typeArgumentListSyntax = null;
235230
CrefParameterListSyntax? parameters = null;
@@ -256,7 +251,7 @@ private ImmutableArray<Symbol> BindExtensionMemberCref(ExtensionMemberCrefSyntax
256251

257252
TypeArgumentListSyntax? extensionTypeArguments = syntax.TypeArgumentList;
258253
int extensionArity = extensionTypeArguments?.Arguments.Count ?? 0;
259-
ImmutableArray<Symbol> sortedSymbols = computeSortedAndFilteredCrefExtensionMembers(namedContainer, memberName, extensionArity, arity, extensionTypeArguments, diagnostics, syntax);
254+
ImmutableArray<Symbol> sortedSymbols = computeSortedAndFilteredCrefExtensionMembers(containerOpt, memberName, extensionArity, arity, extensionTypeArguments, diagnostics, syntax);
260255

261256
if (sortedSymbols.IsDefaultOrEmpty)
262257
{
@@ -268,7 +263,7 @@ private ImmutableArray<Symbol> BindExtensionMemberCref(ExtensionMemberCrefSyntax
268263

269264
return ProcessCrefMemberLookupResults(sortedSymbols, arity, syntax, typeArgumentListSyntax, parameters, out ambiguityWinner, diagnostics);
270265

271-
ImmutableArray<Symbol> computeSortedAndFilteredCrefExtensionMembers(NamedTypeSymbol container, string name, int extensionArity, int arity, TypeArgumentListSyntax? extensionTypeArguments, BindingDiagnosticBag diagnostics, ExtensionMemberCrefSyntax syntax)
266+
ImmutableArray<Symbol> computeSortedAndFilteredCrefExtensionMembers(NamespaceOrTypeSymbol? containerOpt, string name, int extensionArity, int arity, TypeArgumentListSyntax? extensionTypeArguments, BindingDiagnosticBag diagnostics, ExtensionMemberCrefSyntax syntax)
272267
{
273268
Debug.Assert(name is not null);
274269

@@ -295,9 +290,19 @@ ImmutableArray<Symbol> computeSortedAndFilteredCrefExtensionMembers(NamedTypeSym
295290
CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = this.GetNewCompoundUseSiteInfo(diagnostics);
296291
ArrayBuilder<Symbol>? sortedSymbolsBuilder = null;
297292

298-
foreach (var nested in container.GetTypeMembers())
293+
IEnumerable<NamedTypeSymbol> candidateTypes = containerOpt switch
294+
{
295+
null => enumerateCandidateTypes(containerOpt, syntax, diagnostics),
296+
NamedTypeSymbol container => container.GetTypeMembers(""),
297+
_ => []
298+
};
299+
300+
foreach (var nested in candidateTypes)
299301
{
300-
if (!nested.IsExtension || nested.Arity != extensionArity || nested.ExtensionParameter is null)
302+
if (!nested.IsExtension
303+
|| nested.Arity != extensionArity
304+
|| nested.ExtensionParameter is null
305+
|| nested is not { ContainingType: { ContainingType: null } }) // only consider extension blocks in top-level types
301306
{
302307
continue;
303308
}
@@ -365,6 +370,36 @@ ImmutableArray<Symbol> computeSortedAndFilteredCrefExtensionMembers(NamedTypeSym
365370

366371
return sortedSymbolsBuilder.ToImmutableAndFree();
367372
}
373+
374+
IEnumerable<NamedTypeSymbol> enumerateCandidateTypes(NamespaceOrTypeSymbol? container, SyntaxNode syntax, BindingDiagnosticBag diagnostics)
375+
{
376+
CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
377+
LookupResult result = LookupResult.GetInstance();
378+
this.LookupSymbolsOrMembersInternal(
379+
result,
380+
container,
381+
name: "",
382+
arity: 0,
383+
basesBeingResolved: null,
384+
options: LookupOptions.AllNamedTypesOnArityZero | LookupOptions.NamespacesOrTypesOnly,
385+
diagnose: false,
386+
useSiteInfo: ref useSiteInfo);
387+
388+
diagnostics.Add(syntax, useSiteInfo);
389+
390+
if (result.IsMultiViable)
391+
{
392+
foreach (var symbol in result.Symbols)
393+
{
394+
if (symbol is NamedTypeSymbol namedType)
395+
{
396+
yield return namedType;
397+
}
398+
}
399+
}
400+
401+
result.Free();
402+
}
368403
}
369404

370405
// NOTE: not guaranteed to be a method (e.g. class op_Addition)

src/Compilers/CSharp/Portable/Binder/WithCrefTypeParametersBinder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ private MultiDictionary<string, TypeParameterSymbol> CreateTypeParameterMap()
6363
case SyntaxKind.IndexerMemberCref:
6464
case SyntaxKind.OperatorMemberCref:
6565
case SyntaxKind.ConversionOperatorMemberCref:
66+
case SyntaxKind.ExtensionMemberCref:
6667
{
6768
AddTypeParameters((MemberCrefSyntax)_crefSyntax, map);
6869
break;

0 commit comments

Comments
 (0)