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 : unmanaged
During constraint solving (§14.5), the constraint
type : unmanaged
is met if type is unmanaged as specified below:
- Types
sbyte
,byte
,char
,nativeint
,unativeint
,float32
,float
,int16
,uint16
,int32
,uint32
,int64
,uint64
,decimal
are 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