Skip to content

Commit 09be0d7

Browse files
authored
Extensions: Ignore ref kind of extension parameter for static members in betterness (#79885)
1 parent e5924c0 commit 09be0d7

File tree

3 files changed

+311
-11
lines changed

3 files changed

+311
-11
lines changed

src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2566,11 +2566,11 @@ private BetterResult BetterFunctionMember<TMember>(
25662566

25672567
// Returns the parameter type (considering params).
25682568
static TypeSymbol getParameterTypeAndRefKind(int i, MemberAnalysisResult memberResolutionResult, ImmutableArray<ParameterSymbol> parameters,
2569-
TypeWithAnnotations paramsElementTypeOpt, TMember member, out RefKind parameter1RefKind)
2569+
TypeWithAnnotations paramsElementTypeOpt, TMember member, out RefKind parameterRefKind)
25702570
{
25712571
ParameterSymbol parameter = getParameterOrExtensionParameter(i, memberResolutionResult, parameters, member);
25722572

2573-
parameter1RefKind = parameter.RefKind;
2573+
parameterRefKind = GetParameterBetternessRefKind(parameter, member);
25742574

25752575
var type = parameter.Type;
25762576
if (memberResolutionResult.Kind == MemberResolutionKind.ApplicableInExpandedForm &&
@@ -2631,7 +2631,10 @@ static BetterResult preferValOverInOrRefInterpolatedHandlerParameters(
26312631
Debug.Assert(!isInterpolatedStringHandlerConversion || arguments[i] is BoundUnconvertedInterpolatedString or BoundBinaryOperator { IsUnconvertedInterpolatedStringAddition: true });
26322632
}
26332633

2634-
if (p1.RefKind == RefKind.None && isAcceptableRefMismatch(p2.RefKind, isInterpolatedStringHandlerConversion))
2634+
RefKind refKind1 = GetParameterBetternessRefKind(p1, m1.Member);
2635+
RefKind refKind2 = GetParameterBetternessRefKind(p2, m2.Member);
2636+
2637+
if (refKind1 == RefKind.None && isAcceptableRefMismatch(refKind2, isInterpolatedStringHandlerConversion))
26352638
{
26362639
if (valOverInOrRefInterpolatedHandlerPreference == BetterResult.Right)
26372640
{
@@ -2642,7 +2645,7 @@ static BetterResult preferValOverInOrRefInterpolatedHandlerParameters(
26422645
valOverInOrRefInterpolatedHandlerPreference = BetterResult.Left;
26432646
}
26442647
}
2645-
else if (p2.RefKind == RefKind.None && isAcceptableRefMismatch(p1.RefKind, isInterpolatedStringHandlerConversion))
2648+
else if (refKind2 == RefKind.None && isAcceptableRefMismatch(refKind1, isInterpolatedStringHandlerConversion))
26462649
{
26472650
if (valOverInOrRefInterpolatedHandlerPreference == BetterResult.Left)
26482651
{
@@ -2670,6 +2673,16 @@ static bool isAcceptableRefMismatch(RefKind refKind, bool isInterpolatedStringHa
26702673
}
26712674
}
26722675

2676+
private static RefKind GetParameterBetternessRefKind<TMember>(ParameterSymbol parameter, TMember member) where TMember : Symbol
2677+
{
2678+
// For static extension members, the ref kind of the extension parameter shouldn't affect betterness.
2679+
bool isExtensionParameterOfStaticExtensionMember = parameter is { ContainingSymbol: TypeSymbol { IsExtension: true, ExtensionParameter: var extensionParameter } }
2680+
&& member.IsStatic
2681+
&& object.ReferenceEquals(parameter, extensionParameter);
2682+
2683+
return isExtensionParameterOfStaticExtensionMember ? RefKind.None : parameter.RefKind;
2684+
}
2685+
26732686
/// <summary>
26742687
/// Returns true if the overload required a function type conversion to infer
26752688
/// generic method type arguments or to convert to parameter types.

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

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using System.Linq;
77
using Microsoft.CodeAnalysis.CSharp.Symbols;
8+
using Microsoft.CodeAnalysis.CSharp.Syntax;
89
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
910
using Microsoft.CodeAnalysis.Test.Utilities;
1011
using Roslyn.Test.Utilities;
@@ -27578,5 +27579,76 @@ static void Main()
2757827579
Diagnostic(ErrorCode.ERR_BadBinaryOps, "x += 1").WithArguments("+=", "C1", "int").WithLocation(7, 9)
2757927580
);
2758027581
}
27582+
27583+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79171")]
27584+
public void RemoveWorseMembers_01()
27585+
{
27586+
// by-value vs. in extension parameter, static operator
27587+
var src = """
27588+
_ = new S() + new S();
27589+
27590+
struct S { }
27591+
27592+
static class E1
27593+
{
27594+
extension(S)
27595+
{
27596+
public static S operator +(S s1, S s2) => throw null;
27597+
}
27598+
}
27599+
27600+
static class E2
27601+
{
27602+
extension(in S s)
27603+
{
27604+
public static S operator +(S s1, S s2) => throw null;
27605+
}
27606+
}
27607+
""";
27608+
var comp = CreateCompilation(src);
27609+
comp.VerifyEmitDiagnostics(
27610+
// (1,5): error CS0034: Operator '+' is ambiguous on operands of type 'S' and 'S'
27611+
// _ = new S() + new S();
27612+
Diagnostic(ErrorCode.ERR_AmbigBinaryOps, "new S() + new S()").WithArguments("+", "S", "S").WithLocation(1, 5));
27613+
27614+
var tree = comp.SyntaxTrees.First();
27615+
var model = comp.GetSemanticModel(tree);
27616+
var binary = GetSyntax<BinaryExpressionSyntax>(tree, "new S() + new S()");
27617+
Assert.Null(model.GetSymbolInfo(binary).Symbol);
27618+
}
27619+
27620+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79171")]
27621+
public void RemoveWorseMembers_02()
27622+
{
27623+
// by-value vs. in parameter, static operator
27624+
var src = """
27625+
_ = new S() + new S();
27626+
27627+
struct S { }
27628+
27629+
static class E1
27630+
{
27631+
extension(S)
27632+
{
27633+
public static S operator +(S s1, S s2) => throw null;
27634+
}
27635+
}
27636+
27637+
static class E2
27638+
{
27639+
extension(S)
27640+
{
27641+
public static S operator +(in S s1, S s2) => throw null;
27642+
}
27643+
}
27644+
""";
27645+
var comp = CreateCompilation(src);
27646+
comp.VerifyEmitDiagnostics();
27647+
27648+
var tree = comp.SyntaxTrees.First();
27649+
var model = comp.GetSemanticModel(tree);
27650+
var binary = GetSyntax<BinaryExpressionSyntax>(tree, "new S() + new S()");
27651+
AssertEx.Equal("S E1.<G>$3B24C9A1A6673CA92CA71905DDEE0A6C.op_Addition(S s1, S s2)", model.GetSymbolInfo(binary).Symbol.ToTestDisplayString());
27652+
}
2758127653
}
2758227654
}

0 commit comments

Comments
 (0)