Why I cannot have generic unmanaged struct in F#? May be Cell<'T when 'T: unmanaged> is not unmanaged, then how I can fix that?
type FloatCell =
    struct
        val x: float
        val y: nativeptr<FloatCell>
    end
    
[<Struct>]
[<StructLayout(LayoutKind.Sequential)>]
type Cell<'T when 'T: unmanaged> =
    struct
        val x: 'T
        val y: nativeptr<Cell<'T>>
    end   
Gives
error FS0001: A generic construct requires that the type 'Cell<'T>' is an unmanaged type [E:\dzmitry\src\uncorefx\src\uncorefx\uncorefx.fsproj]
UPDATE:
C# has same.
   unsafe struct FloatCell
    {
        public float val;
        public FloatCell* next;
    }
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    unsafe struct Cell<T> where T: unmanaged
    {
        public float val;
        public Cell<T>* next;
    }
With error:
error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('Program.Cell')
I do not think it is managed.
UPDATE2:
I tried attributes. Did not help. I have used extension property for cast. Possible solution. But question why I cannot do that natively? Or I can do? Or should I raise C#/F# issue?
[<Struct>]
[<NativeCppClass>]
[<System.Runtime.CompilerServices.UnsafeValueType>]
[<StructLayout(LayoutKind.Sequential)>]
type Cell<'T when 'T: unmanaged> =
    struct
        val element: 'T
        val next:  voidptr
    end    
type Cell<'T when 'T: unmanaged> with
    member  x.Next = x.next |> NativePtr.ofVoidPtr<'T> 
UPDATE3:
I have tried to wrap up pointers, and got into the issue without pointers.
    public struct UnmanagedStruct
    {
    }
    public struct UnmanagedStructWithSpecifiedGenerics
    {
        public EmptyCell<float> cell;
    }
    public ref struct RefUnmanagedStruct
    {
        public EmptyCell<float> cell;
    }
    public  struct EmptyCell<T> where T : unmanaged
    {
    }
And then instantiate:
        var compiles1 = new UnmanagedStructWithSpecifiedGenerics();
        var compiles2 = new EmptyCell<UnmanagedStruct>();
        var CS8377_1 = new EmptyCell<EmptyCell<float>>();
        var CS8377_1 = new EmptyCell<UnmanagedStructWithSpecifiedGenerics>();
        var CS0306 = new EmptyCell<RefUnmanagedStruct>();
Leads to:
error CS8377: The type 'EmptyCell' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'EmptyCell'
error CS8377: The type 'UnmanagedStructWithSpecifiedGenerics' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'EmptyCell'
error CS0306: The type 'RefUnmanagedStruct' may not be used as a type argument
Wrong error message? Should I raise issue onto Roslyn compiler?
It appears to be by design, though I'm not sure of the reason for the limitation. Here's a quote from the F# spec:
5.2.9 Unmanaged Constraints
An unmanaged constraint has the following form:
typar : unmanagedDuring constraint solving (§14.5), the constraint
type : unmanagedis met if type is unmanaged as specified below:
- Types
sbyte,byte,char,nativeint,unativeint,float32,float,int16,uint16,int32,uint32,int64,uint64,decimalare unmanaged.- Type
nativeptr<type>is unmanaged.- A non-generic struct type whose fields are all unmanaged types is unmanaged.
Note non-generic struct types are explicitly mentioned in the last bullet.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With