Repository navigation
chore: lay the foundation for the per-collection modules - #25
Merged
Merged
Conversation
5 of 6 tasks
There was a problem hiding this comment.
🟡 Changes recommended
The new ordering and operation-category checks can silently accept violations they are intended to reject.
3 open issues
What changed in this PR
Establishes the foundation for ADR 0001’s per-collection rewrite without changing public functions.
Changes:
- Adds shared argument checks, contract-test helpers, and convention enforcement.
- Targets .NET 8 and .NET 10 and raises the minimum FSharp.Core version.
- Updates collection documentation and build guidance.
| File | Description |
|---|---|
| tests/FSharp.Collections.Immutable.Tests/TestCategoriesTests.fs | Adds category convention checks. |
| tests/FSharp.Collections.Immutable.Tests/TestCategories.fs | Defines centralized category attributes. |
| tests/FSharp.Collections.Immutable.Tests/Stack.fs | Removes placeholder tests. |
| tests/FSharp.Collections.Immutable.Tests/Sets.fs | Removes placeholder tests. |
| tests/FSharp.Collections.Immutable.Tests/Queue.fs | Removes placeholder tests. |
| tests/FSharp.Collections.Immutable.Tests/Maps.fs | Removes placeholder tests. |
| tests/FSharp.Collections.Immutable.Tests/IndexedSeq.fs | Removes placeholder tests. |
| tests/FSharp.Collections.Immutable.Tests/ImmutableList.fs | Removes placeholder tests. |
| tests/FSharp.Collections.Immutable.Tests/FSharp.Collections.Immutable.Tests.fsproj | Registers helpers and both target frameworks. |
| tests/FSharp.Collections.Immutable.Tests/FlatList.fs | Removes placeholder tests. |
| tests/FSharp.Collections.Immutable.Tests/Contracts/OverrideAssert.fs | Adds representation comparison helpers. |
| tests/FSharp.Collections.Immutable.Tests/Contracts/Inputs.fs | Adds shared contract inputs. |
| tests/FSharp.Collections.Immutable.Tests/Contracts/ExceptionAssert.fs | Adds exception comparison helpers. |
| src/FSharp.Collections.Immutable/ImmutableCollectionUtil.fs | Removes the former helper file. |
| src/FSharp.Collections.Immutable/Helper.fs | Preserves helpers and adds default-array validation. |
| src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj | Registers Helper.fs and both target frameworks. |
| README.md | Adds collection table and CheckOrder guidance. |
| docsSrc/index.md | Adds collection table. |
| docsSrc/Explanations/Background.md | Adds collection table. |
| Directory.Packages.props | Raises FSharp.Core minimum version. |
| CHANGELOG.md | Records framework and dependency changes. |
| build/check-order.fsx | Adds signature and implementation ordering checks. |
| build/build.fs | Runs CheckOrder before builds. |
| .github/copilot-instructions.md | Updates architecture and convention guidance. |
Review effort: Balanced
xperiandri
added a commit
that referenced
this pull request
Oct 18, 2026
`build/check-order.fsx` (review of #25): - understands file-scoped modules (`module A.B` without `=`), whose members start at column 0, and `module rec`; - reports a `val` at column 0 outside every module that it understands, instead of passing an unknown header unchecked; - compares the category of each function of the implementation with the signature, so that a moved banner is reported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 of 6 tasks
xperiandri
force-pushed
the
chore/foundation
branch
from
October 18, 2026 13:03
1c689c6 to
54f9dba
Compare
xperiandri
commented
Oct 18, 2026
Prepares the chain of ADR 0001, one pull request per collection: - `Helper.fs` replaces `ImmutableCollectionUtil.fs` and adds `checkNotDefault`, which treats a default `ImmutableArray` as FSharp.Core treats a `null` array. - `build/check-order.fsx` checks that every signature file groups its functions under category banners in the canonical order, sorts them alphabetically inside a category and that the implementation file repeats that order. The FAKE target `CheckOrder` runs it before `DotnetBuild`. - The library and the tests target `net8.0` and `net10.0`; FSharp.Core 10.1.301 is the first release with `partitionWith`. - The placeholder tests are replaced by the category attributes of every collection, tests that enforce the category rules, and the shared helpers of the contract tests: inputs, the comparison of an exception with the FSharp.Core oracle, and the comparison of the `Option` and `Tuple` overrides with the default functions. - The README and the documentation pages list the collections in a table that each following pull request updates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`build/check-order.fsx` (review of #25): - understands file-scoped modules (`module A.B` without `=`), whose members start at column 0, and `module rec`; - reports a `val` at column 0 outside every module that it understands, instead of passing an unknown header unchecked; - compares the category of each function of the implementation with the signature, so that a moved banner is reported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follows the reworked ADR 0001: - Test categories go on the test classes only (D8). `TestCategoriesTests` checks that no test class has a category written as a string and that test methods carry no categories, instead of an operation category on every method; its own methods lose their categories. `TestCategories.fs` states the rule. - Root modules (D2): `ExceptionAssert`, `Inputs` and `OverrideAssert` are the root modules of their files. The `Mirror` union moves to `Contracts/Mirror.fs`, so it stays in the namespace. - `check-order.fsx` reads the access modifier of `val internal`/`val private`, so an internal value no longer counts as a public function named `internal`. - The copilot instructions list the types files, the comparer structs, the extension modules and the rules of the reworked ADR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tests compare arrays and take their cases as data rows: - `Inputs` is a static class of arrays, so that a test can name its properties in `DynamicData (nameof Inputs.All, typeof<Inputs>)`; `typeof` cannot name a module. `All` and `NonEmpty` are the row sources of the tests that run on every input. Every property builds new arrays on each read, so that no test sees the rows of another. - `OverrideAssert.pairMatches` and `tripleMatches` compare with F# structural equality: the equality of a tuple compares arrays by reference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The `<summary>` of `ExceptionAssert.headline` spans several lines, as its `<remarks>` does: a summary and a remarks stay on one line each only when both are short. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The solution structure lists the files that every folder has: - Every `XOption` and `XTuple` file has a line of its own, as the `FlatList` files do. - The comparer struct and the extension files take their dotted names (`HashMap.CustomComparers`, `HashMap.Extensions`, `HashSet.CustomComparer`, ...) and nest under the line of their module; they carry `<DependentUpon>`, so that Visual Studio shows them as a tree. - The builder and computation expression files and `ComputationExpressions.fs` have their signature files, as the rule above the tree asks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The order check parses the files with Fantomas.FCS instead of regular expressions and runs inside the build project as `CheckOrder.fs`; the signature decides which implementation bindings take part in the order. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
xperiandri
force-pushed
the
chore/foundation
branch
from
October 18, 2026 17:33
83e75cf to
e524b23
Compare
xperiandri
commented
Oct 18, 2026
The order check runs the signature files in parallel: each pair is independent, so `Array.Parallel.collect` keeps the violations in file order without a shared list. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The contract assert helpers are static classes with methods and an optional `message`, like the `Assert` class of MSTest: `ExceptionAssert.Same` / `Mirrored` / `Headline` and `OverrideAssert.OptionMatches` / `PairMatches` / `TripleMatches`. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
xperiandri
commented
Oct 18, 2026
The optional `message` of the contract assert helpers is a struct optional parameter, so it is a `voption`. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Open
5 of 6 tasks
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.


Proposed Changes
First link of the chain that implements ADR 0001 – Per-collection modules (#23): the foundation that the collection pull requests build on. It changes no public function yet.
Helper.fsreplacesImmutableCollectionUtil.fs(same internal module, so the legacy files compile unchanged) and addscheckNotDefault, which treats a defaultImmutableArrayas FSharp.Core treats anullarray.build/check-order.fsxchecks every signature file: the functions are grouped under// ---- Category ----banners in the canonical order of ADR 0001 D4, sorted ordinally inside a category (active patterns last), and the implementation file repeats the banners and the order. It readsval internalandval privatedeclarations correctly. The FAKE targetCheckOrderruns it beforeDotnetBuild; the README lists the target.net8.0andnet10.0(D10); CI and the dev container already install both runtimes.List.partitionWith,Array.partitionWithandSet.partitionWith, which the modules mirror.TestCategories.fswith one category attribute per collection and per specialized area, sorted by type name;TestCategoriesTests.fs, which enforces the category rules of ADR 0001 D8 and keeps the test run non-empty: one category per attribute, named after the type, the attributes sorted, a category attribute of this project on every test class, no category on a test method and no category written as a string;Contracts/Inputs.fs,Contracts/ExceptionAssert.fs(compares an exception with the one of the mirrored FSharp.Core function: type, first line of the message and parameter name, under the invariant culture, because FSharp.Core ships localized messages),Contracts/OverrideAssert.fs, andContracts/Mirror.fswith the FSharp.Core module that a collection mirrors..github/copilot-instructions.mddescribes the new layout: the types files, the comparer structs, the extension modules, root modules and categories on the test classes.Types of changes
What types of changes does your code introduce to FSharp.Collections.Immutable?
Put an
xin the boxes that applyThe package requires FSharp.Core 10.1.301 or later.
Checklist
Put an
xin the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.Further comments
One deviation from ADR 0001 D9: the contract bases arrive with the first collection that implements them (
FlatListbrings the sequence-like facets,HashMapthe map facets,HashSetthe set facets) instead of this pull request, so each base is reviewed together with an implementation that runs it.The collection pull requests are stacked on this one. Each one merges into the branch it is based on until this one is in
main.The test helpers move to arrays and data rows (the new Testing rules on
main) in a follow-up push.🤖 Generated with Claude Code