Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
Expand Down Expand Up @@ -196,6 +196,9 @@
<None Include="TestCases\ILPretty\CS1xSwitch_Release.cs" />
<Compile Remove="TestCases\ILPretty\CallIndirect.cs" />
<None Include="TestCases\ILPretty\CallIndirect.cs" />
<Compile Remove="TestCases\ILPretty\InstanceOperatorCall.cs" />
<None Include="TestCases\ILPretty\InstanceOperatorCall.cs" />
<None Include="TestCases\ILPretty\InstanceOperatorCall.il" />
<Compile Remove="TestCases\ILPretty\EmptyBodies.cs" />
<None Include="TestCases\ILPretty\EmptyBodies.cs" />
<Compile Remove="TestCases\ILPretty\TruncatedAccessorBody.cs" />
Expand Down
6 changes: 6 additions & 0 deletions ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,12 @@ public async Task CallIndirect()
await Run();
}

[Test]
public async Task InstanceOperatorCall()
{
await Run();
}

[Test]
public async Task FSharpLoops_Debug()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
public class CallSite
{
public static bool CompareVirtual<T>(Source<T> s, T a, T b)
{
return a < b;
}

public static bool CompareDirect(Source<int> s, int a, int b)
{
return a > b;
}
}
public class Source<T>
{
public virtual bool operator <(T a, T b)
{
return false;
}

public bool operator >(T a, T b)
{
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Metadata version: v4.0.30319
.assembly extern System.Runtime
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 11:0:0:0
}
.assembly InstanceOperatorCall
{
.ver 1:0:0:0
}
.module InstanceOperatorCall.dll
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY

// F# emits comparison operators as instance members, so operator metadata names appear on
// methods C# would never bind as operators: the operands are the arguments, and the operator
// lives on the receiver type rather than on either operand type.
.class public auto ansi beforefieldinit Source`1<T>
extends [System.Runtime]System.Object
{
.method public hidebysig specialname newslot virtual
instance bool op_LessThan(!T a,
!T b) cil managed
{
.maxstack 8
IL_0000: ldc.i4.0
IL_0001: ret
}

.method public hidebysig specialname
instance bool op_GreaterThan(!T a,
!T b) cil managed
{
.maxstack 8
IL_0000: ldc.i4.0
IL_0001: ret
}

.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: ret
}
}

.class public auto ansi beforefieldinit CallSite
extends [System.Runtime]System.Object
{
.method public hidebysig static bool CompareVirtual<T>(class Source`1<!!T> s,
!!T a,
!!T b) cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: callvirt instance bool class Source`1<!!T>::op_LessThan(!0,
!0)
IL_0008: ret
}

.method public hidebysig static bool CompareDirect(class Source`1<int32> s,
int32 a,
int32 b) cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: call instance bool class Source`1<int32>::op_GreaterThan(!0,
!0)
IL_0008: ret
}

.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: ret
}
}
7 changes: 7 additions & 0 deletions ICSharpCode.Decompiler/CSharp/CallBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1643,6 +1643,13 @@ OverloadResolutionErrors IsUnambiguousCall(ExpectedTargetDetails expectedTargetD
if (or.IsAmbiguous)
return OverloadResolutionErrors.AmbiguousMatch;
foundMember = or.GetBestCandidateWithSubstitutedTypeArguments();
if (foundMember == null)
{
// Overload resolution reports no error for an empty candidate set - there is no
// best candidate to carry one - so a call that matched nothing has to be reported
// as unresolvable here.
return OverloadResolutionErrors.AmbiguousMatch;
}
if (!IsAppropriateCallTarget(expectedTargetDetails, method, foundMember))
return OverloadResolutionErrors.AmbiguousMatch;
var map = or.GetArgumentToParameterMap();
Expand Down
Loading