Search code examples
reflectionf#cilil

"unmanaged" generic parameter constraint in IL


When I compile the following code:

type Class1<'T when 'T : unmanaged> =
    class end

type Class2<'T> =
    class end

in IL it looks like this:

.class auto ansi serializable nested public Class1`1<T> extends [mscorlib]System.Object

.class auto ansi serializable nested public Class2`1<T> extends [mscorlib]System.Object

Is the unmanaged constraint saved somewhere? If so, where and how can I programatically obtain it?

In this question, I read it is somewhere in the "emdbedded signature file". What is that?


Solution

  • These constraint are located in the entity data stored in FSharpSignatureData managed resource. It is possible to browse them using F# Metadata Reader from F# PowerPack:

    public static IList<FSharpGenericParameterConstraint> GetFSharpGenericParameterConstraints(Type genericType, int position)
    {
        return GetFSharpGenericParameterConstraints(genericType.GetGenericArguments()[position]);
    }
    
    public static IList<FSharpGenericParameterConstraint> GetFSharpGenericParameterConstraints(Type genericParameter)
    {
        var declMethod = genericParameter.DeclaringMethod;
        var declType = genericParameter.DeclaringType;
        var fsAsm = FSharpAssembly.FromAssembly(genericParameter.Assembly);
        int pos = genericParameter.GenericParameterPosition;
        var entities = AllEntities(fsAsm.Entities);
        if(declMethod != null)
        {
            var member = entities.SelectMany(e => e.MembersOrValues).First(m => m.ReflectionMemberInfo == declMethod);
            return member.GenericParameters[pos].Constraints;
        }else if(declType != null)
        {
            var entity = entities.First(e => e.ReflectionType == declType);
            return entity.GenericParameters[pos].Constraints;
        }
        return null;
    }
    
    private static IEnumerable<FSharpEntity> AllEntities(IEnumerable<FSharpEntity> entities)
    {
        return entities.Concat(entities.SelectMany(e => AllEntities(e.NestedEntities)));
    }
    

    bool unmanaged = GetFSharpGenericParameterConstraints(typeof(MyModule.Class1<>), 0).Any(c => c.IsUnmanagedConstraint);