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

Witnesses made visible in FCS #9510

Merged
merged 14 commits into from
Nov 3, 2020
Merged

Witnesses made visible in FCS #9510

merged 14 commits into from
Nov 3, 2020

Conversation

dsyme
Copy link
Contributor

@dsyme dsyme commented Jun 19, 2020

This is an FCS feature requested by @alfonsogarciacaro for Fable and also relevant to WebSharper and others

It surfaces the information about witness passing through the FCS API

This will make F# transpilers more semantically accurate

The key additions can be seen in the signatrue files, e.g.

type FSharpExpr =
   ....
    /// Like Call but also indicates witness arguments
    val (|CallWithWitnesses|_|) : FSharpExpr -> (FSharpExpr option * FSharpMemberOrFunctionOrValue * FSharpType list * FSharpType list * FSharpExpr list * FSharpExpr list) option 

    /// Indicates a witness argument index from the witness arguments supplied to the enclosing method
    val (|WitnessArg|_|) : FSharpExpr -> int option

type FSharpMemberOrFunctionOrValue = 

    /// Check if this method has an entrpoint that accepts witness arguments and if so return
    /// the name of that entrypoint and the types of the witness arguments
    member GetWitnessPassingInfo: unit -> (string * IList<FSharpType>) option

TODO

  • testing
  • hopefully @alfonsogarciacaro can check if the information is sufficient for Fable

KevinRansom
KevinRansom previously approved these changes Jun 20, 2020
@alfonsogarciacaro
Copy link
Contributor

This is great, @dsyme, thanks a lot! I can PR some tests to this branch next week with SRTP samples that have been reported recently as not being resolved correctly by Fable 👍

@KevinRansom
Copy link
Member

@dsyme , this is marked as wip, is it still a wip?

@alfonsogarciacaro
Copy link
Contributor

@dsyme I've built FCS from this branch and I'm testing it with Fable: https://github.com/fable-compiler/Fable/blob/1ed140e4ffacf232ca5d14e5bee2e48e5b1c3570/src/Fable.Transforms/FSharp2Fable.fs#L548-L562

It's working but I'm facing a couple of problems:

  • The index from WitnessArg doesn't seem to be reliable. Every time I've found the pattern is always -1, so I've to make a guess and assume it's 0 if the enclosing scope does contain witnesses.
  • When visiting some expressions the following line is throwing the exception: "The lists had different lengths. list2 is 1 element shorter than list1":
    let convertedArgs = (argExprs, argTypes) ||> List.map2 (fun expr expectedTy -> mkCoerceIfNeeded g expectedTy (tyOfExpr g expr) expr)

For example I get the exception when trying to parse any of the following texts (note the message always says "list2 is 1 element shorter than list1"):

type Point =
    { x: int; y: int }
    static member Zero = { x=0; y=0 }
    static member Neg(p: Point) = { x = -p.x; y = -p.y }
    static member (+) (p1, p2) = { x= p1.x + p2.x; y = p1.y + p2.y }

type MyNumber =
    | MyNumber of int
    static member Zero = MyNumber 0
    static member (+) (MyNumber x, MyNumber y) =
        MyNumber(x + y)
    static member DivideByInt (MyNumber x, i: int) =
        MyNumber(x / i)

type MyNumberWrapper =
    { MyNumber: MyNumber }

module ArrayTests =
    testCase "Array.average works with custom types" <| fun () ->
        [|MyNumber 1; MyNumber 2; MyNumber 3|] |> Array.average |> equal (MyNumber 2)

    testCase "Array.averageBy works with custom types" <| fun () ->
        [|{ MyNumber = MyNumber 5 }; { MyNumber = MyNumber 4 }; { MyNumber = MyNumber 3 }|]
        |> Array.averageBy (fun x -> x.MyNumber) |> equal (MyNumber 4)

    testCase "Array.sum with non numeric types works" <| fun () ->
        let p1 = {x=1; y=10}
        let p2 = {x=2; y=20}
        [|p1; p2|] |> Array.sum |> equal {x=3;y=30}

    testCase "Array.sumBy with non numeric types works" <| fun () ->
        let p1 = {x=1; y=10}
        let p2 = {x=2; y=20}
        [|p1; p2|] |> Array.sumBy Point.Neg |> equal {x = -3; y = -30}

    testCase "Array.sum with non numeric types works II" <| fun () ->
        [|MyNumber 1; MyNumber 2; MyNumber 3|] |> Array.sum |> equal (MyNumber 6)

    testCase "Array.sumBy with non numeric types works II" <| fun () ->
        [|{ MyNumber = MyNumber 5 }; { MyNumber = MyNumber 4 }; { MyNumber = MyNumber 3 }|]
        |> Array.sumBy (fun x -> x.MyNumber) |> equal (MyNumber 12)

I will try to convert these into tests for this repository and send a PR tomorrow.

@dsyme
Copy link
Contributor Author

dsyme commented Jun 26, 2020

@alfonsogarciacaro Thank you so much for trialling this, I'll take a look at the problems you mention and get things under test too.

@dsyme
Copy link
Contributor Author

dsyme commented Jun 26, 2020

For example I get the exception when trying to parse any of the following texts (note the message always says "list2 is 1 element shorter than list1"):

Do you know if you were using the FSharp.Core from a nuget package (without witness passing) or the freshly built FSharp.Core (with witness passsing)

@alfonsogarciacaro
Copy link
Contributor

Ah, I had a feeling it might be related to FSharp.Core. I was indeed using the one from Nuget, let me try with a freshly built one.

@dsyme
Copy link
Contributor Author

dsyme commented Jun 26, 2020

Ah, I had a feeling it might be related to FSharp.Core. I was indeed using the one from Nuget, let me try with a freshly built one.

Well, we need to be robust when using the nuget one, I was just more asking for my own information when I look into this

@alfonsogarciacaro
Copy link
Contributor

Hmm, I tried using the artifacts/bin/FSharp.Core/Proto/netstandard2.0/FSharp.Core.dll file I got after running fcs/build.sh in this branch, both for the Tests project and Fable itself but still getting the same error :/

As a side note, I must say that building this repo in macOS is a breeze compared to what it used to be. Kudos to everybody involved in improving this!

@brettfo brettfo changed the base branch from master to main August 19, 2020 20:02
@ncave
Copy link
Contributor

ncave commented Sep 17, 2020

Adding --langversion:preview (see #10140) seems to be breaking FCS tests here.

@dsyme dsyme changed the title [WIP] Witnesses made visible in FCS Witnesses made visible in FCS Oct 24, 2020
@cartermp
Copy link
Contributor

FYI @dsyme @alfonsogarciacaro we are planning on release FCS 38 alongside F# 5, which is just in a few short weeks. If this is important to get in by then, we should prioritize addressing all outstanding issues with this one so that it's not a mad rush to publish.

@alfonsogarciacaro
Copy link
Contributor

For what it concerns Fable, right now we are using a custom build of FCS so we don't depend on the package, so please don't rush things just to let this in, we can build from this repo later (we can even build from the branch). Although other projects like Websharper may do be waiting for this to be included in the FCS package, see dotnet-websharper/core#1113

@alfonsogarciacaro
Copy link
Contributor

In contrast, in the FSharpExprConvert.GetWitnessArgs call stack there's a point where the constraints of the type parameters are set. Maybe something like that is missing in .GetWitnessPassingInfo()?

FSharpExprConvert.GetWitnessArgs 
> ConstraintSolver.CodegenWitnessesForTyparInst
> ConstraintSolver.FreshenTypeInst
> ConstraintSolver.FreshenAndFixupTypars
> ConstraintSolver.FixupNewTypars

(tpsorig, tps) ||> List.iter2 (fun tporig tp -> tp.SetConstraints (CopyTyparConstraints m tprefInst tporig))

@dsyme
Copy link
Contributor Author

dsyme commented Oct 30, 2020

@alfonsogarciacaro Thanks, I'm setting things up to repro your situation

I assume the README in lib\fcs in the Fable repro is accurate?

C:\GitHub\dsyme\Fable>more lib\fcs\README.md
# FSharp.Compiler.Service

This binary is generated by the following steps:

- Clone https://github.com/ncave/fsharp
- Check out `service_slim` branch
- Run `bash fcs/build.sh`
- Copy `artifacts/bin/FSharp.Compiler.Service/Release/netstandard2.0/FSharp.Compiler.Service.*`
- Copy `artifacts/bin/FSharp.Compiler.Service/Release/netstandard2.0/FSharp.Core.*`

@dsyme
Copy link
Contributor Author

dsyme commented Oct 30, 2020

Actually I guess I want this branch

service_slim_fcsw -> ncave/service_slim_fcsw

@dsyme
Copy link
Contributor Author

dsyme commented Oct 30, 2020

@ncave I'm have some trouble building ncave/service_slim_fcsw. I get

C:\GitHub\dsyme\ncave\src\buildtools\buildtools.targets(30,5): error MSB3073: The command ""C:\Program Files\dotnet\dotnet.exe" "C:\GitHub\dsyme\ncave\artifacts\\bin\fslex\Release\netcoreapp3.1\fslex.dll" -o "C:\GitHub\dsyme\ncave\artifacts\obj\FSharp.Compiler.Private\Proto\net472\illex.fs" --unicode --lexlib Internal.Utilities.Text.Lexing ..\absil\illex.fsl" exited with code 1. [C:\GitHub\dsyme\ncave\src\fsharp\FSharp.Compiler.Private\FSharp.Compiler.Private.fsproj]

after running

.\build.cmd

in that branch. I'll try various techniques to unblock

@alfonsogarciacaro
Copy link
Contributor

alfonsogarciacaro commented Oct 30, 2020

@dsyme Yes, the instructions are correct. And for the witnesses you are correct it is ncave/fsharp:service_slim_fcsw branch. I think you get the error if you run ./build.cm, you must run bash fcs/build.sh (that is, the script in the "fcs" directory) instead. I assume in Windows you can use git bash to run the script, but its contents are just:

dotnet build -c Release src/buildtools/buildtools.proj
dotnet build -c Release src/fsharp/FSharp.Compiler.Service

Actually , the fable:witnesses-repro already contains the FCS binaries, so you only need to build again if you want to make a change and test it.

@alfonsogarciacaro
Copy link
Contributor

alfonsogarciacaro commented Oct 30, 2020

A full script to recompile FCS and test it with Fable, assuming you're in Fable directory and ncave/fsharp:service_slim_fcsw is in the "ncave" sibling directory, would be:

cd ..\ncave
dotnet build -c Release ../ncave/src/buildtools/buildtools.proj
dotnet build src/fsharp/FSharp.Compiler.Service -c Release
cd ..\fable
copy /y ..\ncave\artifacts\bin\FSharp.Compiler.Service\Release\netstandard2.0\FSharp.Compiler.Service.* lib\fcs\
copy /y ..\ncave\artifacts\bin\FSharp.Compiler.Service\Release\netstandard2.0\FSharp.Core.* lib\fcs\
dotnet run -p src/Fable.Cli -- src/quicktest

@dsyme
Copy link
Contributor Author

dsyme commented Oct 30, 2020

OK, the problem with List.sum repros in main as a regression when taking quotations of code involving List.sum (when trying to generate the quotation data).

@cartermp This is a regression, I presume we may see this in the wild. I will add a separate issue for this.

type Point =
    { x: int; y: int }
    static member Zero = { x=0; y=0 }
    static member (+) (p1, p2) = { x= p1.x + p2.x; y = p1.y + p2.y }
let p1 = {x=1; y=10}
let p2 = {x=2; y=20}

<@ List.sum [p1] @>

@dsyme
Copy link
Contributor Author

dsyme commented Oct 30, 2020

Tracked here: #10364

@dsyme
Copy link
Contributor Author

dsyme commented Oct 30, 2020

@alfonsogarciacaro I think I'm doing this right, that QuickTest now seems to pass:

C:\GitHub\dsyme\Fable>dotnet run -p src/Fable.Cli -- src/quicktest
Fable: F# to JS compiler 3.0.0-nagareyama-beta-004
Thanks to the contributor! @vbfox
src\quicktest> cmd /C "dotnet" restore QuickTest.fsproj
  Determining projects to restore...
  Restored C:\GitHub\dsyme\Fable\src\quicktest\QuickTest.fsproj (in 406 ms).
Parsing src\quicktest\QuickTest.fsproj...
Initializing F# compiler...
Compiling src\quicktest\QuickTest.fsproj...
F# compilation finished in 2454ms
Compiled src\quicktest\QuickTest.fs
Fable compilation finished in 904ms

@dsyme
Copy link
Contributor Author

dsyme commented Oct 30, 2020

This is ready once @alfonsogarciacaro and @ncave confirm it works for Fable without additional issues

@alfonsogarciacaro
Copy link
Contributor

This is awesome @dsyme, thanks a lot for all your help! I've merged your latest changes and all Fable tests are passing now 🎉 🎉 🎉

GetWitnessPassingInfo still doesn't seem to work, but the cases where BasicPatterns.TraitCall appears without inlining can be resolved by simply selecting the appropriate method using the trait info.

The performance fix is also very welcome! So far when we were building active patterns by composing BasicPatterns (so we were visiting expressions more than once) there was always a performance hit, and this was probably the reason.

The trial by fire will now be to compile FSharpPlus with Fable ;)

@dsyme
Copy link
Contributor Author

dsyme commented Nov 2, 2020

This is awesome @dsyme, thanks a lot for all your help! I've merged your latest changes and all Fable tests are passing now 🎉 🎉 🎉

This is great. This PR is now ready to merge

The trial by fire will now be to compile FSharpPlus with Fable ;)

Just a word on this: that library is complex and relies on baroque aspects of SRTP resolution that use the feature in ways that have never been recommended F# practice, and which to be honest I believe make for a poor user experience (e.g. in error messages, simplicity and compiler performance, let alone the problem I have with throwing the Functor/Applicative/... computational abstractions at beginners who deeply don't need them). I occasionally use it as a stress test, and use it as a way to isolate out test cases that capture the exact nature of those baroque corners, and it's useful for flushing those out. It's those individual extracted tests - the existing ones are already in this repo - that I consider the acceptance criteria. If the library does cause problems, please extract out a minimal test case, and we'll fix it as a separate bug.

@dsyme dsyme requested a review from KevinRansom November 2, 2020 23:25
@dsyme
Copy link
Contributor Author

dsyme commented Nov 2, 2020

@KevinRansom @TIHan @cartermp Can I have a review on this please? It's ready to go in.

Copy link
Member

@KevinRansom KevinRansom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this Don

Copy link
Contributor

@cartermp cartermp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - been following along as this progressed. Lots of formatting changes but they're all for the better.

@cartermp cartermp merged commit 05b0569 into main Nov 3, 2020
@cartermp cartermp deleted the feature/fcsw branch November 3, 2020 01:32
@alfonsogarciacaro
Copy link
Contributor

The release candidate of Fable 3 has been published with these changes and it's working flawlessly (at least in my tests. Thanks again for all your work @dsyme!

Also, not entirely sure if it's all due to the performance fix in this PR but I made another simple benchmark of the compiler and the Fable part compilation (after FCS ParseAndCheck) is now around 25% faster! 🚀 This is in the addition to the performance improvements that were already presented at F# eXchange.

@forki
Copy link
Contributor

forki commented Nov 7, 2020

Awesome! So exciting

nosami pushed a commit to xamarin/visualfsharp that referenced this pull request Feb 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants