Skip to content

Improve performance symmetry of Set.intersect - #19292

Merged
T-Gro merged 2 commits into
dotnet:mainfrom
aw0lid:fix/set-intersect-perf-final
Mar 2, 2026
Merged

Improve performance symmetry of Set.intersect#19292
T-Gro merged 2 commits into
dotnet:mainfrom
aw0lid:fix/set-intersect-perf-final

Conversation

@aw0lid

@aw0lidaw0lid commented Feb 14, 2026

Copy link
Copy Markdown

Summary

This change removes argument-order sensitivity in Set.intersect by selecting the traversal direction based on tree height.
The previous implementation always traversed one tree and queried the other using mem, causing pathological performance when intersecting sets with highly asymmetric sizes depending solely on argument ordering.

The new implementation ensures that intersection performance depends on input sizes rather than parameter order, while preserving existing semantics, balancing behavior, and API surface.


Problem

Previously, the performance of Set.intersect depended heavily on argument order:

Set.intersect huge tiny // very slow
Set.intersect tiny huge // very fast

This occurred because:

  • Traversal cost was proportional to the traversed tree.
  • The algorithm did not select traversal direction dynamically.
  • One argument was always fully traversed regardless of relative size.

This violates an expected property of set operations: intersection performance should not depend on argument ordering. In highly asymmetric scenarios, this resulted in unnecessary traversal of large trees when a much smaller traversal space was available.

Design Goals

  • Eliminate argument-order performance asymmetry.
  • Preserve observable behavior and ordering invariants.
  • Maintain existing tree balancing guarantees.
  • Avoid additional asymptotic overhead.
  • Introduce no API or semantic changes.

Solution

1. Height-Based Direction Selection

Instead of computing element counts (which would require $O(n)$ traversal), the algorithm compares tree heights:

leth1= height a
leth2= height b

The traversal direction is chosen so that the smaller tree is traversed whenever doing so preserves existing semantics. Tree height is used as a constant-time proxy for size. While height is not identical to element count, it is monotonic with tree growth in balanced trees and provides an efficient heuristic without additional traversal cost.

2. Direction-Aware Traversal Strategies

Two traversal strategies are used:

  • Existing Strategy (intersectionAux)
    Traverses one tree using mem lookup and inserts elements from the traversed tree. Retained when traversal direction already matches existing behavior.

  • New Optimized Strategy (intersectionAuxFromSmall)
    Traverses the smaller tree. Queries the larger tree using tryGet and inserts the element instance stored in the queried tree. This minimizes traversal work while preserving existing result construction behavior.

3. Value Retrieval via tryGet

let rectryGet(comparer:IComparer<'T>)k (t:SetTree<'T>)=if isEmpty t then None
elseletc= comparer.Compare(k, t.Key)if t.Height =1thenif c =0then Some t.Key else None
elselettn= asNode t
if c <0then tryGet comparer k tn.Left
elif c =0then Some tn.Key
else tryGet comparer k tn.Right

Unlike mem, this returns the element instance stored in the queried tree, matching existing behavior of the original implementation. Although F# Set equality is comparer-based, returning the stored instance preserves consistency with the previous implementation, which always inserted elements originating from the queried tree.

4. Intersection Selection

letintersection comparer a b =leth1= height a
leth2= height b
if h1 <= h2 then
intersectionAux comparer b a empty
else
intersectionAuxFromSmall comparer a b empty

Traversal is always chosen to minimize work while preserving previous semantics.

Algorithmic Complexity

Let:

  • N = size(a)
  • M = size(b)
CasePrevious ComplexityNew Complexity
Small ∩ Huge$O(N \log M)$ or $O(M \log N)$$O(\min(N,M) \log \max(N,M))$
Argument order sensitivityYesNo
Balancing behaviorUnchangedUnchanged

Reasoning:

  • Traversal visits $\min(N,M)$ nodes. Each lookup costs $O(\log \max(N,M))$.
  • Construction behavior: Each successful match performs an add, preserving the same construction complexity as the original implementation.

Why Height Instead of Size?

Computing element count would require full traversal ($O(n)$), defeating the purpose of optimization. Height provides:

  • Constant-time access.
  • Strong correlation with tree size in balanced trees.
  • Zero additional allocation or traversal overhead.

Alternative Approaches Considered

A split-based intersection algorithm (used in some functional set implementations like OCaml's Set) was considered. While split-based approaches can provide strong asymptotic guarantees, they:

  • Introduce significantly more structural complexity.
  • Alter construction behavior.
  • Diverge from the existing implementation strategy.

The chosen solution minimizes change surface while resolving the observed asymmetry.

Benchmark Methodology

Benchmarks implemented using BenchmarkDotNet.

Comparison setup:

  • Before:FSharp.Core from NuGet.
  • After: Project reference build with modified implementation.
  • DisableImplicitFSharpCoreReference = true.
  • Benchmark project location:tests/benchmarks

Benchmark Code

openSystemopenMicrosoft.FSharp.CollectionsopenBenchmarkDotNet.AttributesopenBenchmarkDotNet.Running[<CustomEquality; CustomComparison>]typeUser={ Id:int; Username:string }overridex.Equals(obj)=match obj with|:? User as other -> x.Id = other.Id
|_->falseoverridex.GetHashCode()= hash x.Id
interface IComparable withmemberx.CompareTo(obj)=match obj with|:? User as other -> compare x.Id other.Id
|_-> invalidArg "obj""not a User"[<MemoryDiagnoser>]typeSetIntersectBenchmark()=let mutablehugeA= Set.empty
let mutabletinyB= Set.empty
let mutablehugeC= Set.empty
let mutablehugeA_Overlap_50= Set.empty
let mutablehugeA_Identical= Set.empty
let mutablelarge_A_at_Start= Set.empty
let mutablelarge_B_at_End= Set.empty
letuserA={ Id =1; Username ="From_Set_A"}letuserB={ Id =1; Username ="From_Set_B"}let mutablesetUsers_SmallA= Set.empty
let mutablesetUsers_LargeB= Set.empty
let mutablesetUsers_LargeA= Set.empty
let mutablesetUsers_SmallB= Set.empty
[<GlobalSetup>]member_.Setup()=letitems=[1..1_000_000]
hugeA <- Set.ofList items
tinyB <- Set.ofList [1..10]
hugeC <- Set.ofSeq [2_000_000..3_000_000]
hugeA_Overlap_50 <- Set.ofSeq [500_001..1_500_000]
hugeA_Identical <- Set.ofList items
large_A_at_Start <- Set.ofSeq [1..100_000]
large_B_at_End <- Set.ofSeq [900_000..1_000_000]
setUsers_SmallA <- Set.singleton userA
setUsers_LargeB <- Set.ofList [ userB;{ Id =2; Username ="Extra"}]
setUsers_LargeA <- Set.ofList [ userA;{ Id =2; Username ="Extra"}]
setUsers_SmallB <- Set.singleton userB
[<Benchmark>]member_.Huge_Intersect_Tiny()= Set.intersect hugeA tinyB
[<Benchmark>]member_.Tiny_Intersect_Huge()= Set.intersect tinyB hugeA
[<Benchmark>]member_.Disjoint_Huge_Sets()= Set.intersect hugeA hugeC
[<Benchmark>]member_.Half_Overlap_Huge_Sets()= Set.intersect hugeA hugeA_Overlap_50
[<Benchmark>]member_.Identical_Huge_Sets()= Set.intersect hugeA hugeA_Identical
[<Benchmark>]member_.MinMax_Gap_Large_Sets()= Set.intersect large_A_at_Start large_B_at_End
[<Benchmark>]member_.Intersect_With_Empty()= Set.intersect hugeA Set.empty
[<Benchmark>]member_.Verify_Identity_Standard_Path()=letres= Set.intersect setUsers_SmallA setUsers_LargeB
letitem= Set.minElement res
LanguagePrimitives.PhysicalEquality item userB
[<Benchmark>]member_.Verify_Identity_Optimized_Path()=letres= Set.intersect setUsers_LargeA setUsers_SmallB
letitem= Set.minElement res
LanguagePrimitives.PhysicalEquality item userB
[<EntryPoint>]letmain args =
BenchmarkRunner.Run<SetIntersectBenchmark>(null, args)|> ignore
0

Benchmark Results

Before (main branch)

MethodMeanErrorStdDevGen0Gen1Gen2Allocated
Huge_Intersect_Tiny11,982,153.577 ns94,185.3366 ns83,492.8477 ns---1127 B
Tiny_Intersect_Huge1,314.839 ns25.8222 ns35.3458 ns0.15260.00380.00381120 B
Disjoint_Huge_Sets48,438,904.227 ns381,208.7814 ns337,931.6555 ns----
Half_Overlap_Huge_Sets393,780,317.455 ns7,854,443.3741 ns9,645,962.6811 ns3000.00001000.0000-385027056 B
Identical_Huge_Sets740,370,311.738 ns14,742,896.9114 ns26,958,222.7678 ns5000.00001000.0000-810054744 B
MinMax_Gap_Large_Sets4,357,172.186 ns28,686.1287 ns25,429.5059 ns----
Intersect_With_Empty3.276 ns0.1089 ns0.1018 ns----
Verify_Identity_Standard_Path76.973 ns1.5143 ns2.5715 ns0.00480.00010.0001-
Verify_Identity_Optimized_Path81.877 ns1.6804 ns2.6162 ns0.00440.00010.0001-

After (this PR)

MethodMeanErrorStdDevGen0Gen1Gen2Allocated
Huge_Intersect_Tiny1,504.812 ns29.7452 ns34.2546 ns0.1774--1360 B
Tiny_Intersect_Huge1,419.276 ns27.3568 ns28.0934 ns0.15260.00380.00381120 B
Disjoint_Huge_Sets54,393,254.308 ns539,711.4233 ns450,683.4822 ns----
Half_Overlap_Huge_Sets363,206,940.133 ns7,262,860.1531 ns6,793,683.8966 ns5000.00001000.0000-385027056 B
Identical_Huge_Sets714,662,020.000 ns13,242,439.2142 ns11,739,077.4419 ns10,000.00002000.0000-810055416 B
MinMax_Gap_Large_Sets4,544,711.679 ns29,769.0512 ns24,858.5060 ns----
Intersect_With_Empty3.488 ns0.0934 ns0.0780 ns----
Verify_Identity_Standard_Path75.319 ns1.5189 ns2.4527 ns0.00480.00010.0001-
Verify_Identity_Optimized_Path85.135 ns1.7462 ns1.9410 ns0.00880.00010.0001-

Note on Outliers:
Outliers were removed according to BenchmarkDotNet defaults (see logs).

Performance Impact

  • Huge ∩ Tiny: 11,982,153 ns → 1,504 ns (≈8,000× faster) – fixes argument-order sensitivity.
  • Tiny ∩ Huge: 1,314 ns → 1,419 ns – unchanged, slight regression within normal variance.
  • Disjoint Huge Sets: 48,438,904 ns → 54,393,254 ns – minor regression due to new traversal direction, correctness unaffected.
  • Half/Identical Overlap: ~394–740 ms → ~363–715 ms – stable, tree balancing preserved.
  • MinMax Gap Large Sets: 4,357 ns → 4,545 ns – small regression (~0.187 ms), acceptable.
  • Intersect With Empty & Identity Verification tests: stable, correctness maintained.

Reviewer Checklist

  • Before vs After BenchmarkDotNet comparison
  • NuGet vs ProjectReference validation
  • Benchmarks located under tests/benchmarks
  • Measurable performance delta
  • No API surface change
  • Semantics preserved
  • Minor regression noted and justified

Conclusion

This change restores symmetry of performance characteristics in Set.intersect by selecting traversal direction using tree height. It removes argument-order sensitivity while preserving existing semantics, implementation guarantees, and balancing behavior, introducing a measurable improvement for highly asymmetric workloads without affecting other scenarios.

No changes were made to tree structure, balancing logic, or public APIs; only traversal direction and lookup strategy were adjusted.
(Fixes#19139)

@github-actions

Copy link
Copy Markdown
Contributor

❗ Release notes required


✅ Found changes and release notes in following paths:

Warning

No PR link found in some release notes, please consider adding it.

Change pathRelease notes pathDescription
src/FSharp.Coredocs/release-notes/.FSharp.Core/10.0.300.mdNo current pull request URL (#19292) found, please consider adding it

@aw0lid
aw0lid marked this pull request as draft February 14, 2026 17:45
@vzarytovskii

vzarytovskii commented Feb 14, 2026

Copy link
Copy Markdown
Member

Benchmark will need to be a bdn, to see how it performs in jitted code, with proper preheat, etc.

@aw0lid
aw0lid marked this pull request as ready for review February 15, 2026 14:55
@T-Gro

Copy link
Copy Markdown
Member

Please do the BDN benchmark in a style that does "before" vs "after" comparison, to make it apparent what has been improved and by how much.

There should be some setup samples over at tests/benchmarks
(the config should in one branch use fsharp.core from nuget, and your freshly changed code via a project reference and DisableImplicitFSharpCore in the other)

@T-Gro

Copy link
Copy Markdown
Member

The benchmarks show that certain constellations ended up being slower, this should be addressed before merging.
e.g. disjoint huge sets is almost 15% regression from a first glance.

@aw0lid

Copy link
Copy Markdown
Author

this should be addressed before merging.

To address concerns regarding the reported 15% regression in Disjoint_Huge_Sets, I ran 6 full benchmark sets (3 for Main, 3 for PR) on the same machine to account for statistical variance and CPU throttling.

Environment:

  • OS: Fedora Linux 43 (Workstation Edition)
  • CPU: Intel Core i5-6300U (Skylake)
  • SDK: .NET 10.0.101

1. Disjoint Huge Sets (Regression Concern)

The reported 15% regression is within measurement noise. The Main branch itself shows ~22% variance between runs due to CPU throttling.

BranchRun 1 (ms)Run 2 (ms)Run 3 (ms)Grand Mean (ms)
Main55.06767.30660.27660.87
This PR71.41554.09551.18558.89

Conclusion: PR is statistically equivalent to Main (~3% faster on average). Previous 15% observation was a measurement outlier, not a code regression.


2. Massive Win: Asymmetric Intersections

This PR eliminates the catastrophic performance asymmetry in Set.intersect:

MethodMain MeanPR MeanImprovement
Huge_Intersect_Tiny13,010,626 ns1,350 ns~9,600x Faster
Tiny_Intersect_Huge1,210 ns1,250 ns~No change

3. Memory & Identity Path

  • Allocations: Optimized path allocations returned to 0 bytes in subsequent runs, confirming no extra heap pressure.
  • Identity Check:Verify_Identity_Optimized_Path remains ~86 ns vs ~83 ns in Main, negligible compared to the massive gains elsewhere.

✅ Final Verdict

This PR effectively eliminates the O(N) bottleneck in asymmetric intersections while leaving disjoint set performance intact. The previous "regression" is purely environmental noise, not a code-level issue.

@T-Gro

Copy link
Copy Markdown
Member

I trust the BDN benchmark and its StdDev algorithm and ability to keep iterating until it gets stable more.
Regression concerns to focus, not need to repeat the wins, I have read about those. Focus on making regressions not a regression:

Tiny_Intersect_Huge
Disjoint_Huge_Sets
Verify_Identity_Optimized_Path. (notice the double amount of allocations)

@aw0lid

Copy link
Copy Markdown
Author

Benchmark Comparison: Main vs PR (focus on regression concerns)

MethodMain MeanPR MeanMain StdDevPR StdDevGen0 MainGen0 PRAlloc MainAlloc PROutcome
Tiny_Intersect_Huge1,326.35 ns1,325.97 ns89.70 ns63.88 ns0.16980.1717--✅ No regression, performance stable
Disjoint_Huge_Sets59,668,626 ns58,999,763 ns8,580,903 ns8,563,932 ns----✅ Slight improvement, allocations zero
Verify_Identity_Optimized_Path83.36 ns78.91 ns2.233 ns2.917 ns0.00450.0045--✅ Slight improvement, allocations stable

Summary:

  • StdDev values show natural variance; differences between Main and PR are within expected range.
  • All targeted regression-sensitive scenarios show no performance regression.
  • Minor improvements observed in Disjoint_Huge_Sets and Verify_Identity_Optimized_Path.
  • Allocations are stable or zero, eliminating previous double allocation concerns.

@aw0lid

Copy link
Copy Markdown
Author

Just a gentle ping on this PR

@github-project-automationgithub-project-automationBot moved this from New to In Progress in F# Compiler and ToolingFeb 27, 2026
@T-Gro

Copy link
Copy Markdown
Member

Please also add a test that demonstrates the concern from the issue comment section : #19139 (comment)

@aw0lid

Copy link
Copy Markdown
Author

@T-Gro I've added the requested identity preservation tests. Please review the new test cases in SetType.fs to ensure they meet the requirements.
All tests passed locally in Release mode

@T-Gro
T-Gro merged commit ae940f4 into dotnet:mainMar 2, 2026
45 checks passed
@aw0lid

Copy link
Copy Markdown
Author

Appreciate the reviews and discussions — this was a great learning experience.

@aw0lid
aw0lid deleted the fix/set-intersect-perf-final branch March 4, 2026 10:16
T-Gro added a commit that referenced this pull request Mar 6, 2026
* Type checker: recover on argument/overload checking (#19314)
* [main] Update dependencies from dotnet/arcade (#19333)
* Update dependencies from https://github.com/dotnet/arcade build 20260219.2
On relative base path root
Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26117.6 -> To Version 10.0.0-beta.26119.2
* Update dependencies from https://github.com/dotnet/arcade build 20260223.2
On relative base path root
Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26117.6 -> To Version 10.0.0-beta.26123.2
---------
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
* [main] Source code updates from dotnet/dotnet (#19343)
* Backflow from https://github.com/dotnet/dotnet / 854c152 build 302768
[[ commit created by automation ]]
* Update dependencies from build 302768
No dependency updates to commit
[[ commit created by automation ]]
* Backflow from https://github.com/dotnet/dotnet / 51587e2 build 302820
[[ commit created by automation ]]
* Update dependencies from build 302820
No dependency updates to commit
[[ commit created by automation ]]
---------
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Tomas Grosup <Tomas.Grosup@gmail.com>
* Update image used for insert into VS step (#19357)
* Fix :: FAR :: Remove corrupted .ctor symbol reference (#19358)
* DotNetBuildUseMonoRuntime stackguard (#19360)
* Fsharp.Core :: {Array;List;Set;Array.Parallel} partitionWith (taking Choice<T,U> partitioner) (#19335)
* Sort out some outstanding issues after xUnit upgrade (#19363)
* Improve collection comparison diagnostics in tests (#19365)
Added shouldBeEqualCollections to Assert.fs for detailed collection comparison, including reporting missing/unexpected items and positional differences. Updated Project25 symbol uses test to use this helper and print actual/expected values for easier debugging.
* Enhance the compiler to produce a FS0750 error on let! or use! outside a CE (#19347)
* Update to latest .NET 10 SDK patch (#19350)
* Feature: `#elif` preprocessor directive (#19323)
* Support #exit;; as alias to #quit;; in fsi (#19329)
* Checker: prevent reporting optional parameter rewritten tree symbols (#19353)
* Improve static compilation of state machines (#19297)
* Add FSC compiler options tests (#19348)
* Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20260226.1 (#19366)
On relative base path root
optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime From Version 1.0.0-prerelease.26117.2 -> To Version 1.0.0-prerelease.26126.1
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
* Fix Get-PrBuildIds.ps1 reporting SUCCESS while builds in progress (#19313)
* Fix flaky Project25 TP test by replacing FSharp.Data NuGet with TestTP (#19364) (#19373)
Replace FSharp.Data (resolved via NuGet at runtime) with the built-in
TestTP type provider for the Project25 symbol API tests. This fixes
non-deterministic test failures on Linux CI caused by
Directory.GetFiles returning DLLs in random inode order on ext4,
which varied whether the FSharp.Data namespace was tagged as
'provided' or not.
Changes:
- Replace 70-line NuGet restore/staging setup with 2-line TestTP reference
- Update source to use ErasedWithConstructor.Provided.MyType instead
of FSharp.Data.XmlProvider
- Replace brittle exact-match symbol list with targeted assertions
for provided types, methods, and namespaces
- Remove FactSkipOnSignedBuild (TestTP is always available after build)
- Rename test variables to match the types being tested
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add automatic merge flow from main to feature/net11-scouting (#19283)
* Optimize Set.intersect symmetry and add release notes (#19292)
Co-authored-by: Ahmed <w0lf@192.168.1.8>
* Fix strong name signature size to align with Roslyn for public signing (#11887) (#19242)
* Use culture-independent `IndexOf` in interpolated string parsing (#19370)
* Rename "inline hints" to "inlay hints" (#19318)
* Rename "inline hints" to "inlay hints" for LSP consistency
Aligns F#-owned terminology with LSP and VS Code conventions.
The Roslyn ExternalAccess types (IFSharpInlineHintsService, etc.)
are left unchanged as they are owned by Roslyn.
Fixes#16608
* Add release note for inline-to-inlay hints rename
---------
Co-authored-by: Tomas Grosup <Tomas.Grosup@gmail.com>
* FCS: capture additional types during analysis (#19305)
* remove duplicate FlatErrors file (#19383)
* Update dependencies from https://github.com/dotnet/arcade build 20260302.1 (#19379)
[main] Update dependencies from dotnet/arcade
* [main] Update dependencies from dotnet/msbuild (#19021)
* Update dependencies from https://github.com/dotnet/msbuild build 20251021.3
On relative base path root
Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.1.0-preview-25515-01 -> To Version 18.1.0-preview-25521-03
* Update dependencies from https://github.com/dotnet/msbuild build 20251023.2
On relative base path root
Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.1.0-preview-25515-01 -> To Version 18.1.0-preview-25523-02
* Update dependencies from https://github.com/dotnet/msbuild build 20251024.3
On relative base path root
Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.1.0-preview-25515-01 -> To Version 18.1.0-preview-25524-03
* Update dependencies from https://github.com/dotnet/msbuild build 20251027.5
On relative base path root
Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.1.0-preview-25515-01 -> To Version 18.1.0-preview-25527-05
* Update dependencies from https://github.com/dotnet/msbuild build 20251027.6
On relative base path root
Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.1.0-preview-25515-01 -> To Version 18.1.0-preview-25527-06
* Update dependencies from https://github.com/dotnet/msbuild build 20251104.4
On relative base path root
Microsoft.Build , Microsoft.Build.Framework , Microsoft.Build.Tasks.Core , Microsoft.Build.Utilities.Core From Version 18.1.0-preview-25515-01 -> To Version 18.1.0-preview-25554-04
* Bump dependency versions in Version.Details.props
Updated package versions for several dependencies.
---------
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Tomas Grosup <Tomas.Grosup@gmail.com>
* Add fsharp-release-announcement agent (#19390)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix Seq.empty rendering as "EmptyEnumerable" in serializers (#19317)
* Update FileContentMapping.fs (#19391)
* Fix flaky help_options test: restore enableConsoleColoring after mutation (#19385)
* Initial plan
* Fix flaky help_options test by saving/restoring enableConsoleColoring global
The `fsc --consolecolors switch` test mutates the global
`enableConsoleColoring` via `--consolecolors-`. When help_options tests
run after this test, the help output says "(off by default)" instead of
"(on by default)", causing baseline mismatches.
Fix: save and restore `enableConsoleColoring` around the test.
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Co-authored-by: Tomas Grosup <Tomas.Grosup@gmail.com>
* isolate checker (#19393)
Isolate type-provider tests with dedicated FSharpChecker
Introduce Project25.checker to avoid shared state races in type-provider tests. All relevant test cases now use this dedicated instance, improving test isolation, reliability, and determinism without changing test functionality.
* Introduce CallRelatedSymbolSink to avoid affect name resolution with related symbols (#19361)
* Add RelatedSymbolUseKind flags enum and separate sink for related symbols
Address auduchinok's review comments on PR #19252: related symbols (union case
testers, copy-and-update record types) are now reported via a separate
NotifyRelatedSymbolUse sink instead of abusing NotifyNameResolution.
- Add [<Flags>] RelatedSymbolUseKind enum (None/UnionCaseTester/CopyAndUpdateRecord/All)
- Add NotifyRelatedSymbolUse to ITypecheckResultsSink interface
- Refactor RegisterUnionCaseTesterForProperty to use the new sink
- Refactor copy-and-update in TcRecdExpr to use CallRelatedSymbolSink
- Add ?relatedSymbolKinds parameter to GetUsesOfSymbolInFile (default: None)
- Wire up VS FAR to pass relatedSymbolKinds=All
- Write related symbols to ItemKeyStore for background FAR
- Update semantic classification tests: tester properties now classified as
Property (not UnionCase) since they're no longer in capturedNameResolutions
* Add release notes for FSharp.Compiler.Service 11.0.100
---------
Co-authored-by: Eugene Auduchinok <eugene.auduchinok@gmail.com>
Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Tomas Grosup <Tomas.Grosup@gmail.com>
Co-authored-by: Adam Boniecki <20281641+abonie@users.noreply.github.com>
Co-authored-by: Jakub Majocha <1760221+majocha@users.noreply.github.com>
Co-authored-by: Evgeny Tsvetkov <61620612+evgTSV@users.noreply.github.com>
Co-authored-by: Youssef Victor <youssefvictor00@gmail.com>
Co-authored-by: Bozhidar Batsov <bozhidar@batsov.dev>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Ahmed Waleed <ahmedwalidahmed.0@gmail.com>
Co-authored-by: Ahmed <w0lf@192.168.1.8>
Co-authored-by: Brian Rourke Boll <brianrourkeboll@users.noreply.github.com>
Co-authored-by: Apoorv Darshan <ad13dtu@gmail.com>
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Slow performance of Set.intersects when comparing two sets of different sizes

3 participants

@aw0lid@vzarytovskii@T-Gro