Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 5, 2026

String Empty Pattern Match Optimization - Investigation Complete

Comprehensive investigation of redundant null check elimination completed. The isNullFiltered parameter infrastructure is in place but not eliminating redundant checks as expected.

Changes Made

  1. Removed hasIsNullEdge computation (line 821-823): Simplified the logic to only use the isNullFiltered parameter that's passed through recursive calls, rather than trying to detect IsNull edges in the current edges list.

  2. Debug instrumentation in place (lines 774-851): Comprehensive logging available via verbose flag to trace pattern compilation flow.

Current Behavior

The optimization IS working for the primary goal:

  • ✅ Empty string patterns use .Length == 0 instead of String.Equals
  • ✅ Null safety is preserved (no crashes on null input)
  • ✅ All patterns compile correctly

But redundant null checks remain:

  • ❌ OR patterns like | null | "" -> 0 generate two null checks
  • ❌ Separate clauses also show this behavior

Root Cause Analysis

The isNullFiltered parameter is set to true at line 801 after processing an IsNull edge, and passed to recursive BuildSwitch calls at line 811. However, the IL shows the redundant check persists.

Theory: The issue may be that the empty string check is being generated in a DIFFERENT BuildSwitch invocation than where isNullFiltered=true was set. The decision tree structure for OR patterns may not be what we expect.

Next Steps

Need to understand the exact decision tree structure created for OR patterns. The verbose flag provides logging, but output isn't captured in test runs. May need to create a standalone compilation scenario to trace the exact flow.

Original prompt

Motivation

Replace F# pattern match empty string equality with a length check for performance, but preserve null safety. The optimization must ensure that match s with "" pattern NEVER crashes if s is null, even if the programmer did not add a null case.

Implementation Steps

  1. Extend DecisionTreeTest with: | StringLengthZero of TType
  2. In getDiscrimOfPattern, emit DecisionTreeTest.StringLengthZero for TPat_const (Const.String "").
  3. Update discrimsEq and discrimWithinSimultaneousClass to support the new case.
  4. In isDiscrimSubsumedBy, ensure null subsumes empty string (avoids emitting a second null check).
  5. In BuildSwitch, emit code that guards .Length checks with a null test unless a previous pattern already filtered null. Never access .Length if value might be null.

Testing Steps

  • Add/modify tests for typechecking, IL, and runtime under:
    • tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs
    • tests/FSharp.Compiler.ComponentTests/EmittedIL/PatternMatching/PatternMatchingTests.fs
    • tests/FSharp.Compiler.ComponentTests/Language/Execution/ExecutionTests.fs
  • Edge case: Programmer omits "null" pattern, but the value is null.
  • Edge case: Both null and "" handled—confirm only one null check is emitted in generated IL.
  • Rerun and compare existing IL tests to confirm no regressions or unsafe changes.
  • Compile-and-run tests for ("", null, non-empty) must never crash and yield correct output.

Safety

  • Never call .Length if the value could be null. Always cover missing null case in tests.

Example Test:

let f (x: string) = match x with | "" -> "empty" | _ -> "other"
// Should not crash for null, must print: "empty,other,other" for ("", null, "x")

This pull request was created from Copilot chat.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Copilot AI and others added 2 commits January 5, 2026 16:14
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Copilot AI changed the title [WIP] Optimize F# pattern match for empty string equality Optimize empty string pattern matching with null-safe length checks Jan 5, 2026
Copilot AI requested a review from T-Gro January 5, 2026 16:22
…ion in BuildSwitch only

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
…ompatibility

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
…, move release notes to 10.0.200

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
…ontexts

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
…t null checks

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@dotnet dotnet deleted a comment from Copilot AI Jan 12, 2026
@T-Gro
Copy link
Member

T-Gro commented Jan 13, 2026

/run ilverify

@github-actions
Copy link
Contributor

🔧 CLI Command Report

  • Command: /run ilverify
  • Outcome: success

✅ Patch applied:
- Files changed: 4
- Lines changed: 126

@T-Gro T-Gro marked this pull request as ready for review January 14, 2026 14:07
@T-Gro T-Gro requested a review from a team as a code owner January 14, 2026 14:07
@T-Gro T-Gro requested a review from abonie January 14, 2026 14:07
@T-Gro T-Gro enabled auto-merge (squash) January 14, 2026 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

4 participants