Skip to content

Commit 7f61d62

Browse files
committed
Extensions: only look for new extensions in new LangVer
1 parent 2b5f28c commit 7f61d62

File tree

3 files changed

+145
-14
lines changed

3 files changed

+145
-14
lines changed

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

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -199,30 +199,34 @@ private void LookupAllExtensionMembersInSingleBinder(LookupResult result, string
199199
internal void EnumerateAllExtensionMembersInSingleBinder(ArrayBuilder<SingleLookupResult> result,
200200
string? name, int arity, LookupOptions options, Binder originalBinder, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo, ref CompoundUseSiteInfo<AssemblySymbol> classicExtensionUseSiteInfo)
201201
{
202-
// 1. Collect new extension members
203202
PooledHashSet<MethodSymbol>? implementationsToShadow = null;
204-
var extensionDeclarations = ArrayBuilder<NamedTypeSymbol>.GetInstance();
205-
this.GetExtensionDeclarations(extensionDeclarations, originalBinder);
206203

207-
foreach (NamedTypeSymbol extensionDeclaration in extensionDeclarations)
204+
// 1. Collect new extension members
205+
if (this.Compilation.LanguageVersion.AllowNewExtensions())
208206
{
209-
var candidates = name is null ? extensionDeclaration.GetMembers() : extensionDeclaration.GetMembers(name);
207+
var extensionDeclarations = ArrayBuilder<NamedTypeSymbol>.GetInstance();
208+
this.GetExtensionDeclarations(extensionDeclarations, originalBinder);
210209

211-
foreach (var candidate in candidates)
210+
foreach (NamedTypeSymbol extensionDeclaration in extensionDeclarations)
212211
{
213-
SingleLookupResult resultOfThisMember = originalBinder.CheckViability(candidate, arity, options, null, diagnose: true, useSiteInfo: ref useSiteInfo);
214-
result.Add(resultOfThisMember);
212+
var candidates = name is null ? extensionDeclaration.GetMembers() : extensionDeclaration.GetMembers(name);
215213

216-
if (candidate is MethodSymbol { IsStatic: false } shadows &&
217-
shadows.OriginalDefinition.TryGetCorrespondingExtensionImplementationMethod() is { } toShadow)
214+
foreach (var candidate in candidates)
218215
{
219-
implementationsToShadow ??= PooledHashSet<MethodSymbol>.GetInstance();
220-
implementationsToShadow.Add(toShadow);
216+
SingleLookupResult resultOfThisMember = originalBinder.CheckViability(candidate, arity, options, null, diagnose: true, useSiteInfo: ref useSiteInfo);
217+
result.Add(resultOfThisMember);
218+
219+
if (candidate is MethodSymbol { IsStatic: false } shadows &&
220+
shadows.OriginalDefinition.TryGetCorrespondingExtensionImplementationMethod() is { } toShadow)
221+
{
222+
implementationsToShadow ??= PooledHashSet<MethodSymbol>.GetInstance();
223+
implementationsToShadow.Add(toShadow);
224+
}
221225
}
222226
}
223-
}
224227

225-
extensionDeclarations.Free();
228+
extensionDeclarations.Free();
229+
}
226230

227231
// 2. Collect classic extension methods
228232
var extensionMethods = ArrayBuilder<MethodSymbol>.GetInstance();

src/Compilers/CSharp/Portable/LanguageVersion.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,5 +572,10 @@ internal static bool AllowImprovedOverloadCandidates(this LanguageVersion self)
572572
{
573573
return self >= MessageID.IDS_FeatureImprovedOverloadCandidates.RequiredVersion();
574574
}
575+
576+
internal static bool AllowNewExtensions(this LanguageVersion self)
577+
{
578+
return self >= MessageID.IDS_FeatureExtensions.RequiredVersion();
579+
}
575580
}
576581
}

src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26600,4 +26600,126 @@ void M<U>(U u)
2660026600
Assert.Equal("void E.<>E__0<System.Int32>.M<U>(U u)", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString());
2660126601
Assert.Equal(["void E.<>E__0<System.Int32>.M<U>(U u)"], model.GetMemberGroup(expr).ToTestDisplayStrings());
2660226602
}
26603+
26604+
[Fact]
26605+
public void GetSymbolInfo_08()
26606+
{
26607+
var src = """
26608+
public static class E
26609+
{
26610+
public static void M<T>(this T t)
26611+
{
26612+
t.M<T>();
26613+
t.M();
26614+
}
26615+
}
26616+
""";
26617+
var comp = CreateCompilation(src);
26618+
comp.VerifyEmitDiagnostics();
26619+
26620+
var tree = comp.SyntaxTrees.First();
26621+
var model = comp.GetSemanticModel(tree);
26622+
26623+
var extensionParameterSyntax = tree.GetRoot().DescendantNodes().OfType<ParameterSyntax>().First();
26624+
IParameterSymbol extensionParameter = model.GetDeclaredSymbol(extensionParameterSyntax);
26625+
Assert.Equal("T t", extensionParameter.ToTestDisplayString());
26626+
var t = extensionParameter.Type;
26627+
26628+
var expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M<T>()").Expression;
26629+
Assert.Equal("void T.M<T>()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString());
26630+
Assert.Equal(["void T.M<T>()"], model.GetMemberGroup(expr).ToTestDisplayStrings());
26631+
26632+
AssertEqualAndNoDuplicates(["void T.M<T>()"], model.LookupSymbols(position: expr.SpanStart, t, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings());
26633+
26634+
expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M()").Expression;
26635+
Assert.Equal("void T.M<T>()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString());
26636+
Assert.Equal(["void T.M<T>()"], model.GetMemberGroup(expr).ToTestDisplayStrings());
26637+
}
26638+
26639+
[Fact]
26640+
public void LangVer_01()
26641+
{
26642+
var libSrc = """
26643+
public static class E
26644+
{
26645+
extension(object)
26646+
{
26647+
public void M() { }
26648+
public static void M2() { }
26649+
public static int P => 0;
26650+
}
26651+
}
26652+
26653+
""";
26654+
var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.RegularNext);
26655+
libComp.VerifyEmitDiagnostics();
26656+
var libRef = libComp.EmitToImageReference();
26657+
26658+
var srcCompat = """
26659+
new object().M();
26660+
System.Action a = new object().M;
26661+
var x = new object().M;
26662+
26663+
E.M(new object());
26664+
E.get_P();
26665+
E.M2();
26666+
""";
26667+
var comp = CreateCompilation(srcCompat, references: [libRef], parseOptions: TestOptions.Regular13);
26668+
comp.VerifyEmitDiagnostics();
26669+
26670+
comp = CreateCompilation(srcCompat, references: [libRef], parseOptions: TestOptions.RegularNext);
26671+
comp.VerifyEmitDiagnostics();
26672+
26673+
comp = CreateCompilation(srcCompat, references: [libRef]);
26674+
comp.VerifyEmitDiagnostics();
26675+
26676+
// PROTOTYPE function type not yet supported
26677+
var src = """
26678+
object.M2();
26679+
System.Action a = object.M2;
26680+
//var x = object.M2;
26681+
26682+
_ = object.P;
26683+
""";
26684+
comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13);
26685+
comp.VerifyEmitDiagnostics(
26686+
// (1,8): error CS0117: 'object' does not contain a definition for 'M2'
26687+
// object.M2();
26688+
Diagnostic(ErrorCode.ERR_NoSuchMember, "M2").WithArguments("object", "M2").WithLocation(1, 8),
26689+
// (2,26): error CS0117: 'object' does not contain a definition for 'M2'
26690+
// System.Action a = object.M2;
26691+
Diagnostic(ErrorCode.ERR_NoSuchMember, "M2").WithArguments("object", "M2").WithLocation(2, 26),
26692+
// (5,12): error CS0117: 'object' does not contain a definition for 'P'
26693+
// _ = object.P;
26694+
Diagnostic(ErrorCode.ERR_NoSuchMember, "P").WithArguments("object", "P").WithLocation(5, 12));
26695+
verifySymbolInfo(comp, newLangVer: false);
26696+
26697+
comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.RegularNext);
26698+
comp.VerifyEmitDiagnostics();
26699+
verifySymbolInfo(comp, newLangVer: true);
26700+
26701+
comp = CreateCompilation(src, references: [libRef]);
26702+
comp.VerifyEmitDiagnostics();
26703+
verifySymbolInfo(comp, newLangVer: true);
26704+
26705+
static void verifySymbolInfo(CSharpCompilation comp, bool newLangVer)
26706+
{
26707+
var tree = comp.SyntaxTrees.Single();
26708+
var model = comp.GetSemanticModel(tree);
26709+
var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object);
26710+
26711+
if (newLangVer)
26712+
{
26713+
AssertEqualAndNoDuplicates(["void E.<>E__0.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings());
26714+
AssertEqualAndNoDuplicates(["void E.<>E__0.M2()"], model.LookupSymbols(position: 0, o, name: "M2", includeReducedExtensionMethods: true).ToTestDisplayStrings());
26715+
AssertEqualAndNoDuplicates(["System.Int32 E.<>E__0.P { get; }"], model.LookupSymbols(position: 0, o, name: "P", includeReducedExtensionMethods: true).ToTestDisplayStrings());
26716+
}
26717+
else
26718+
{
26719+
AssertEqualAndNoDuplicates(["void System.Object.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings());
26720+
AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M2", includeReducedExtensionMethods: true).ToTestDisplayStrings());
26721+
AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "P", includeReducedExtensionMethods: true).ToTestDisplayStrings());
26722+
}
26723+
}
26724+
}
2660326725
}

0 commit comments

Comments
 (0)