Skip to content

Record the parameter and type parameter counts of a navigable item - #20531

Open
xperiandri wants to merge 2 commits into
dotnet:mainfrom
xperiandri:navigable-item-parameter-counts
Open

xperiandri wants to merge 2 commits into
dotnet:mainfrom
xperiandri:navigable-item-parameter-counts

Conversation

@xperiandri

Copy link
Copy Markdown
Contributor

Description

Navigate To orders matches of the same kind by a secondary sort. For C# and VB that key holds each declaration's parameter and type parameter counts, taken from Roslyn's declaration index, after the folder distance to the file being edited. dotnet/roslyn#85280 computes the same key for F# results, and needs F# to supply the two counts.

NavigateTo.GetNavigableItems is where F# builds its declaration list from the parse tree, so NavigableItem now carries:

  • ParameterCount: every curried and tupled argument of the method the declaration compiles to. An instance member's self argument is not counted, and neither is a solitary unit argument: let f () = … and val f: unit -> int count 0, let f () x = … counts 2. Bindings take it from the arity the parser inferred. For signatures, the parser leaves a solitary unit argument in the arity, so it is recognised from the type.
  • TypeParameterCount: the explicitly declared type parameters of a type, binding or signature.

This changes the public surface: NavigableItem is a record, so code that constructs one must supply the two fields.

Checklist

  • Test cases added: NavigateToTests covers values, curried, tupled and unit functions, generic functions, types, instance and static members and properties, in implementation and signature files.
  • Performance benchmarks added in case of performance changes
  • Release notes entry updated

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

❗ Release notes required

You can open this PR in browser to add release notes: open in github.dev

@xperiandri,

Caution

No release notes found for the changed paths (see table below).

Please make sure to add an entry with an informative description of the change as well as link to this pull request, issue and language suggestion if applicable. Release notes for this repository are based on Keep A Changelog format.

The following format is recommended for this repository:

`* . (PR #XXXXX)`

See examples in the files, listed in the table below or in th full documentation at https://fsharp.github.io/fsharp-compiler-docs/release-notes/About.html.

If you believe that release notes are not necessary for this PR, please add NO_RELEASE_NOTES label to the pull request.

Change path Release notes path Description
`src/Compiler` docs/release-notes/.FSharp.Compiler.Service/11.0.200.md No release notes found or release notes format is not correct

@github-actions

This comment has been minimized.

@github-actions github-actions Bot added the ⚠️ Affects-Design-Time Tooling check: PR touches type providers or dependency manager label Sep 13, 2026

@T-Gro T-Gro left a comment

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.

🤖 🕵️ AI review — verify independently.

| SynType.LongIdent(SynLongIdent([ id ], _, _)) -> id.idText = "unit"
| SynType.Paren(innerType, _)
| SynType.WithGlobalConstraints(innerType, _, _) -> isUnitType innerType
| _ -> false

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.

🤖 🕵️ Named unit parameter counted as 1 in the signature but 0 in the implementation — different Navigate To sort keys for the same zero-argument method.

// NamedUnit.fsi
module NamedUnit
val Search : u: unit -> int

// NamedUnit.fs
module NamedUnit
let Search () = 1

@T-Gro T-Gro added the AI-reviewed PR reviewed by AI review council label Sep 14, 2026
@T-Gro
T-Gro self-requested a review September 14, 2026 14:32

/// The parameters of the compiled method: the parser leaves a solitary unit argument of a signature in its arity,
/// where a binding has already dropped it.
let private parameterCountOfSignature (SynValInfo(curriedArgInfos, _)) (synType: SynType) =

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.

I am afraid this might alltogether operate on a wrong layer, considering things like:

  • unit
  • byrefs
  • units of measure

This should follow existing functions that know how a function is represented in IL.

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.

The layer is forced by what the caller is: NavigateTo.GetNavigableItems runs on a parse tree alone. Navigate To has to answer for every document in the solution, and it has to answer while the solution is still loading, so no checking has happened and there is no Val, no TType, nothing the arity functions (GetTopValTypeInFSharpForm, ArgInfosOfMember) could be handed. Reaching for them here would mean checking every document in the solution to fill in a sort tiebreak.

That is also the layer the numbers are compared against. They exist for NavigateToSearchResultHelpers.ComputeSecondarySort, which orders results that already matched the pattern equally well, and C# and Visual Basic fill them the same way — CSharpDeclaredSymbolInfoFactoryService takes ParameterList.Parameters.Count and TypeParameterList?.Parameters.Count straight off the declaration syntax. A wrong count moves one same-named result past another in that list; it is never asked whether two members are the same member.

On the three you named:

  • byrefs — a byref parameter is still one parameter in IL, so the count is unaffected;
  • units of measure — a measure annotates the type of a parameter and adds none, so likewise;
  • unit — this one really does differ, and it is the only one that does. A solitary unit argument is dropped by the compiler but left in the arity the parser produces for a signature, so val f : unit -> int and let f () = 1 disagreed. That is handled.

The remaining hole is the named form the bot found in the other thread, val Search : u: unit -> int: the check looks through SynType.Paren and SynType.WithGlobalConstraints but not through SynType.SignatureParameter, so a named unit still counts as one. Fixing that, and adding both spellings to the tests.

If the team would rather the two numbers be IL-accurate, then they cannot come from this walker at all and the tiebreak needs a different source — happy to take that route instead, but it is a different change from this one.

@xperiandri
xperiandri force-pushed the navigable-item-parameter-counts branch from b0f52c9 to 188278c Compare September 22, 2026 11:34
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

xperiandri and others added 2 commits September 26, 2026 03:00
Navigate To orders matches that are otherwise equal by these counts for C#
and VB. NavigableItem now carries them: every curried and tupled argument of
the method a declaration compiles to, without the instance and without a
solitary unit argument, and its explicitly declared type parameters.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 26, 2026 01:00
@xperiandri
xperiandri force-pushed the navigable-item-parameter-counts branch from 188278c to f1b560c Compare September 26, 2026 01:00

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

Two correctness issues remain in parameter-count computation, and the release note is in the wrong version file.

Review effort: Lite
Findings: 1 Medium severity

Open (1)
What changed in this PR

Adds parameter and type-parameter counts to F# NavigableItem results for consistent Navigate To ordering.

Changes:

  • Computes counts from implementation and signature syntax.
  • Extends the public API and surface-area baseline.
  • Adds comprehensive tests and release notes.
File Summary
tests/​FSharp.Compiler.Service.Tests/​NavigateToTests.fs Adds coverage for declaration count behavior.
tests/​FSharp.Compiler.Service.Tests/​FSharp.Compiler.Service.Tests.fsproj Includes the updated tests.
tests/​FSharp.Compiler.Service.Tests/​FSharp.Compiler.Service.SurfaceArea.netstandard20.bsl Updates the API baseline.
src/​Compiler/​Service/​ServiceNavigation.fsi Exposes and documents the new fields.
src/​Compiler/​Service/​ServiceNavigation.fs Computes declaration counts; labeled unit signatures and property setters require corrections (moderate, 3 and 1 votes).
docs/​release-notes/​.FSharp.Compiler.Service/​11.0.100.md Adds release notes, but the entry should move to the current 11.0.200 file (nit, 1 vote).

Comment on lines +780 to +783
| SynType.LongIdent(SynLongIdent([ id ], _, _)) -> id.idText = "unit"
| SynType.Paren(innerType, _)
| SynType.WithGlobalConstraints(innerType, _, _) -> isUnitType innerType
| _ -> false
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Tooling Safety Check — Affects-Design-Time
Affects-Design-Time: Changes Navigate To declaration metadata.

Generated by PR Tooling Safety Check · gpt56 913.7K · ◷

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

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

3 participants