Incorrect generic parameter for invocation of constructor on generic type #343

Open
kg opened this Issue May 27, 2012 · 1 comment

1 participant

@kg
kg commented May 27, 2012

Hi,

It seems like ILAst is generating incorrect generic parameters for invocations of constructors on generic types. This doesn't seem to negatively affect the generated C# from decompilation but it seems to be semantically wrong - the MethodReference for the constructor uses generic method parameter references (like !!0) instead of type parameter references (T).

For example, this function:

    public static List<string> MyToList1(IEnumerable<string> source)
    {
        return new List<string>(source);
    }

Produces this IL:

.method public hidebysig static 
    class [mscorlib]System.Collections.Generic.List`1<string> MyToList1 (
        class [mscorlib]System.Collections.Generic.IEnumerable`1<string> source
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 12 (0xc)
    .maxstack 2
    .locals init (
        [0] class [mscorlib]System.Collections.Generic.List`1<string> CS$1$0000
    )

    IL_0000: nop
    IL_0001: ldarg.0
    IL_0002: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>)
    IL_0007: stloc.0
    IL_0008: br.s IL_000a

    IL_000a: ldloc.0
    IL_000b: ret
} // end of method Program::MyToList1

However, if you inspect the actual newobj ILExpression, the Operand is:

{System.Void System.Collections.Generic.List`1<System.String>::.ctor(System.Collections.Generic.IEnumerable`1<!0>)}

For comparison, the actual signature of that constructor according to ILSpy is:

.method public hidebysig specialname rtspecialname 
    instance void .ctor (
        class System.Collections.Generic.IEnumerable`1<!T> collection
    ) cil managed 
{

As I understand it, the !0 form of a generic parameter refers to a generic method's generic parameters - in this case, neither the calling method or the constructor are generic, so they cannot have any generic method parameters. I would expect the parameter to be !T or T here.

Is this a bug in ILSpy or am I just missing a detail about how MSIL works? In my case, I'm using the Operand from the newobj to identify which particular constructor overload is being invoked, and this discrepancy makes it impossible for me to locate the actual overload at work here. Is !0 a positional reference to something else in the expression?

@kg
kg commented May 27, 2012

Oh, I see... !0 is different from !!0, so I think that's a positional reference to a type parameter... so that means the first type parameter for the enclosing type, which would be T. Is this just a failure to expand the !0 to T?

Edit: Digging through the ECMA MSIL spec suggests this is the case. I've never seen the !0 form before this, though, so I assume it's intended for it not to be exposed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment