[Repo Assist] fix: preserve nullable type annotations in hover tooltips#1461
Conversation
In formatFSharpType, simple non-generic types (HasTypeDefinition but GenericArguments.Count = 0) were formatted using TypeDefinition.DisplayName, which loses any nullability annotation from the F# 9 nullable reference type feature. For example, a function returning 'string | null' would show just 'string' in the hover tooltip, while inlay hints (which use FSharpType.Format) correctly showed 'string | null'. Switching to typ.Format context for this branch lets FCS include the '| null' suffix when present, while still respecting the caller's DisplayContext (open statements, qualified name settings, etc.). For non-nullable types the output is unchanged. Closes #1352 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
✅ Pull request created: #1461 |
|
/repo-assist create tests for this case |
|
🤖 This is an automated response from Repo Assist. Tests have been created in a new draft PR. The changes are:
let nullableStringVal: string | null = null
let returnsNullable (s: string) : string | null = null
The test PR targets the same fix branch so both the fix and the tests can be reviewed and merged together.
|
🤖 This PR was created by Repo Assist, an automated AI assistant.
Summary
Fixes
hover tooltip does not show nullable values as possibly null(#1352).When hovering over a symbol with a nullable reference type (F# 9
| nullsyntax), the hover tooltip showed juststringinstead ofstring | null, while inlay hints and linelens showed the correctstring | null.Root Cause
In
SignatureFormatter.formatFSharpType, the branch handling simple non-generic types (HasTypeDefinition && GenericArguments.Count = 0) usedtyp.TypeDefinition.DisplayNamedirectly:TypeDefinition.DisplayNameis just the bare type name (e.g."string") and does not include nullability annotations. The F# Compiler Service'sFSharpType.Formatmethod, on the other hand, correctly produces"string | null"when the type carries a null annotation.Inlay hints use
ty.Format displayContextdirectly (inInlayHints.fs), which is why they showed the correct type — the tooltip code path had a divergent, hand-rolled formatter that lost the annotation.Fix
Replace
TypeDefinition.DisplayNamewithtyp.Format contextin the simple non-generic type branch offormatFSharpType:For non-nullable simple types (
string,int,bool, etc.) the output oftyp.Format contextis identical toTypeDefinition.DisplayName, so there is no regression for the common case.Test Status
dotnet build src/FsAutoComplete/FsAutoComplete.fsproj -f net8.0succeeded with 0 warnings, 0 errors.| nullwhere FCS reports it.Trade-offs
FSharpKeywords.NormalizeIdentifierBackticksis no longer applied for simple types — however,FSharpType.Formatitself goes through the compiler's formatter which already handles keyword-escaping. The existingwith _ -> typ.Format contextfallback had the same behaviour, so this is consistent.else if typ.HasTypeDefinitionandelsebranches now both calltyp.Format context. They could be merged into a singleelse, but keeping the structure unchanged makes the diff minimal and easier to review.