Skip to content
This repository was archived by the owner on Aug 24, 2022. It is now read-only.
This repository was archived by the owner on Aug 24, 2022. It is now read-only.

C# 7.2 "in" keyword in interfaces #1052

Description

@baehny

The in C# 7.2 introduced "in" keyword for method parameters results in a crash when used in an interface, but only if the class that is implementing the interface is cast back to the interface.
The code throws a System.InvalidCastException at runtime (Firefox 57.0.4).

Bug test project:
https://github.com/baehny/Bugs/tree/master/JSIL/JSIL_InParameters/JSIL_InParameters

using System;
public struct TestStruct
{
    public int Field;
}
public interface TestInterface
{
    void TestMethodRef(ref TestStruct testStruct);
    void TestMethodIn(in TestStruct testStruct);
}
public class TestClass : TestInterface
{
    public void TestMethodRef(ref TestStruct testStruct) { }
    public void TestMethodIn(in TestStruct testStruct) { }
}
class Program
{
    static void Main(string[] args)
    {
        TestStruct testStruct = new TestStruct();
        TestClass interfaceClass = new TestClass();

        Console.WriteLine("1:");
        interfaceClass.TestMethodRef(ref testStruct); //Works

        Console.WriteLine("2:");
        interfaceClass.TestMethodIn(testStruct); //Works

        Console.WriteLine("3:");
        ((TestInterface)interfaceClass).TestMethodRef(ref testStruct); //Works

        Console.WriteLine("4:");
        ((TestInterface)interfaceClass).TestMethodIn(testStruct); //Crash: throws System.InvalidCastException: Unable to cast object of type 'TestStruct' to type 'ref TestStruct'

        Console.WriteLine("End");
    }
}

There is no problem when using "ref" which is strange because in both cases the parameter is passed as valuetype TestStruct& but with a System.Runtime.InteropServices.InAttribute for the "in" parameter version. However the in keyword results in two definitions for TestMethodIn()

First version of TestMethodIn :

.method public hidebysig 
	instance void TestMethodIn (
		valuetype TestStruct& testStruct
	) cil managed 
{
	.param [1]
	.custom instance void [mscorlib]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
		01 00 00 00
	)
	// Method begins at RVA 0x2050
	// Code size 2 (0x2)
	.maxstack 8

	IL_0000: nop
	IL_0001: ret
} // end of method TestClass::TestMethodIn

Second version of TestMethodIn :

.method private final hidebysig newslot virtual 
	instance void TestInterface.TestMethodIn (
		valuetype TestStruct& modreq([mscorlib]System.Runtime.InteropServices.InAttribute)  testStruct
	) cil managed 
{
	.override method instance void TestInterface::TestMethodIn(valuetype TestStruct& modreq([mscorlib]System.Runtime.InteropServices.InAttribute) )
	.param [1]
	.custom instance void [mscorlib]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = (
		01 00 00 00
	)
	// Method begins at RVA 0x205c
	// Code size 8 (0x8)
	.maxstack 8

	IL_0000: ldarg.0
	IL_0001: ldarg.1
	IL_0002: call instance void TestClass::TestMethodIn(valuetype TestStruct&)
	IL_0007: ret
} // end of method TestClass::TestInterface.TestMethodIn

TestMethodRef :

.method public final hidebysig newslot virtual 
	instance void TestMethodRef (
		valuetype TestStruct& testStruct
	) cil managed 
{
	// Method begins at RVA 0x2050
	// Code size 2 (0x2)
	.maxstack 8

	IL_0000: nop
	IL_0001: ret
} // end of method TestClass::TestMethodRef

Calling code:

	IL_0037: ldstr "3:"
	IL_003c: call void [mscorlib]System.Console::WriteLine(string)
	IL_0041: nop
	IL_0042: ldloc.1
	IL_0043: ldloca.s 0
	IL_0045: callvirt instance void TestInterface::TestMethodRef(valuetype TestStruct&)
	IL_004a: nop
	IL_004b: ldstr "4:"
	IL_0050: call void [mscorlib]System.Console::WriteLine(string)
	IL_0055: nop
	IL_0056: ldloc.1
	IL_0057: ldloca.s 0
	IL_0059: callvirt instance void TestInterface::TestMethodIn(valuetype TestStruct& modreq([mscorlib]System.Runtime.InteropServices.InAttribute) )
	IL_005e: nop

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions