Error: "Either the method itself or the containing type is not fully instantiated"

Topics: Metadata Model
Jan 14, 2014 at 1:43 PM
Edited Jan 14, 2014 at 1:45 PM
I'm trying to create a mutator based off the ILMutator sample which modifies some classes to make them freezable if they have a certain attribute. I inject a boolean field "isFrozen" and a method "FreezablePrecondition" which throws an exception if isFrozen is true. I then inject a call to that method into the setters of properties.

It all works fine until I try and mutate the IL of a class with generic parameters. Even then the mutator program runs fine, but when I try to invoke a method I've injected I get the error:

System.InvalidOperationException: Could not execute the method because either the method itself or the containing type is not fully instantiated.

at FreezableRewriter.TestAssembly.Generic`1.FreezablePrecondition()
at FreezableRewriter.TestAssembly.Generic`1.set_Test(T value)
at FreezableRewriter.Tests.FreezableTests.TestGenericIsFrozen()


peverify doesn't detect any problems with the assembly.

In reflector the IL for FreezablePrecondition() looks like this:
    .method private hidebysig instance void FreezablePrecondition() cil managed
    {
        .custom instance void [FreezableHelper]FreezableHelper.ReferenceFreezablePreconditionAttribute::.ctor()
        .maxstack 2
        .locals init (
            [0] bool flag)
        L_0000: nop 
        L_0001: ldarg.0 
        L_0002: ldfld bool FreezableRewriter.TestAssembly.Generic`1::isFrozen
        L_0007: ldc.i4.0 
        L_0008: ceq 
        L_000a: stloc.0 
        L_000b: ldloc.0 
        L_000c: brtrue.s L_001a
        L_000e: nop 
        L_000f: ldstr "The instance is frozen and cannot be modified."
        L_0014: newobj instance void [FreezableHelper]FreezableHelper.InstanceFrozenException::.ctor(string)
        L_0019: throw 
        L_001a: ret 
    }
As you can see it checks a local boolean (isFrozen) and throws an exception if the value is true. Again, this all works fine if the class doesn't have any generic parameters.

I tried creating a method that does something similar manually and compared the IL. The only real difference is this line:
       L_0002: ldfld bool FreezableRewriter.TestAssembly.Generic`1<!T>::test
Where, compared to the line in the injected code, the field reference has "<!T>" on the end of the location. I'm unsure how to do this in CCI (I've tried using a SpecializedFieldReference but it didn't help).

Can anyone point me in the right direction here?

Thanks,
James.
Coordinator
Jan 14, 2014 at 4:19 PM
All references to generic metadata items must refer to generic instantiations and not directly to the templates. So you must use a SpecializedFieldReference. Possibly the problem you are running into with that is that you did not specialize the containing type of the field reference. Check out TypeHelper.SpecializeTypeReference to help with that.
Marked as answer by jamesthurley on 1/14/2014 at 10:36 AM
Jan 14, 2014 at 5:34 PM
Perfect, that was the problem. Thank you!