Skip to content

Let FSharpProjectSnapshot.FromOptions take reference stamps from the host - #20459

Open
xperiandri wants to merge 3 commits into
dotnet:mainfrom
xperiandri:perf/snapshot-reference-stamps
Open

xperiandri wants to merge 3 commits into
dotnet:mainfrom
xperiandri:perf/snapshot-reference-stamps

Conversation

@xperiandri

Copy link
Copy Markdown
Contributor

Description

FSharpProjectSnapshot.FromOptions stats every -r: reference (FileSystem.GetLastWriteTimeShim) each time a snapshot is built from options. Under the transparent compiler in Visual Studio that is the from-scratch path for every new Roslyn Project instance whose options are not reusable — after every options recompute, since FSharpProjectOptions.AreSameForChecking compares only the Stamp — so a project with a few hundred references pays a few hundred stats per typecheck request.

This adds an optional getReferenceStamp: string -> DateTime to FromOptions. A host that already tracks the last-write times of its references (#20457 keeps them behind an IVsAsyncFileChangeEx2 watcher) supplies them; everyone else gets the same FileSystem.GetLastWriteTimeShim as before. The callback is threaded through the recursive call for FSharpReferencedProject.FSharpReference, so referenced projects' snapshots use it too.

No behaviour change for existing callers; the surface-area baseline gains the new optional parameter on the existing overload.

Checklist

  • Test cases added — FSharpChecker/ProjectSnapshot.fs: the stamps of both the project and its referenced F# project come from the callback.
  • Performance benchmarks added in case of performance changes — none; the change removes a stat per reference only when a host opts in, the default path is unchanged.
  • Release notes entry updated — docs/release-notes/.FSharp.Compiler.Service/11.0.100.md.

@github-actions

github-actions Bot commented Sep 6, 2026 •

Copy link
Copy Markdown
Contributor

✅ Release notes checked


✅ Found changes and release notes in following paths:

Change path Release notes path Description
`src/Compiler` docs/release-notes/.FSharp.Compiler.Service/11.0.200.md

@xperiandri
xperiandri force-pushed the perf/snapshot-reference-stamps branch from 268d203 to c75a5bd Compare September 6, 2026 04:08
@xperiandri xperiandri changed the title Let FSharpProjectSnapshot.FromOptions take reference stamps from the host Let FSharpProjectSnapshot.FromOptions take reference stamps from the host Sep 6, 2026
@xperiandri
xperiandri force-pushed the perf/snapshot-reference-stamps branch from c75a5bd to dab34ee Compare September 6, 2026 04:35
@github-actions github-actions Bot added the AI-Tooling-Check-Scanned-Clean Tooling check: diff analyzed, no interesting infrastructure files label Sep 6, 2026

static member FromOptions(options: FSharpProjectOptions, getFileSnapshot, ?snapshotAccumulator) =
static member FromOptions
(options: FSharpProjectOptions, getFileSnapshot, ?snapshotAccumulator, ?getReferenceStamp: string -> DateTime)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖🕵️ Keep the existing public FromOptions CLR method. Put shared logic in a private implementation and expose a distinctly named internal host entry point for the editor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@xperiandri but arguments are optional

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@xperiandri TODO - I think this hasnt been addressed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I wonder if this really required, if added parameter is optional

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I wonder if this really required, if added parameter is optional

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed now, in ab9604d250. You were right and my "the arguments are optional" was not: an optional parameter is part of the CLR signature, so adding one replaced the existing FromOptions instead of extending it, and a consumer built against the old one would have hit a MissingMethodException.

The shape is the one you asked for — a private SnapshotOfOptions does the work, the three FromOptions overloads are byte-for-byte what main has, and the host entry point is the separately named FromOptionsWithReferenceStamps(options, getFileSnapshot, getReferenceStamp, ?snapshotAccumulator).

It is public rather than internal: FSharp.Compiler.Service grants InternalsVisibleTo to fsc, fsi, VisualFSharp.Salsa, VisualFSharp.UnitTests and the two test projects, and not to FSharp.Editor, which is the host that would pass the stamps. Happy to make it internal and add that IVT instead if you prefer to keep it off the public surface.

@xperiandri
xperiandri requested a review from T-Gro September 11, 2026 15:35
@xperiandri
xperiandri force-pushed the perf/snapshot-reference-stamps branch from dab34ee to 6a1f447 Compare September 11, 2026 15:36
@github-actions github-actions Bot added the ⚠️ Affects-Design-Time Tooling check: PR touches type providers or dependency manager label Sep 11, 2026
@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Tooling Safety Check — Affects-Design-Time
Affects-Design-Time: Changes project snapshots consumed by design-time hosts.

Generated by PR Tooling Safety Check · gpt56 3.1M · ◷

@T-Gro T-Gro added the AI-reviewed PR reviewed by AI review council label Sep 14, 2026
FSharpProjectSnapshot.FromOptions stats every -r: reference each time a snapshot is built from options; under the transparent compiler in Visual Studio that is every from-scratch snapshot after an options recompute. A host that already tracks the last-write times of its references can pass getReferenceStamp instead; the default stays FileSystem.GetLastWriteTimeShim. The callback is threaded through the recursive call for referenced F# projects.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 26, 2026 01:01
@xperiandri
xperiandri force-pushed the perf/snapshot-reference-stamps branch from 6a1f447 to b61c671 Compare September 26, 2026 01:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Preserve the existing FromOptions overload to avoid breaking already-built consumers.

Review effort: Lite
Findings: 1 High severity

Open (1)
What changed in this PR

Adds host-provided reference timestamp callbacks to FSharpProjectSnapshot.FromOptions, including recursive referenced projects.

Changes:

  • Adds callback-based reference stamping with filesystem fallback.
  • Adds tests for project and referenced-project stamps.
  • Updates the API baseline and release notes.
File Summary
src/​Compiler/​Service/​FSharpProjectSnapshot.fs Implements callback-based stamping; retain the existing 3-argument overload for binary compatibility.
tests/​FSharp.Compiler.ComponentTests/​FSharpChecker/​ProjectSnapshot.fs Tests callback propagation.
tests/​FSharp.Compiler.Service.Tests/​FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl Updates the public API baseline.
docs/​release-notes/​.FSharp.Compiler.Service/​11.0.100.md Documents the API enhancement.

Comment on lines +650 to +652
static member FromOptions
(options: FSharpProjectOptions, getFileSnapshot, ?snapshotAccumulator, ?getReferenceStamp: string -> DateTime)
=

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Both of you are right, and my "but the argument is optional" was wrong: F# compiles an optional parameter into the CLR signature, so the 3-argument method was replaced rather than extended, and a consumer built against it would have found no such method.

Fixed in ab9604d250, the way @T-Gro asked for it: the work moved to a private SnapshotOfOptions, the three FromOptions overloads are back exactly as they were on main, and a host that already tracks its references calls the new FromOptionsWithReferenceStamps(options, getFileSnapshot, getReferenceStamp, ?snapshotAccumulator).

One deviation from your wording, @T-Gro: the new entry point is public rather than internal. FSharp.Compiler.Service has InternalsVisibleTo for fsc, fsi, VisualFSharp.Salsa, VisualFSharp.UnitTests and the two test projects, but not for FSharp.Editor, which is the host meant to pass the stamps — internal would need a new IVT entry for it. Say the word if you would rather have the IVT than a public name.

The surface-area baseline now has the three original lines untouched plus one for the new member (regenerated with TEST_UPDATE_BSL=1, and the test passes on a re-run). The component test calls the new name and passes.

xperiandri and others added 2 commits September 26, 2026 13:47
`main` opened 11.0.200 for SDK 11.0.200; 11.0.100 has shipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An optional parameter is part of the CLR signature, so adding one replaced
`FromOptions` rather than extending it: an already-built consumer would have found no
such method. The three overloads are back as they were, the work moved to a private
implementation, and a host that tracks its references calls
`FromOptionsWithReferenceStamps`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚠️ Affects-Design-Time Tooling check: PR touches type providers or dependency manager AI-reviewed PR reviewed by AI review council AI-Tooling-Check-Scanned-Clean Tooling check: diff analyzed, no interesting infrastructure files

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

3 participants