Skip to content

Wrong SRTP constraints inferred #1306

@gusty

Description

@gusty

Long time ago I was trying to define generic constants, something like the existing GenericZero and GenericOne, but involving a method constraint of a typar and a specific type since we can't simulate static member outside the F# compiler.
But writing those signatures were not possible because of this limitation the only solution I found was involving a phantom type:

type M() =
    static member ($) (x:string, M) = ""
    static member ($) (x:int   , M) = 0
    static member ($) (x:float , M) = 0.0

let inline empty< ^R, ^M when (^R or ^M) : (static member ($) : ^R * M ->  ^R) and ^M :> M> =
    let m = M()
    ((^R or ^M) : (static member ($): ^R * M -> ^R ) (Unchecked.defaultof<'R>, m))

let a :int    = empty<  _ , M >
let b :string = empty<  _ , M >

But now that there is a PR which solves that issue I tried again using that version and found that in fact that limitation was hiding a bug in the type inference.

Repro steps

. Download the fixed F# compiler
. type build
. open it with Visual Studio
. Set FSIANYCPU as Start Project
. Press F5
. Paste this code:

type M() =
    static member ($) (x:string, M) = ""
    static member ($) (x:int   , M) = 0
    static member ($) (x:float , M) = 0.0

let inline empty< ^R when ( ^R or  M) : (static member ( $ ) :  ^R *  M ->  ^R)> =        
    let m = M()
    Unchecked.defaultof< ^R> $ m: ^R

Expected behavior

val inline empty< ^R when ( ^R or  M) : (static member ( $ ) :  ^R * M ->  ^R) > :
   ^R when ( ^R or  M) : (static member ( $ ) :  ^R * M ->  ^R)

Actual behavior

It fails to compile with this error:

      Unchecked.defaultof< ^R> $ (m:M) : ^R;;
  ----^^^^^^^^^^^^^^^^^^^^^^^^
stdin(155,5): error FS0001: A type parameter is missing a constraint 'when ( ^R or  ^_arg2) : (static member ( $ ) :  ^R *  ^_arg2 ->  ^R)'

Known workarounds

No workaround found apart from the phantom type solution above mentioned which is very ugly.

Related information

Branch:

BTW: why in cases like this (even without the fix) the compiler complains about a missing constraint instead of inferring it for you as it does normally?

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugImpact-Medium(Internal MS Team use only) Describes an issue with moderate impact on existing code.Ready

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions