Skip to content

Migrate to the .NET 10 SDK - #244

Open
nojaf wants to merge 2 commits into
fsprojects:masterfrom
nojaf:update-all-things
Open

Migrate to the .NET 10 SDK#244
nojaf wants to merge 2 commits into
fsprojects:masterfrom
nojaf:update-all-things

Conversation

@nojaf

@nojaf nojaf commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Move global.json to 10.0.100 and retarget every net6.0 project to net10.0: the fslex and fsyacc tools, the Expecto test projects and the example projects. The shipped FsLexYacc.targets and the NuGet template now point at build/fslex/net10.0 and build/fsyacc/net10.0, so consumers of the tools package need a .NET 10 runtime.

FSharp.Core 10 — is this reasonable?

@dsyme @T-Gro @baronfel — I'd like a sanity check on one part of this before merging.

This raises the FSharp.Core floor for FsLexYacc.Runtime from >= 4.6.2 to >= 10.1.400. That is a big jump for a package that a lot of people take a transitive dependency on, so I don't want to do it quietly.

My reasoning is that the older versions are no longer usable on the .NET 10 SDK, not merely old:

  • 4.6.2 and 4.7.2 make the compiler emit dynamic arithmetic instead of inlining it. The tests fail at runtime with Dynamic invocation of op_Subtraction is not supported, thrown from Position.Column in Lexing.fs — which is a plain int - int.
  • 6.0.0 gets past that but breaks dotnet publish with NETSDK1152, because the package ships FSharp.Core.xml under both netstandard2.0 and netstandard2.1 content files and the SDK now rejects the collision.

So the floor has to move; the question is how far. I went to 10 because that is what the compiler repo itself ships and consumes (FSharpCoreShippedPackageVersionValue is 10.0.101 in eng/Versions.props), and picking an intermediate version looked like it would just defer the same conversation.

I think this is fine, but it's a one-way door for anyone still on an older FSharp.Core, so I'd rather ask than assume. If you'd prefer a lower floor that still works, I'm happy to change it.

Everything else

  • Local tools bumped. Paket had to move to 10.3.1 because 8.0.3 cannot parse the net10.0 framework identifier at all. Fantomas is on the latest 8.0.0 alpha; it no longer recognises fsharp_max_dot_get_expression_width, renamed the check command, and reformats one call in Lexing.fs.
  • FAKE is gone. build.fsx is now a Fun.Build script run with dotnet fsi, and tests/fsyacc/OldFsYaccTests.fsx is a plain dotnet fsi script. Beyond FAKE being fairly quiet these days, it was an active blocker here: FAKE compiles its scripts against the reference assemblies of the framework in the #r "paket:" header, and a runner with only the .NET 10 SDK has no net6.0 targeting pack, so the build died before the first target ran. FAKE's bundled Paket cannot parse net10.0 either, so there was no version of that header that worked.
  • build.sh and build.cmd now invoke dotnet fsi build.fsx; pipelines are selected with -p (-p Release, -p Docs) instead of FAKE's -t.
  • actions/setup-dotnet bumped to v6; the other actions are already on their latest major.

nojaf added 2 commits August 28, 2026 18:05
Move global.json to 10.0.100 and retarget every net6.0 project to
net10.0: the fslex and fsyacc tools, the Expecto test projects and the
example projects. The shipped FsLexYacc.targets and the NuGet template
now point at build/fslex/net10.0 and build/fsyacc/net10.0, so consumers
of the tools package need a .NET 10 runtime.

Raise the FSharp.Core floor to 10.0.0. The older versions are no longer
usable on this SDK: 4.6.2 and 4.7.2 make the compiler emit dynamic
arithmetic instead of inlining, which fails at runtime with "Dynamic
invocation of op_Subtraction is not supported" from Position.Column,
and 6.0.0 breaks publish with NETSDK1152 because it ships duplicate
FSharp.Core.xml content files.

Bump the local tools. Paket had to move to 10.3.1 because 8.0.3 cannot
parse the net10.0 framework identifier at all. Fantomas 8 no longer
recognises fsharp_max_dot_get_expression_width and renamed the check
command, and it reformats one call in Lexing.fs.

Bump actions/setup-dotnet to v6; the other actions are already on their
latest major.
build.fsx is now a Fun.Build script run through dotnet fsi, and
OldFsYaccTests.fsx is a plain dotnet fsi script. FAKE compiles a script
against the reference assemblies of the framework named in its
"#r paket:" header, and a machine with only the .NET 10 SDK has no
net6.0 targeting pack, so the build died before the first target ran.
Its bundled Paket cannot parse net10.0 either, so no value of that
header worked. Beyond that, FAKE has seen little maintenance lately.

The FAKE targets become three pipelines: Build (the default), Release,
which adds packaging, and Docs. ReleaseNotes.parse, AssemblyInfoFile,
Shell.cleanDirs and Paket.pack are replaced by local equivalents.
Release notes reach dotnet pack and paket pack through an explicit
argument list rather than a command string, so the multi-line text
survives without quoting.

build.sh and build.cmd invoke dotnet fsi, and pipelines are selected
with -p instead of -t.

Ignore the signature files fslex has emitted since 11.2.0. Every
generated .fs was ignored but none of its .fsi siblings were, and
fantomas checks src/, so a leftover signature file failed CheckFormat
on the second consecutive build. repro1885.fs is generated too and was
tracked by mistake; nothing compiles it, and the committed copy still
held an absolute path from whoever last ran the suite.
@T-Gro

T-Gro commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

IMO 10 makes the most sense - 8 and 9 are going out of support in a few months.

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.

2 participants