dotnet / dotnet/roslyn

`FindImplementationForInterfaceMember` incorrectly treats non-virtual public method in metadata as an interface implementation

Open
#77,874 1 comment 0 reactions 0 assignees View on GitHub
Area-Compilers
Dominant language
C#
Stars
20.7k
Forks
4.3k
PR merge metrics
PR metrics pending

Description

```
[Fact]
public void Test()
{
/*
public interface I1
{
void M1();
}

public class C1 : I1
{
void I1.M1()
{
System.Console.Write(1);
}
}

public class C2 : C1, I1
{
public NOTVIRTUAL void M1()
{
System.Console.Write(2);
}
}
*/
var ilSource = @"
.class interface public auto ansi abstract beforefieldinit I1
{
.method public hidebysig newslot abstract virtual
instance void M1 () cil managed
{
}
}

.class public auto ansi beforefieldinit C1
extends [mscorlib]System.Object
implements I1
{
.method private final hidebysig newslot virtual
instance void I1.M1 () cil managed
{
.override method instance void I1::M1()
.maxstack 8

IL_0000: ldc.i4.1
IL_0001: call void [mscorlib]System.Console::Write(int32)
IL_0006: ret
}

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

.class public auto ansi beforefieldinit C2
extends C1
implements I1
{
.method public hidebysig
instance void M1 () cil managed
{
.maxstack 8

IL_0000: ldc.i4.2
IL_0001: call void [mscorlib]System.Console::Write(int32)
IL_0006: ret
}

.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
.maxstack 8

IL_0000: ldarg.0
IL_0001: call instance void C1::.ctor()
IL_0006: ret
}
}
";

var source1 =
@"
class Program
{
static void Main()
{
I1 x = new C2();
x.M1();
}
}";
var compilation1 = CreateCompilationWithIL(source1, ilSource, options: TestOptions.DebugExe);

CompileAndVerify(compilation1, expectedOutput: "1").VerifyDiagnostics();

var i1M1 = compilation1.GetMember("I1.M1");
var c2 = compilation1.GetTypeByMetadataName("C2");

// Expected: C1.I1.M1 because that is what is getting called
AssertEx.Equal("void C2.M1()", c2.FindImplementationForInterfaceMember(i1M1).ToTestDisplayString());
}
```

Note, rules for methods declared in source are different.

Should check behavior in VB as well.

Contributor guide

Open the contributing guide

Research direction

Start with the embedded IL and the Test method in the issue, then run the regression through FindImplementationForInterfaceMember and inspect the returned symbol for C2. Compare the behavior with source-declared methods and add the requested Visual Basic check; done means the API identifies the interface implementation that is actually invoked rather than the non-virtual metadata method.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.