Small part of a code to highlight the problem:
open System.IO
let do_smth i (stm : #System.IO.Stream) = // val do_smth : 'a -> #Stream -> unit
(*....*)
()
type SomeOps = SomeOps with
static member op (i : int) = do_smth i
let test_currying i = do_smth i // val test_currying : 'a -> (Stream -> unit)
// NB: Stream, not #Stream
let main() =
use stm = new System.IO.MemoryStream()
test_currying 42 stm // OK, upcasted to Stream somehow
SomeOps.op 42 stm // compiler error!
Can someone explain, why is compiler’s behavior so different in last two lines? And why we lost information (about flexible #Stream) in test_currying function?
This looks like a bug to me. The compiler handles differently functions constructed using
letand functions written asstatic member.In particular, I think that it does not insert flexible types for member arguments that are not explicitly declared in the member declaration (that is, arguments that are either the result of partial function application or are created using the
funconstruct).The simplest example that demonstrates the behavior does not use flexible type and looks like this:
According to the specification (Section 14.4.2, posted by Brian in a deleted (?) answer), a flexible type that allows using supertypes should be inserted regardless of whether the invoked function is member or a let-bound value.