Skip to content

Commit 6c19368

Browse files
authored
Fix checked/unchecked pair matching for extension unary operators during consumption (#78538)
1 parent 6b83c96 commit 6c19368

File tree

3 files changed

+87
-15
lines changed

3 files changed

+87
-15
lines changed

src/Compilers/CSharp/Portable/Binder/Semantics/Operators/UnaryOperatorOverloadResolution.cs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -245,22 +245,36 @@ private PairedExtensionUnaryOperatorSignatureComparer() { }
245245

246246
public bool Equals(UnaryOperatorSignature x, UnaryOperatorSignature y)
247247
{
248-
return x.Method.OriginalDefinition.ContainingType.ContainingType == (object)x.Method.OriginalDefinition.ContainingType.ContainingType &&
249-
new SourceMemberContainerTypeSymbol.ExtensionGroupingKey(x.Method.OriginalDefinition.ContainingType).Equals(
250-
new SourceMemberContainerTypeSymbol.ExtensionGroupingKey(y.Method.OriginalDefinition.ContainingType)) &&
251-
SourceMemberContainerTypeSymbol.DoOperatorsPair(x.Method.OriginalDefinition, y.Method.OriginalDefinition);
248+
if (x.Method.OriginalDefinition.ContainingType.ContainingType != (object)x.Method.OriginalDefinition.ContainingType.ContainingType)
249+
{
250+
return false;
251+
}
252+
253+
var xGroupingKey = new SourceMemberContainerTypeSymbol.ExtensionGroupingKey(x.Method.OriginalDefinition.ContainingType);
254+
var yGroupingKey = new SourceMemberContainerTypeSymbol.ExtensionGroupingKey(y.Method.OriginalDefinition.ContainingType);
255+
256+
if (!xGroupingKey.Equals(yGroupingKey))
257+
{
258+
return false;
259+
}
260+
261+
return SourceMemberContainerTypeSymbol.DoOperatorsPair(
262+
x.Method.OriginalDefinition.AsMember(xGroupingKey.NormalizedExtension),
263+
y.Method.OriginalDefinition.AsMember(yGroupingKey.NormalizedExtension));
252264
}
253265

254266
public int GetHashCode(UnaryOperatorSignature op)
255267
{
256268
var typeComparer = Symbols.SymbolEqualityComparer.AllIgnoreOptions;
257269

258270
int result = typeComparer.GetHashCode(op.Method.OriginalDefinition.ContainingType.ContainingType);
259-
result = Hash.Combine(result, new SourceMemberContainerTypeSymbol.ExtensionGroupingKey(op.Method.OriginalDefinition.ContainingType).GetHashCode());
260271

261-
foreach (var typeWithAnnotations in op.Method.OriginalDefinition.ParameterTypesWithAnnotations)
272+
var groupingKey = new SourceMemberContainerTypeSymbol.ExtensionGroupingKey(op.Method.OriginalDefinition.ContainingType);
273+
result = Hash.Combine(result, groupingKey.GetHashCode());
274+
275+
foreach (var parameter in op.Method.OriginalDefinition.AsMember(groupingKey.NormalizedExtension).Parameters)
262276
{
263-
result = Hash.Combine(result, typeComparer.GetHashCode(typeWithAnnotations.Type));
277+
result = Hash.Combine(result, typeComparer.GetHashCode(parameter.Type));
264278
}
265279

266280
return result;

src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2482,25 +2482,38 @@ static ImmutableArray<Symbol> concatMembers(ImmutableArray<Symbol> existingMembe
24822482

24832483
internal readonly struct ExtensionGroupingKey : IEquatable<ExtensionGroupingKey>
24842484
{
2485-
public readonly int ExtensionArity;
2486-
public readonly TypeSymbol ReceiverType;
2485+
public readonly NamedTypeSymbol NormalizedExtension;
24872486

24882487
public ExtensionGroupingKey(NamedTypeSymbol extension)
24892488
{
2490-
ExtensionArity = extension.Arity;
2491-
24922489
if (extension.Arity != 0)
24932490
{
24942491
extension = extension.Construct(IndexedTypeParameterSymbol.Take(extension.Arity));
24952492
}
24962493

2497-
if (extension.ExtensionParameter is { } receiverParameter)
2494+
NormalizedExtension = extension;
2495+
}
2496+
2497+
private readonly int ExtensionArity
2498+
{
2499+
get
24982500
{
2499-
ReceiverType = receiverParameter.Type;
2501+
return NormalizedExtension.Arity;
25002502
}
2501-
else
2503+
}
2504+
2505+
private readonly TypeSymbol ReceiverType
2506+
{
2507+
get
25022508
{
2503-
ReceiverType = ErrorTypeSymbol.UnknownResultType;
2509+
if (NormalizedExtension.ExtensionParameter is { } receiverParameter)
2510+
{
2511+
return receiverParameter.Type;
2512+
}
2513+
else
2514+
{
2515+
return ErrorTypeSymbol.UnknownResultType;
2516+
}
25042517
}
25052518
}
25062519

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,51 @@ static void Main()
17701770
);
17711771
}
17721772

1773+
[Fact]
1774+
public void Unary_034_Consumption_Checked_Generic()
1775+
{
1776+
var src = $$$"""
1777+
public static class Extensions1
1778+
{
1779+
extension<T1>(C1<T1>)
1780+
{
1781+
public static C1<T1> operator -(C1<T1> x)
1782+
{
1783+
System.Console.Write("regular");
1784+
return x;
1785+
}
1786+
}
1787+
extension<T2>(C1<T2>)
1788+
{
1789+
public static C1<T2> operator checked -(C1<T2> x)
1790+
{
1791+
System.Console.Write("checked");
1792+
return x;
1793+
}
1794+
}
1795+
}
1796+
1797+
public class C1<T>;
1798+
1799+
class Program
1800+
{
1801+
static void Main()
1802+
{
1803+
var c1 = new C1<int>();
1804+
_ = -c1;
1805+
1806+
checked
1807+
{
1808+
_ = -c1;
1809+
}
1810+
}
1811+
}
1812+
""";
1813+
1814+
var comp = CreateCompilation(src, options: TestOptions.DebugExe);
1815+
CompileAndVerify(comp, expectedOutput: "regularchecked").VerifyDiagnostics();
1816+
}
1817+
17731818
[Theory]
17741819
[CombinatorialData]
17751820
public void Increment_001_Declaration([CombinatorialValues("++", "--")] string op)

0 commit comments

Comments
 (0)