Fable: Cannot resolve inline trait call

Created on 11 Jun 2020  路  15Comments  路  Source: fable-compiler/Fable

Description

I'm trying to work around compiler limitations with method overloading similarly to how libraries like Fleece and F#+ do. Unfortunately it doesn't look like this can be properly resolved with Fable at the moment.

It would be great if we can get this working as not only does it give us a workaround for dealing with JS libraries that give us a million overloads, but also enable more powerful support from F#+ (potentially things like generic computation expressions).

Repro code

REPL

Expected and actual results

Expected:

module Test = begin
  val str : RecoilValue<string,ReadWrite> = { Value = "test"
                                              Mode = { Test = () } }
  val asy : RecoilValue<string,ReadWrite> = { Value = "test"
                                              Mode = { Test = () } }
  val asyF : RecoilValue<(string -> string),ReadWrite> =
    { Value = <fun:asyF@29>
      Mode = { Test = () } }
end

Actual:

FABLE: Cannot resolve trait call OfRecoil - Inline call from .(26,14)
(22,47)
FABLE: Cannot resolve trait call OfRecoil - Inline call from .(27,55)
(22,47)
witnesses

All 15 comments

Probably related: https://github.com/fable-compiler/Fable/issues/1962#issuecomment-641986203

Unfortunately the way to resolve SRTPs is different in Fable and the F# compiler. This is because the F# AST doesn't include SRTP resolution so Fable has to do its own simplistic one.

I was hoping the latest changes in FCS would provide more information in the TypedTree to help with SRTP resolution but I'm not so sure anymore. Maybe @ncave has some ideas?

I gave this a try. Unfortunately it seems that witnesses are not helping with this. Probably it's because Fable still has its own way to resolve locally inlined lambdas but I tried to move iOfRecoil outside the Invoke scope and the result is the same. I also tried removing the unsafe unbox casts to no avail. TBH, I don't really understand the code, I can see the results are different when compiling with .NET but I don't know how the overloads are supposed to resolve.

The main point of this code is a way to work around the fact that method overloads don't work well with generics, and so by passing the second parameter it lets us properly resolve the correct method call based on the type of the first parameter.

Put simply the methods below would always print "1" regardless of the input type:

type Testing =
    static member test (value: 'T) = printfn "1"
    static member test (value: Async<'T>) = printfn "2"
    static member test (value: Async<'U -> 'T>) = printfn "3"

This doesn't reproduce anymore, using the give repro in the latest REPL. Prints the values Test.str, Test.asy, and Test.asyF without issue.

Hmm, if I'm not mistaken this is still an issue because the code should print "1, 2, 3" to show the correct overloads are being picked (right now it shows "1, 1, 1"). Not sure how the casting with unbox is affecting the overload resolution though. TBH I forgot how the overload resolution worked in Fable, I need to check again 馃槄 Or maybe we can try with latest FCS, seems some issues with witnesses reported by @ncave (we currently have a "hack" in the Fable FCS to ignore witnesses errors) have been recently fixed: https://github.com/dotnet/fsharp/pull/11388

Yeah, might be worth doing an update to FCS for sure. Issues like this were only recently resolved at the FCS boundary layer.

I tried to merge current dotnet/fsharp main with ncave/fsharp fable (the FCS fork Fable uses) but there are many conflicts. If @ncave can help that'd be great. Or I can try to go slowly fixing the conflicts.

@alfonsogarciacaro I'll take a look.

My bad, the actual branch is ncave/fsharp service_slim. Luckily there are not so many conflicts there :)

@alfonsogarciacaro

  • For Fable, rebasing ncave/fsharp service_slim branch to latest is done.
    Please note there have been many upstream naming changes you may have to adapt to.
  • For Fable REPL and fable-compiler-js, rebasing the ncave/fsharp fable branch will take a bit longer.

Thanks a lot @ncave! I fixed the build errors in #2442, though I'm getting some warnings about dependencies when building:

/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277: Found conflicts between different versions of "System.Reflection.Metadata" that could not be resolved. [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277: There was a conflict between "System.Reflection.Metadata, Version=1.4.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" and "System.Reflection.Metadata, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:     "System.Reflection.Metadata, Version=1.4.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" was chosen because it was primary and "System.Reflection.Metadata, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" was not. [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:     References which depend on "System.Reflection.Metadata, Version=1.4.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" [/usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/3.1.0/ref/netcoreapp3.1/System.Reflection.Metadata.dll]. [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:         /usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/3.1.0/ref/netcoreapp3.1/System.Reflection.Metadata.dll [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:           Project file item includes which caused reference "/usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/3.1.0/ref/netcoreapp3.1/System.Reflection.Metadata.dll". [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:             /usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/3.1.0/ref/netcoreapp3.1/System.Reflection.Metadata.dll [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:     References which depend on "System.Reflection.Metadata, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" []. [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:         /home/alfonso/repos/Fable/lib/fcs/FSharp.Compiler.Service.dll [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:           Project file item includes which caused reference "/home/alfonso/repos/Fable/lib/fcs/FSharp.Compiler.Service.dll". [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:             ../../lib/fcs/FSharp.Compiler.Service.dll [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:             /home/alfonso/repos/Fable/src/Fable.Transforms/bin/Release/netstandard2.0/Fable.Transforms.dll [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277: Found conflicts between different versions of "System.Collections.Immutable" that could not be resolved. [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277: There was a conflict between "System.Collections.Immutable, Version=1.2.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" and "System.Collections.Immutable, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:     "System.Collections.Immutable, Version=1.2.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" was chosen because it was primary and "System.Collections.Immutable, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" was not. [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:     References which depend on "System.Collections.Immutable, Version=1.2.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" [/usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/3.1.0/ref/netcoreapp3.1/System.Collections.Immutable.dll]. [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:         /usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/3.1.0/ref/netcoreapp3.1/System.Collections.Immutable.dll [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:           Project file item includes which caused reference "/usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/3.1.0/ref/netcoreapp3.1/System.Collections.Immutable.dll". [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:             /usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/3.1.0/ref/netcoreapp3.1/System.Collections.Immutable.dll [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:     References which depend on "System.Collections.Immutable, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" []. [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:         /home/alfonso/repos/Fable/lib/fcs/FSharp.Compiler.Service.dll [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:           Project file item includes which caused reference "/home/alfonso/repos/Fable/lib/fcs/FSharp.Compiler.Service.dll". [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:             ../../lib/fcs/FSharp.Compiler.Service.dll [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]
/usr/share/dotnet/sdk/5.0.202/Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3277:             /home/alfonso/repos/Fable/src/Fable.Transforms/bin/Release/netstandard2.0/Fable.Transforms.dll [/home/alfonso/repos/Fable/src/Fable.Cli/Fable.Cli.fsproj]

And when running Fable I immediate get the following error triggered here:

Initializing F# compiler...
Compiling src/fable-library/Fable.Library.fsproj...
Unhandled exception. System.Exception: unexpected
   at FSharp.Compiler.CompilerImports.k@810-29(CompilationThreadToken ctok, TcConfig tcConfig, TcAssemblyResolutions tcResolutions, TcAssemblyResolutions tcAltResolutions, TcImports frameworkTcImports, FSharpList`1 primaryAssemblyResolution, FSharpList`1 _arg60, FSharpList`1 _arg61) in /home/alfonso/repos/fsharp_fable/src/fsharp/CompilerImports.fs:line 1794
   at FSharp.Compiler.CompilerImports.BuildFrameworkTcImports@1790-1.Invoke(CancellationToken ct) in /home/alfonso/repos/fsharp_fable/src/fsharp/CompilerImports.fs:line 1790
   at [email protected](CancellationToken ct) in /home/alfonso/repos/fsharp_fable/src/fsharp/CompilerImports.fs:line 1925
   at Internal.Utilities.Library.Cancellable.runWithoutCancellation[a](Cancellable`1 comp) in /home/alfonso/repos/fsharp_fable/src/fsharp/absil/illib.fs:line 763
   at FSharp.Compiler.SourceCodeServices.CompilerStateCache.initializeCompilerState() in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Compiler.Service/service_slim.fs:line 87
   at <StartupCode$FSharp-Compiler-Service>[email protected](Unit unitVar) in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Compiler.Service/service_slim.fs:line 118
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.get_Value()
   at FSharp.Compiler.SourceCodeServices.CompilerStateCache.Get() in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Compiler.Service/service_slim.fs:line 122
   at FSharp.Compiler.SourceCodeServices.InteractiveChecker.ParseAndCheckProject(String projectFileName, String[] fileNames, FSharpFunc`2 sourceReader) in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Compiler.Service/service_slim.fs:line 240
   at Fable.Cli.Main.Util.measureTime[a](FSharpFunc`2 f) in /home/alfonso/repos/Fable/src/Fable.Cli/Main.fs:line 63
   at Fable.Cli.Main.ProjectParsed.checkProject(ProjectCracked config, InteractiveChecker checker) in /home/alfonso/repos/Fable/src/Fable.Cli/Main.fs:line 340
   at Fable.Cli.Main.ProjectParsed.Init(ProjectCracked config, FSharpOption`1 checker) in /home/alfonso/repos/Fable/src/Fable.Cli/Main.fs:line 359
   at [email protected](Unit unitVar) in /home/alfonso/repos/Fable/src/Fable.Cli/Main.fs:line 464
   at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult](AsyncActivation`1 ctxt, TResult result1, FSharpFunc`2 part2) in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Core/async.fs:line 386
   at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Core/async.fs:line 105
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.FSharp.Control.AsyncResult`1.Commit() in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Core/async.fs:line 338
   at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronouslyInAnotherThread[a](CancellationToken token, FSharpAsync`1 computation, FSharpOption`1 timeout) in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Core/async.fs:line 851
   at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken cancellationToken, FSharpAsync`1 computation, FSharpOption`1 timeout) in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Core/async.fs:line 886
   at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken) in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Core/async.fs:line 1148
   at Microsoft.FSharp.Core.ResultModule.Bind[T,TResult,TError](FSharpFunc`2 binder, FSharpResult`2 result) in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Core/result.fs:line 15
   at Fable.Cli.Entry.Runner.Run(FSharpList`1 args, String rootDir, FSharpOption`1 runProc, FSharpOption`1 fsprojPath, FSharpOption`1 watch, FSharpOption`1 testInfo) in /home/alfonso/repos/Fable/src/Fable.Cli/Entry.fs:line 111
   at [email protected](Tuple`2 _arg2)
   at Microsoft.FSharp.Core.ResultModule.Bind[T,TResult,TError](FSharpFunc`2 binder, FSharpResult`2 result) in /home/alfonso/repos/fsharp_fable/src/fsharp/FSharp.Core/result.fs:line 15
   at Fable.Cli.Entry.main(String[] argv) in /home/alfonso/repos/Fable/src/Fable.Cli/Entry.fs:line 257
System.Exception: Process exited with code 134
   at [email protected]_0001.PublishUtils.IProcess.Run(String workingDir, String exePath, String[] args)
   at FSI_0002.test()
   at <StartupCode$FSI_0002>.$FSI_0002.main@()
Stopped due to error

If it doesn't ring any bell I will try to look deeper into that later.

@alfonsogarciacaro I'm not sure, the small smoke test is passing. Perhaps if you reference FCS by project reference, we can debug it and see why it breaks.

@alfonsogarciacaro I'm guessing it could be an assembly reference mismatch, as the warnings above show.
Looks like FCS took dependence on System.Reflection.Metadata, Version=5.0.0.0.
Perhaps switching to target net5.0 will help. Here is the code around the error:

        let primaryAssemblyResolution = frameworkTcImports.ResolveAssemblyReference(ctok, primaryAssemblyReference, ResolveAssemblyReferenceMode.ReportErrors)
        let! primaryAssem = frameworkTcImports.RegisterAndImportReferencedAssemblies(ctok, primaryAssemblyResolution)
        let primaryScopeRef =
            match primaryAssem with
              | (_, [ResolvedImportedAssembly ccu]) -> ccu.FSharpViewOfMetadata.ILScopeRef
              | _ -> failwith "unexpected" // <--- throws here

@alfonsogarciacaro

Rebasing the ncave/fsharp fable branch (for Fable REPL and fable-compiler-js) is done.
There was quite a lot of code churn from upstream to adapt to, but it's fine.
I'll wait until you finish your #2442 before I submit it here.

Awesome @ncave! Thanks a lot for all this work, and also thank you for your advice. You were right, targeting net5.0 with Fable.Cli makes things work :tada: This means users only with netcore3.0 installed won't be able to run the new Fable version but I guess net5.0 is already installed in most machines even if it's not LTS.

Another very good news is I tried building service_slim removing the commit to ignore witnesses errors and it still worked! So hopefully we can remove the little hack now 馃憤

On the other hand, updating FCS doesn't seem to have an effect on this issue specifically. The compiled code still prints "1, 1, 1". However I'm still not sure how (or whether) we can fix this. It's true that running the code on top with FSI gives "1, 2, 3" but it relies on the unsafe unboxing. If we remove the unbox the code doesn't compile, but if we remove the first overload (the most generic one) the code compiles and gives the same result in dotnet and fable: REPL

So probably we can close this for now and reopen if @Shmew can provide some code without the unboxing that compiles in F#. We can continue the discussion about FCS update in #2442

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MangelMaxime picture MangelMaxime  路  3Comments

tomcl picture tomcl  路  4Comments

krauthaufen picture krauthaufen  路  3Comments

alfonsogarciacaro picture alfonsogarciacaro  路  3Comments

rommsen picture rommsen  路  3Comments