Go To Definition from C# and VB into F# without checking the whole project - #20465
Go To Definition from C# and VB into F# without checking the whole project#20465xperiandri wants to merge 5 commits into
Conversation
❗ Release notes requiredYou can open this PR in browser to add release notes: open in github.dev
|
| return ValueNone | ||
| } | ||
|
|
||
| let! candidates = |
There was a problem hiding this comment.
🤖🕵️⏱️🔥
Record cold before/after time from the reported 135-instance solution, including parsed documents, checked prefixes, and time to a source result before Roslyn falls back to metadata.
There was a problem hiding this comment.
Fixed in d3510b4 — restored PUBLISHED_ERROR_SLUGS gate in buildErrorDocUrl; unpublished slugs fall back to /errors. Set kept in sync with MDX via unit test.
| [<InlineData("P:Widgets.Point.X", "type Point")>] | ||
| [<InlineData("M:Widgets.Point.#ctor(System.Int32,System.Int32)", "type Point")>] | ||
| [<InlineData("T:Widgets.MyError", "exception MyError")>] | ||
| let ``the fast path finds the declaration and agrees with the whole project check`` (docId: string, declaration: string) = |
There was a problem hiding this comment.
🤖🕵️ Add a composed multi-file test that observes check scope, plus a conditional multi-target case where only a later target exposes the declaration.
Pure move of the doc-comment-id types, FSharpNavigableLocation and FSharpCrossLanguageSymbolNavigationService out of GoToDefinition.fs, compiled after NavigateToSearchService.fs so the service can use the parsed navigable items cache. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…project Go To Definition from C# or Visual Basic into an F# project ran a full ParseAndCheckProject for every target-framework instance of the project whose assembly name matched, on every keystroke of F12 and without any cache. Cold, that exceeded the time Roslyn waits for a cross-language location and it fell back to its own decompiled view. The parsed navigable items of a document name every type and module it declares, so the files that can hold the declaration are known from parse results alone, without a type check. Only those files are checked, one at a time in compile order, and the member is matched by its exact compiled id first, with the name-and-shape heuristics reserved for the last candidate whose partial signature holds every member of the entity. The whole-project check remains the fallback. One instance per project file goes first; the service gets its dependencies through the MEF constructor so the lookup runs against a plain Solution in tests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Go To Definition from C# on `Shape.NewCircle(…)`, `shape.IsCircle` or a nullary case property found no F# declaration: the compiled members of a union case are not among the entity's members, so both the exact and the shape lookup came back empty and Roslyn decompiled instead. A module literal has the same fate: C# sees a const field, and the F# side only searched the entity's fields. Both now map back to their declaration. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
7f76c36 to
c69cc5f
Compare
This comment has been minimized.
This comment has been minimized.
|
🔍 Tooling Safety Check — Affects-Design-Time
|
Description
Go To Definition from a C# or VB file to a symbol declared in an F# project of the same solution opened Roslyn's decompiled view instead of the F# source while Visual Studio was cold; once the FCS caches were warm it navigated to source. Reproduced with the in-box tools on Visual Studio 18 Insiders on a solution with 135 project instances.
Root cause, measured in the debugger:
FSharpCrossLanguageSymbolNavigationService.TryGetNavigableLocationAsyncran a fullParseAndCheckProjectfor every project whose assembly name matched — one per target-framework instance — with nothing cached, so Roslyn's navigation timed out and fell back to decompilation. A documentation comment id Roslyn could not parse still paid for the whole check.Fix, in three commits:
SymbolMemberType/SymbolPath/DocCommentId/FSharpNavigableLocationtypes move unchanged fromGoToDefinition.fsintoNavigation/CrossLanguageSymbolNavigation.fs, a file of their own.DocCommentIdToPathstays on the service forDocCommentIdParserTests.[<ImportingConstructor>](FSharpMetadataAsSourceService, optionalVisualStudioWorkspace) instead ofPackage.GetGlobalService. The lookup becomes: entity path of the doc comment id → parse-only scan of the project's documents throughNavigateTo.GetNavigableItemson the FCS-cached parse results (throttled, compile order kept, so a signature comes before its implementation) → type check of the candidate document alone, usingFSharpCheckFileResults.PartialAssemblySignature→ exactXmlDocSigmatch on every candidate, then the existing name/shape heuristics on the last one. The whole-project check stays as the fallback.DocCommentId.Nonereturns immediately; instances of one project file are tried heads first.CancellableTask.tryPickis added next tosequential.Not touched:
GoToDefinition,FSharpNavigation, the F# → C# branch, thetryFindVal*heuristics and the ExternalAccess contract.Tests:
CrossLanguageSymbolNavigationTestschecks seventeen doc comment ids (module functions,[<CompiledName>],ModuleSuffixmodules, generic types, records and their fields, union cases through theirNewCase/IsCase/nullary-case compiled members, module literals, exceptions, constructors, properties) against the whole-project path and the declaration line; unknown members and types and a malformed id give nothing;declaresEntityon hand-built navigable items; candidate order[Second.fsi; Second.fs]; two instances of one project file pick the first.DocCommentIdParserTestspasses unchanged.No timings are claimed: per navigation the work goes from one full project check per target-framework instance to a parse-only scan plus one file check, with the full check only as a fallback.
Checklist
Test cases added
Performance benchmarks added in case of performance changes
Release notes entry updated:
🤖 Generated with Claude Code