Roslyn: Usage of dynamic in local methods generates invalid IL

Created on 25 Feb 2020  路  3Comments  路  Source: dotnet/roslyn

Version Used: Microsoft (R) Visual C# Compiler version 3.4.1-beta4-19614-01 (16504609)

Steps to Reproduce:

  1. Take the following snippet:
using System;
using System.Linq;

namespace DyanmicAndLocalMethodRepro
{
    internal class Program
    {
        class DynamicInsideLocalMethod
        {
            public void Test()
            {
                var one = new One[10];
                var two = new Two[10];

                int weaponCount = CheckSlots<One, Two>(one, two);

                int CheckSlots<T1, T2>(T1[] shipEquipment, T2[] slots) where T2 : class
                {
                    int count = 0;
                    int limit = slots.Length;
                    for (int i = 0; i < limit; i++)
                    {
                        T1 equipment = shipEquipment[i];
                        dynamic slot = slots[i];
                        bool slotInUse = slot != null;

                        if (equipment != null)
                        {
                            if (!slotInUse)
                            {
                                GameObject slotObj = Instantiate();
                                slot = slotObj.GetComponent<T2>();
                                slots[i] = slot;
                            }

                            count++;
                            //slot.LoadValues(equipment, i);
                        }
                        else if (slotInUse)
                        {
                            //Destroy(slot.gameObject);
                            slots[i] = null;
                        }
                    }

                    return count;
                }
            }
        }

        static GameObject Instantiate()
        {
            return new GameObject();
        }
    }

    class GameObject
    {
        public T GetComponent<T>()
        {
            return default;
        }
    }

    public class One
    {

    }

    public class Two
    {

    }
}
  1. Compile csc /t:library /debug+ /out:dynlocal.dll /debug:portable Program.cs
  2. Run peverify

Expected Behavior:

No error.

Actual Behavior:

[IL]: Error: [dynlocal.dll : DyanmicAndLocalMethodRepro.Program+DynamicInsideLocalMethod::<Test>g__CheckSlots|0_0[T1,T2]][offset 0x000000F1]  [HRESULT 0x8007000B] - An attempt was made to load a program with an incorrect format.

1 Error(s) Verifying dynlocal.dll

The generated closure environment <>o__0 reproduces the face you make when you look at the IL for the field:

.field public static class [System.Core]System.Runtime.CompilerServices.CallSite`1<class [mscorlib]System.Func`3<class [System.Core]System.Runtime.CompilerServices.CallSite,object,!!1>> '<>p__2'

Which uses a !!1 generic variable outside of a generic context. peverify errors on the load field instruction for that particular field.

Area-Compilers Bug

Most helpful comment

Here is a minimal reproduction:

class Program
{
    public static void Main()
    {
        M("");
        void M<T>(T slot)
        {
            slot = (dynamic)default;
        }
    }
}

All 3 comments

Here is a minimal reproduction:

class Program
{
    public static void Main()
    {
        M("");
        void M<T>(T slot)
        {
            slot = (dynamic)default;
        }
    }
}

Comparing the difference in the IL between whether CheckSlots is a local method or not, it seems that the issue is that the generated class to store the callsite should be generic, but isn't.

I'm working on a fix for this.

Was this page helpful?
0 / 5 - 0 ratings