Upgrading my solution to FSharp.Core 4.5.1 causes an unexpected build error.
Provide the steps required to reproduce the problem
Upgrade to FSharp.Core 4.5.1.
Build solution.
Unfortunately I'm not able to provide the source code.
The solution builds successfully.
The following error occurs:
FSC : error FS0193: The module/namespace 'Control' from compilation unit 'FSharp.Core' did not contain the val '{MemberParentMangledName = Some "AsyncActivation`1"; MemberIsOverride = false; LogicalName = "OnSuccess"; TotalArgCount = 2;}' [/home/nat/Projects/shopmasse-backend/fsharp/src/Masse.SearchProduct/Masse.SearchProduct.fsproj]
Downgrade to FSharp.Core 4.5.0.
Provide any related information
dotnet --info output:
.NET Core SDK (reflecting any global.json):
Version: 2.1.302
Commit: 9048955601
Runtime Environment:
OS Name: ubuntu
OS Version: 18.04
OS Platform: Linux
RID: ubuntu.18.04-x64
Base Path: /usr/share/dotnet/sdk/2.1.302/
Host (useful for support):
Version: 2.1.2
Commit: 811c3ce6c0
.NET Core SDKs installed:
2.1.105 [/usr/share/dotnet/sdk]
2.1.302 [/usr/share/dotnet/sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.2 [/usr/share/dotnet/shared/Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.2 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.0.7 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.2 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
To install additional .NET Core runtimes or SDKs:
https://aka.ms/dotnet-download
That's rather strange, since the API diff from 4.5.0 and 4.5.1 has nothing to do with Async:

There was a source code change to move stuff out of the massive control.fs file into various other files that are appropriate for what they do, but the compiled .dll is still the same. Are there any other details you could share about your code that could give a hint?
@cartermp Unfortunately, after switching back to FSharp.Core 4.5.0, building successfully, and then switching back to FSharp.Core 4.5.1, I'm not able to reproduce this. If I figure out any kind of consistent pattern I'll report back.
Closing in favor of #5369, as discussion about a root cause is going on there.
TL;DR - later versions of FSharp.Core are not guaranteed to work (at all) with earlier versions of the F# compiler. This is likely such an occasion. The recommendation is to depend on FSharp.Core 4.2.3 (even if 4.5.0 works for you), because this is what has been tested against F# 4.1. Any combination of an F# 4.1 compiler and a later FSharp.Core package working properly is coincidental.
I just ran into this issue and would like to point out the following official bit of guidance:
Applications should target higher versions of FSharp.Core
F# applications should generally use the highest language version and the most platform-specific version of FSharp.Core.
Generally, when writing an application, you want to use the highest version of FSharp.Core available for the platform you are targeting.
How are app developers (like me) supposed to know not to upgrade to the latest version of FSharp.Core?
@brianberns That guidance is semi-official. It's mostly for library developers than anyone else. Library developers need to always target much lower versions for reach purposes.
The guidance for app developers is generally:
But to answer your question specifically, there is no way to know when or when not to upgrade. Barring any issues with the library yourself, the question of when to upgrade should be based on your project's needs.
If FSharp.Core is only guaranteed to work with a specific compiler version, what’s the purpose of releasing it separately on Nuget? The temptation to upgrade it like any other package is very strong. At the very least, there should be a prominent warning about the dependency on the Nuget page.
FSharp.Core is on NuGet because it is the delivery vehicle for dependencies in modern .NET. The fact that it's not a part of the .NET Standard or NetCoreApp is what makes things confusing and requires additional consideration.
With all due respect, that is a total non-answer. That “delivery vehicle” is breaking an unspoken, implicit dependency that developers don’t know about.
I’m a huge fan of F# and hope it continues to flourish. However, a cavalier attitude about these sort of dependencies is a recipe for disaster.
(FWIW, I’m using Visual Studio and the old-fashioned .NET Framework, so .NET Standard isn’t relevant to me.)
Well, I'm sorry that you don't accept that answer. But until a different way to distribute dependencies arises, and doesn't complicate things like the previous GAC-filled world we were in, we won't be changing this.
TL;DR - later versions of FSharp.Core are not guaranteed to work (at all) with earlier versions of the F# compiler. This is likely such an occasion. The recommendation is to depend on FSharp.Core 4.2.3 (even if 4.5.0 works for you), because this is what has been tested against F# 4.1. Any combination of an F# 4.1 compiler and a later FSharp.Core package working properly is coincidental.
Just to say that I don't personally quite subscribe to this and it wasn't the position historically.... However I appreciate that it is hard to test and may to some extent be necessary.
That is, historically whenever I have been making changes to the compiler I always take into account the consumption of generated DLLs (including FSharp.Core) by earlier F# compilers. We have always cared about this kind of backwards compat historically.
For example I am taking this into account in the nullness work.
This scenario is tested in part by our bootstrapping process, though imperfectly.
p.s. I'm not sure of the cause of the original bug.
The original bug in 4.5.1 was a binary breaking change, which is why we unlisted that package. But my goal here is to set expectations - though we don't actively try to make older compilers not work with newer FSharp.Core versions, we do not guarantee that any arbitrary older compiler will work with any newer FSharp.Core.
we do not guarantee that any arbitrary older compiler will work with any newer FSharp.Core.
Would the same apply to other generated binary files? If you produce a binary A.DLL with a new compiler, can you reference it from an old compiler (e.g. via a nuget package)? I think the answer is "yes", otherwise it becomes impossible to reliably prepare nuget packages with new compilers....
I know FSharp.Core is special case and I can see that we may intentionally apply your rule at some point.
If you produce a binary A.DLL with a new compiler, can you reference it from an old compiler (e.g. via a nuget package)?
Not if it uses a construct that the older compiler cannot read. ByRef-like structs come to mind.
Not if it uses a construct that the older compiler cannot read. ByRef-like structs come to mind.
Yes, that's generally correct, and we have done this in the past.
(For the nullness prototype I'm using a second F# metadata attribute which means previous compilers ignore the the nullness information)