@TIHan and I spent a while looking at the status of SRTP constraints on class type parameters.
F# is intended to only support a very limited version of this, namely
type C< ^T when ^T : (static member Foo: unit -> unit)>() =
member inline x.Method1() = ...
...
member inline x.Property1 = ...
...
Many cases of this are properly enforced, e.g. checking there are no non-inline members, or interface implementations etc. However there is another case that we should statically disallow (constructors) and there is also a case where this interacts badly with witness passing.
Problem 1 – "witness not available at runtime".
Here the problem is that a constructor attempts to make an SRTP call on ^T, e.g.
type C< ^T when ^T : (static member Foo: unit -> unit)>() =
let x = (^T : (static member Foo: unit -> unit)())
member inline x.P = 1
type B1() =
static member Foo() = ()
let cb1 = C<B1>()
We should fail if ^T is used anywhere in the constructor (which can’t be inlined). As an aside, note that record types with constrained parameters and a fully inline Create method are allowed.
type C< ^T when ^T : (static member Foo: unit -> unit)> =
{ F: unit -> unit }
member inline x.M() = x.F()
static member inline Create () : C< ^T > = { F = f< ^T > }
type B1() =
static member Foo() = printfn "hello B1"
type B2() =
static member Foo() = printfn "hello B2"
let cb1 = C<B1>.Create()
let cb2 = C<B2>.Create()
cb1.M()
cb2.M()
Problem 2 – "non-generation of witness".
In this case, one of the "inline" methods has code that requires a witness e.g. a quotation or indeed any use of the witness per RFC FS-1043 #6805. We believe this code can be fixed by removing let typs = typars |> List.skip numParentTypars in GetTraitWitnessInfosOfTypars
let inline f< ^T when ^T : (static member Foo: unit -> unit)>() = (^T : (static member Foo: unit -> unit)())
type C< ^T when ^T : (static member Foo: unit -> unit)>() =
member inline x.M() = <@ f< ^T >() @>
type B1() =
static member Foo() = printfn "hello B1"
type B2() =
static member Foo() = printfn "hello B2"
let cb1 = C<B1>()
let cb2 = C<B2>()
cb1.M()
cb2.M()
We should be careful that inline properties are still ok even even if problem 2 is fixed
@TIHan and I spent a while looking at the status of SRTP constraints on class type parameters.
F# is intended to only support a very limited version of this, namely
Many cases of this are properly enforced, e.g. checking there are no non-inline members, or interface implementations etc. However there is another case that we should statically disallow (constructors) and there is also a case where this interacts badly with witness passing.
Problem 1 – "witness not available at runtime".
Here the problem is that a constructor attempts to make an SRTP call on
^T, e.g.We should fail if ^T is used anywhere in the constructor (which can’t be inlined). As an aside, note that record types with constrained parameters and a fully inline
Createmethod are allowed.Problem 2 – "non-generation of witness".
In this case, one of the "inline" methods has code that requires a witness e.g. a quotation or indeed any use of the witness per RFC FS-1043 #6805. We believe this code can be fixed by removing
let typs = typars |> List.skip numParentTyparsinGetTraitWitnessInfosOfTyparsWe should be careful that inline properties are still ok even even if problem 2 is fixed