dotnet-watch: F# hot reload integration (inspection draft)#1
Draft
NatElkins wants to merge 705 commits into
Draft
dotnet-watch: F# hot reload integration (inspection draft)#1NatElkins wants to merge 705 commits into
NatElkins wants to merge 705 commits into
Conversation
This was referenced Jun 12, 2026
Owner
Author
|
Compiler-side counterpart is now under upstream review at dotnet/fsharp#19941. This branch gained: a one-variable master kill switch (DOTNET_WATCH_FSHARP_HOTRELOAD=0), the SupportsHotReload capability now advertised only under dotnet-watch builds (no VS blast radius), and session-object-only FCS support (the bridge no longer requires the retired legacy checker surface — e2e suite 8/0 against current FCS). |
T-Gro
reviewed
Jun 23, 2026
NatElkins
added a commit
that referenced
this pull request
Jun 23, 2026
ChangeFileInFSharpProjectWithLoop_FirstEditAppliesInPlace asserted only the applied/no-restart log messages, so a delta that "applies" without changing behavior would still pass. Assert the running loop now prints the edited string in place (mirrors ChangeFileInFSharpProjectWithLoop_AppliesOrRestarts). Addresses review feedback on #1.
NatElkins
added a commit
that referenced
this pull request
Jun 23, 2026
…t-watch
The F# bridge collapsed the rude-edit reason to a record/DU ToString() dump and
logged it at Debug only, so an edit that forces a restart gave the user no reason.
Now that FSharpHotReloadError.UnsupportedEdit carries a structured rude-edit list
(Id + Severity + Message), read it via reflection (TryFormatRudeEdits) into a clean
"{Id}: {Message}" reason and report it as a warning instead of at Debug. The
extraction is defensive: any shape mismatch falls back to ToString(), so the bridge
stays correct against older FCS builds (where UnsupportedEdit still carries a string).
Pairs with the FCS-side structured diagnostics channel on dotnet/fsharp#19941.
Addresses review feedback on #1.
Co-authored-by: Viktor Hofer <7412651+ViktorHofer@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Jan Provaznik <janprovaznik@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…#54719) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
TestAsset.WithSource applied ~14 property/package-version substitutions by calling UpdateProjProperty/ReplacePackageVersionVariable in a loop, each of which reloaded and rewrote every project file in the asset. That meant ~14 XDocument load+save round-trips per project file during the setup of every test that calls WithSource (the standard setup path for hundreds of SDK integration tests). Extract the per-document mutation bodies into private static helpers and apply all substitutions in one WithProjectChanges pass, so each project file is loaded and saved once. Behavior is unchanged: verified byte-identical output across all 352 test-asset csproj files. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a22eead4-88ca-4142-a6d8-a7199db73289
WithSource copied every source file to the destination and then, in the substitution pass, reloaded and re-saved each project/.xml file with the target-framework, runtime-identifier, and package-version substitutions applied. That meant every project file was written twice: once by File.Copy and again by the substitution save that immediately overwrote it. Skip the File.Copy for files that the substitution pass rewrites; instead load those directly from the source and write the substituted result straight to the destination once. Non-project files are still copied verbatim. Because File.Copy is an exact byte copy, loading from the source is equivalent to loading from the copied destination, so output is unchanged: verified byte-identical across all 257 test assets (1439 files, 0 differences) while eliminating 404 redundant writes (~22% of WithSource's file writes). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a22eead4-88ca-4142-a6d8-a7199db73289
Address review feedback: use OfType<XAttribute>() to filter out null attributes returned by the LINQ chain instead of a redundant inner null-check. Behavior is unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a22eead4-88ca-4142-a6d8-a7199db73289
…55259) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…5218) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…s on x64 (dotnet#55205) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ovider.EnsureInstallPrerequisites (dotnet#55105) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CODEOWNERS_PAT_0 through _2 would need to exist as secrets containing a token with exclusively organization Members: read and repository Issues: read for this to function. This is scope creep so I will be likely removing this and deferring it to another PR but including here so we have it for future reference to build on top of.
Copilot-Session: 1094e91b-1c9c-4704-998f-0a5959e900aa
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 366a002c-9ad2-4938-a79a-af9d2f425d24
dotnet#55388) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 76a86ef3-d73c-451c-8f6e-cef56bf3509c
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 72bf4a4e-15d3-4177-9246-c49ad3071b13
Resolve the TestFX dependency conflicts using main's newer coherent MSTest and Microsoft.Testing.Platform build. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8bf6402b-2114-4555-97d4-9708f64b60da
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 99b4cd14-14dc-459c-bac7-f984c9d2632b
Co-authored-by: Chet Husk <chusk3@gmail.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 72bf4a4e-15d3-4177-9246-c49ad3071b13
Copilot-Session: 2331cf72-dd7c-4507-ba0f-792de68bd434
Update MSTest and Microsoft.Testing.Platform to TestFX build 324182, which includes microsoft/testfx#10169, and re-enable live capture in CI. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8bf6402b-2114-4555-97d4-9708f64b60da
…otnet#55433) Copilot-Session: ffc47f67-df45-4968-a755-7f30f3d3da22
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ed opt-out property (dotnet#55447) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: javiercn <6995051+javiercn@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 72bf4a4e-15d3-4177-9246-c49ad3071b13
…#55117) Co-authored-by: Jan Kratochvíl <kratochvil.jan@outlook.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 44aacce5-4a69-493c-989a-6bacbe193e08
…rp-hotreload-watch-v2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
dotnet-watch: F# hot reload integration (inspection draft)
The dotnet-watch half of F# hot reload, paired with the compiler work in
NatElkins/fsharp#3 (full implementation).
Not for upstream until the FCS API ships publicly — this draft exists for review and for
anyone who wants to run the end-to-end experience.
🚀 Try it
hot-reload-quickstart.md
— two clones, two builds, copy-paste steps, ending with
dotnet watch runhot-patching arunning F# console app (including adding lambdas to live methods). This branch builds the
complete .NET CLI (
artifacts/bin/redist/Debug/dotnet) that the guide uses.What this branch contains
FSharpHotReloadService+FSharpProjectInfo(src/Dotnet.Watch/Watch/HotReload/FSharp/):F# project discovery from the MSBuild graph, source/dependency change mapping, forced-build
orchestration, and a reflection bridge into FSharp.Compiler.Service — no compile-time FCS
dependency, graceful restart-fallback on stock toolsets
FSharpHotReloadSessionper watch run (the FCS-sideDebuggingSessionanalogue), every F# project added at prestart, per-project deltas withsolution-wide commit. Multi-project interleaved edits apply in place — e2e
ChangeFilesInFSharpAppAndLib_InterleavedEditsApplyInPlaceedits a referenced library,then the app, then the library again, all without restart. Legacy single-project path
preserved as the fallback for older FCS builds
(
DOTNET_WATCH_FSHARP_USE_SESSION_OBJECT=0kill switch)kept out of the Roslyn workspace (prevents spurious
ENC1009restarts); runtime EnCcapability forwarding with in-place refresh once agents connect (the session is prestarted
before the app launches)
SupportsHotReloadproject capability inMicrosoft.NET.Sdk.FSharp.targets(C#/VB parity)AddProjecttime: forced design-time rebuilds move the on-disk MVID;deltas must keep targeting the module the runtime actually loaded
DOTNET_WATCH_TRACE_FSHARP_HOTRELOAD=1Evidence
19/19 F# watch test classes (
FSharpHotReloadTests,FSharpHotReloadServiceTests,FSharpReflectionHostTests) including the multi-project e2e, no-op edit handling (norestart on whitespace saves), and dependency-edit handling — run against the locally built
FCS from
hot-reload-v2.Design docs
The architecture (session entity, snapshot contract, capability negotiation, determinism)
is documented on the compiler branch — start at
hot-reload-architecture.md.