Skip to content

Comments

[Repo Assist] fix: preserve nullable type annotations in hover tooltips#1461

Closed
github-actions[bot] wants to merge 1 commit intomainfrom
repo-assist/fix-issue-1352-nullable-type-in-hover-tooltip-d6a07722c4bbfd1c
Closed

[Repo Assist] fix: preserve nullable type annotations in hover tooltips#1461
github-actions[bot] wants to merge 1 commit intomainfrom
repo-assist/fix-issue-1352-nullable-type-in-hover-tooltip-d6a07722c4bbfd1c

Conversation

@github-actions
Copy link
Contributor

🤖 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 | null syntax), the hover tooltip showed just string instead of string | null, while inlay hints and linelens showed the correct string | null.

Root Cause

In SignatureFormatter.formatFSharpType, the branch handling simple non-generic types (HasTypeDefinition && GenericArguments.Count = 0) used typ.TypeDefinition.DisplayName directly:

else if typ.HasTypeDefinition then
    FSharpKeywords.NormalizeIdentifierBackticks typ.TypeDefinition.DisplayName

TypeDefinition.DisplayName is just the bare type name (e.g. "string") and does not include nullability annotations. The F# Compiler Service's FSharpType.Format method, on the other hand, correctly produces "string | null" when the type carries a null annotation.

Inlay hints use ty.Format displayContext directly (in InlayHints.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.DisplayName with typ.Format context in the simple non-generic type branch of formatFSharpType:

else if typ.HasTypeDefinition then
    // Use typ.Format to preserve nullability annotations (e.g. `string | null`)
    // for simple non-generic types; FCS correctly includes `| null` in the output.
    typ.Format context

For non-nullable simple types (string, int, bool, etc.) the output of typ.Format context is identical to TypeDefinition.DisplayName, so there is no regression for the common case.

Test Status

  • Build: ✅ dotnet build src/FsAutoComplete/FsAutoComplete.fsproj -f net8.0 succeeded with 0 warnings, 0 errors.
  • Tests: Infrastructure constraint in this environment prevented running the full test suite. The fix is a one-line change in a pure string-formatting function with no side effects beyond adding | null where FCS reports it.

Trade-offs

  • FSharpKeywords.NormalizeIdentifierBackticks is no longer applied for simple types — however, FSharpType.Format itself goes through the compiler's formatter which already handles keyword-escaping. The existing with _ -> typ.Format context fallback had the same behaviour, so this is consistent.
  • The else if typ.HasTypeDefinition and else branches now both call typ.Format context. They could be merged into a single else, but keeping the structure unchanged makes the diff minimal and easier to review.

Generated by Repo Assist

To install this workflow, run gh aw add githubnext/agentics/workflows/repo-assist.md@828ac109efb43990f59475cbfce90ede5546586c. View source at https://github.com/githubnext/agentics/tree/828ac109efb43990f59475cbfce90ede5546586c/workflows/repo-assist.md.

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>
@github-actions
Copy link
Contributor Author

✅ Pull request created: #1461

@Krzysztof-Cieslak
Copy link
Member

/repo-assist create tests for this case

@github-actions
Copy link
Contributor Author

🤖 This is an automated response from Repo Assist.

Tests have been created in a new draft PR. The changes are:

TestCases/Tooltips/Script.fsx — two new lines:

let nullableStringVal: string | null = null
let returnsNullable (s: string) : string | null = null

CoreTests.fs — two new verifySignature assertions that would fail on main (showing just string) and pass with this fix applied (showing string | null).

The test PR targets the same fix branch so both the fix and the tests can be reviewed and merged together.

Generated by Repo Assist for issue #1461

To install this workflow, run gh aw add githubnext/agentics/workflows/repo-assist.md@828ac109efb43990f59475cbfce90ede5546586c. View source at https://github.com/githubnext/agentics/tree/828ac109efb43990f59475cbfce90ede5546586c/workflows/repo-assist.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant