Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F# compiler still treats FSharpFunc as sealed in generic constraints #9692

Closed
NinoFloris opened this issue Jul 14, 2020 · 8 comments
Closed

Comments

@NinoFloris
Copy link
Contributor

type C() =
    member _.M<'f, 'a, 'b when 'f :> FSharpFunc<'a, 'b>>(f: 'f) = ()
    error FS0698: Invalid constraint: the type used for the constraint is sealed, which means the constraint could only be satisfied by at most one solution
    error FS0663: This type parameter has been used in a way that constrains it to always be '('a -> 'b)'

And a sharplab link
https://sharplab.io/#v2:DYLgZgzgNAJiDUAfA9gBwKYDsAEBlAnhAC7oC2AsAFBH4bYDCAFAJTYC8V2X2pZARugBO2APoA6ALIAeAORgo2GQEMFMvtgDuACyyKw2EAD5sAMVxalg1CYCumAMayVivocOMwIPazbYWQA=

The idea behind using a constraint like this is to strongly box an FSharpFunc inside a struct so it can be devirtualized and potentially inlined as a result – as 'f is now a known sealed implementation for the JIT.

Partial fix mentioned in:
#3737

@TIHan
Copy link
Contributor

TIHan commented Jul 21, 2020

@dsyme will need to look at it.

FSharpFunc isn't technically sealed and you can inherit from it. Therefore, I would not expect the constraint error; I'm guessing it's to prevent this type of pattern.

I'm not sure what problem you are trying to solve. What problem requires this type of pattern?

@TIHan
Copy link
Contributor

TIHan commented Jul 21, 2020

To note: AFAIK, de-virtualization will only happen if the concrete implementation is a struct, it does not do it for reference types.

@NinoFloris
Copy link
Contributor Author

NinoFloris commented Jul 21, 2020

Mostly I was experimenting. It's to get the JIT to devirt and then inline a whole bunch of boilerplate virtual calls (lenses that must be function values in this case).

Devirtualization happens when the concrete type is known, say a visible newobj or generic specialization of a method that has a bound and is a sealed class.

Generic specialization happens if there is at least one value type involved in the generic method call.

Most likely though, bounding this example to something like:

[<Struct>]
type FuncBox<'t, 'u,'v when 't :> FSharpFunc<'u,'v>> = FuncBox of 't
    interface IFuncBox<'u,'v>

would be my obvious choice, however, the constraint still wouldn't be accepted by the compiler today.

@TIHan
Copy link
Contributor

TIHan commented Jul 24, 2020

// cc @AndyAyersMS

@NinoFloris
Copy link
Contributor Author

@TIHan any question for Andy (or me?)

@dsyme dsyme added the Bug label Sep 1, 2020
@cartermp cartermp added this to the Backlog milestone Sep 1, 2020
@dsyme
Copy link
Contributor

dsyme commented Sep 3, 2020

I'll treat this as a spec/design issue rather than saying this was ever intended to work as things stand today

  • The F# type system treates tuple and function types as "special". For example, it doesn't consider function types to be unsealed. And for tuples, it doesn't consider them comparable unless their element types are comparable.

  • The compilation representations System.Tuple, System.ValueTuple and FSharpFunc are usable directly, e.g. you can inherit from FSharpFunc. When present in .NET assemblies or F# source code these are generally de-compiled to the F# forms - we don't allow the compilation representations to really be used with the properties of the compilation representations. This is by-design as an attempt to prevent mixtures of original and representation types.

  • In this instance, the use of FSharpFunc is being decompiled to an F# function type. This is because of the following

    // Try to decode System.Tuple --> F# tuple types etc.
    let ty = g.decompileType tcref actualArgTys

This means the unsealed nature of the representation is lost to the F# programmer.

@dsyme
Copy link
Contributor

dsyme commented Sep 3, 2020

Closing, please open a language suggestion if you'd like to.

@dsyme
Copy link
Contributor

dsyme commented Sep 3, 2020

I've recorded this in the list of issues where precise language spec clarifications are needed: fsharp/fsharp.org#841

@cartermp cartermp removed this from the Backlog milestone Sep 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants