Skip to content

Preserve type aliases in match | null refinement#19745

Open
T-Gro wants to merge 3 commits into
mainfrom
fix/nullness-dropping-alias
Open

Preserve type aliases in match | null refinement#19745
T-Gro wants to merge 3 commits into
mainfrom
fix/nullness-dropping-alias

Conversation

@T-Gro
Copy link
Copy Markdown
Member

@T-Gro T-Gro commented May 15, 2026

Fixes #19646

After match x with | null -> … | s -> …, the binding s was losing its type alias (e.g. string became System.String). Now we try to clear nullness on the original type first, preserving the alias; only fall back to stripping abbreviations when nullness is embedded in the abbreviation RHS.

T-Gro and others added 2 commits May 14, 2026 16:57
…ttern)

After 'match x with | null -> ... | s -> ...', the type of s loses its
alias (e.g. 'string' becomes 'System.String'). These tests lock in the
desired behavior; they fail on main and will pass once the fix lands.

Refs #19646

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The removeNull helper in TcMatchClause was unconditionally calling
stripTyEqns, which expanded transparent abbreviations like 'string' to
'System.String'. As a result, in:

    let test (x: string | null) =
        match x with
        | null -> null
        | s -> s.Replace("a", "b")

the inferred type of 's' was displayed as 'String' instead of 'string'.

Fix: try the cheap path first (replaceNullnessOfTy KnownWithoutNull),
which preserves the abbreviation. If the resulting effective nullness is
already WithoutNull (transparent aliases like 'string' / 'MyStr'), use
that. Otherwise (abbreviations that encode nullness in their RHS, like
'type objnull = obj | null'), fall back to the full stripTyEqns path
introduced by #18852 to keep that regression fixed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 15, 2026

❗ Release notes required


✅ Found changes and release notes in following paths:

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/11.0.100.md

@T-Gro T-Gro requested a review from abonie May 15, 2026 12:26
@T-Gro T-Gro added AI-Auto-Resolve-Conflicts Opt-in: LabelOps merges main into this PR and resolves conflicts every 3h AI-Auto-Resolve-CI Opt-in: LabelOps triages CI failures on this PR every 3h labels May 15, 2026
Per review feedback: parameterize the three alias preservation cases
(string, user alias, Uri alias) into a single Theory with InlineData,
and drop the redundant negative test (the case-sensitive substring
match on 'string' already rules out 'String').

Refs #19646

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@T-Gro T-Gro force-pushed the fix/nullness-dropping-alias branch from a34dcfc to 716d47d Compare May 15, 2026 12:26
@github-actions github-actions Bot added the AI-Tooling-Check-Bypassed Tooling check: non-fork PR, not diff-analyzed label May 15, 2026
@github-actions github-actions Bot mentioned this pull request May 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI-Auto-Resolve-CI Opt-in: LabelOps triages CI failures on this PR every 3h AI-Auto-Resolve-Conflicts Opt-in: LabelOps merges main into this PR and resolves conflicts every 3h AI-Tooling-Check-Bypassed Tooling check: non-fork PR, not diff-analyzed

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

Nullness issue - String should be inferred as string

1 participant