Skip to content

Commit f7ca15c

Browse files
author
Julien Couvreur
authored
Extensions: only look for new extensions in new LangVer (#77690)
1 parent 4482c72 commit f7ca15c

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
@@ -28280,4 +28280,126 @@ void M<U>(U u)
2828028280
Assert.Equal("void E.<>E__0<System.Int32>.M<U>(U u)", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString());
2828128281
Assert.Equal(["void E.<>E__0<System.Int32>.M<U>(U u)"], model.GetMemberGroup(expr).ToTestDisplayStrings());
2828228282
}
28283+
28284+
[Fact]
28285+
public void GetSymbolInfo_08()
28286+
{
28287+
var src = """
28288+
public static class E
28289+
{
28290+
public static void M<T>(this T t)
28291+
{
28292+
t.M<T>();
28293+
t.M();
28294+
}
28295+
}
28296+
""";
28297+
var comp = CreateCompilation(src);
28298+
comp.VerifyEmitDiagnostics();
28299+
28300+
var tree = comp.SyntaxTrees.First();
28301+
var model = comp.GetSemanticModel(tree);
28302+
28303+
var extensionParameterSyntax = tree.GetRoot().DescendantNodes().OfType<ParameterSyntax>().First();
28304+
IParameterSymbol extensionParameter = model.GetDeclaredSymbol(extensionParameterSyntax);
28305+
Assert.Equal("T t", extensionParameter.ToTestDisplayString());
28306+
var t = extensionParameter.Type;
28307+
28308+
var expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M<T>()").Expression;
28309+
Assert.Equal("void T.M<T>()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString());
28310+
Assert.Equal(["void T.M<T>()"], model.GetMemberGroup(expr).ToTestDisplayStrings());
28311+
28312+
AssertEqualAndNoDuplicates(["void T.M<T>()"], model.LookupSymbols(position: expr.SpanStart, t, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings());
28313+
28314+
expr = GetSyntax<InvocationExpressionSyntax>(tree, "t.M()").Expression;
28315+
Assert.Equal("void T.M<T>()", model.GetSymbolInfo(expr).Symbol.ToTestDisplayString());
28316+
Assert.Equal(["void T.M<T>()"], model.GetMemberGroup(expr).ToTestDisplayStrings());
28317+
}
28318+
28319+
[Fact]
28320+
public void LangVer_01()
28321+
{
28322+
var libSrc = """
28323+
public static class E
28324+
{
28325+
extension(object)
28326+
{
28327+
public void M() { }
28328+
public static void M2() { }
28329+
public static int P => 0;
28330+
}
28331+
}
28332+
28333+
""";
28334+
var libComp = CreateCompilation(libSrc, parseOptions: TestOptions.RegularNext);
28335+
libComp.VerifyEmitDiagnostics();
28336+
var libRef = libComp.EmitToImageReference();
28337+
28338+
var srcCompat = """
28339+
new object().M();
28340+
System.Action a = new object().M;
28341+
var x = new object().M;
28342+
28343+
E.M(new object());
28344+
E.get_P();
28345+
E.M2();
28346+
""";
28347+
var comp = CreateCompilation(srcCompat, references: [libRef], parseOptions: TestOptions.Regular13);
28348+
comp.VerifyEmitDiagnostics();
28349+
28350+
comp = CreateCompilation(srcCompat, references: [libRef], parseOptions: TestOptions.RegularNext);
28351+
comp.VerifyEmitDiagnostics();
28352+
28353+
comp = CreateCompilation(srcCompat, references: [libRef]);
28354+
comp.VerifyEmitDiagnostics();
28355+
28356+
// PROTOTYPE function type not yet supported
28357+
var src = """
28358+
object.M2();
28359+
System.Action a = object.M2;
28360+
//var x = object.M2;
28361+
28362+
_ = object.P;
28363+
""";
28364+
comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.Regular13);
28365+
comp.VerifyEmitDiagnostics(
28366+
// (1,8): error CS0117: 'object' does not contain a definition for 'M2'
28367+
// object.M2();
28368+
Diagnostic(ErrorCode.ERR_NoSuchMember, "M2").WithArguments("object", "M2").WithLocation(1, 8),
28369+
// (2,26): error CS0117: 'object' does not contain a definition for 'M2'
28370+
// System.Action a = object.M2;
28371+
Diagnostic(ErrorCode.ERR_NoSuchMember, "M2").WithArguments("object", "M2").WithLocation(2, 26),
28372+
// (5,12): error CS0117: 'object' does not contain a definition for 'P'
28373+
// _ = object.P;
28374+
Diagnostic(ErrorCode.ERR_NoSuchMember, "P").WithArguments("object", "P").WithLocation(5, 12));
28375+
verifySymbolInfo(comp, newLangVer: false);
28376+
28377+
comp = CreateCompilation(src, references: [libRef], parseOptions: TestOptions.RegularNext);
28378+
comp.VerifyEmitDiagnostics();
28379+
verifySymbolInfo(comp, newLangVer: true);
28380+
28381+
comp = CreateCompilation(src, references: [libRef]);
28382+
comp.VerifyEmitDiagnostics();
28383+
verifySymbolInfo(comp, newLangVer: true);
28384+
28385+
static void verifySymbolInfo(CSharpCompilation comp, bool newLangVer)
28386+
{
28387+
var tree = comp.SyntaxTrees.Single();
28388+
var model = comp.GetSemanticModel(tree);
28389+
var o = ((Compilation)comp).GetSpecialType(SpecialType.System_Object);
28390+
28391+
if (newLangVer)
28392+
{
28393+
AssertEqualAndNoDuplicates(["void E.<>E__0.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings());
28394+
AssertEqualAndNoDuplicates(["void E.<>E__0.M2()"], model.LookupSymbols(position: 0, o, name: "M2", includeReducedExtensionMethods: true).ToTestDisplayStrings());
28395+
AssertEqualAndNoDuplicates(["System.Int32 E.<>E__0.P { get; }"], model.LookupSymbols(position: 0, o, name: "P", includeReducedExtensionMethods: true).ToTestDisplayStrings());
28396+
}
28397+
else
28398+
{
28399+
AssertEqualAndNoDuplicates(["void System.Object.M()"], model.LookupSymbols(position: 0, o, name: "M", includeReducedExtensionMethods: true).ToTestDisplayStrings());
28400+
AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "M2", includeReducedExtensionMethods: true).ToTestDisplayStrings());
28401+
AssertEqualAndNoDuplicates([], model.LookupSymbols(position: 0, o, name: "P", includeReducedExtensionMethods: true).ToTestDisplayStrings());
28402+
}
28403+
}
28404+
}
2828328405
}

0 commit comments

Comments
 (0)