Skip to content

Move NullableBool to Common with sbyte backing; replace scattered tri-state int/sbyte patterns#125307

Merged
jkotas merged 11 commits intomainfrom
copilot/move-nullablebool-under-common
Mar 9, 2026
Merged

Move NullableBool to Common with sbyte backing; replace scattered tri-state int/sbyte patterns#125307
jkotas merged 11 commits intomainfrom
copilot/move-nullablebool-under-common

Conversation

Copy link
Contributor

Copilot AI commented Mar 8, 2026

Description

Consolidates the common "lazy-initialized cached bool" pattern into a single shared NullableBool : sbyte enum, replacing local volatile int/volatile sbyte tri-state fields and the private Tristate enum in TextInfo.

Changes

  • New: src/libraries/Common/src/System/NullableBool.csinternal enum NullableBool : sbyte { Undefined = 0, False = -1, True = 1 }. sbyte backing fits in one byte (same as bool) and is valid for volatile. Unlike bool?, it is safe to use from multiple threads (a Nullable<T> is a two-field struct that can tear under concurrent access).

  • Removed: private nested NullableBool enum from SafeFileHandle.Unix.cs (fields already typed NullableBool, now reference Common).

  • Replaced Tristate in TextInfo: The local Tristate : byte { NotInitialized=0, False=1, True=2 } driving _isAsciiCasingSameAsInvariant and _needsTurkishCasing is replaced with NullableBool.

  • Replaced volatile int tri-state fields (-1 = unset, 0 = false, 1 = true) in:

    • ConsoleUtils.css_emitAnsiColorCodes
    • AuthenticationHelper.NtAuth.css_usePortInSpn
    • SslStream.Protocol.css_disableTlsResume and s_enableServerAiaDownloads
    • NameResolutionPal.Windows.css_getAddrInfoExSupported (also removes the now-unnecessary Interlocked.CompareExchange; initialization is idempotent, consistent with all other patterns)
  • Replaced volatile sbyte tri-state fields (same encoding: 0 = unset, 1 = true, -1 = false) in:

    • Environment.css_privilegedProcess
    • Interop.MemfdCreate.css_memfdSupported (also removes Interlocked.CompareExchange; MemfdSupportedImpl() is idempotent — read-only kernel version check and syscall)
  • Replaced volatile int field with non-standard encoding (remapped to NullableBool equivalents) in:

    • ProcessManager.Linux.cs_procMatchesPidNamespace (was 0 = unset, 1 = match, 2 = no match; remapped to NullableBool.Undefined, NullableBool.True, NullableBool.False)
  • Project file updates: Added NullableBool.cs to System.Private.CoreLib.Shared.projitems, System.Console.csproj, Microsoft.Extensions.Logging.Console.csproj, System.Net.Http.csproj, System.Net.NameResolution.csproj, System.Net.Security.csproj, System.IO.MemoryMappedFiles.csproj (unix/browser/wasi group), System.Diagnostics.Process.csproj (linux group), and System.Net.NameResolution.Pal.Tests.csproj (Windows group — the test project directly compiles NameResolutionPal.Windows.cs and also needs the type).

Before / After

// Before
private static volatile int s_usePortInSpn = -1;
int usePortInSpn = s_usePortInSpn;
if (usePortInSpn != -1)
    return usePortInSpn != 0;
s_usePortInSpn = value ? 1 : 0;

// After
private static volatile NullableBool s_usePortInSpn;
NullableBool usePortInSpn = s_usePortInSpn;
if (usePortInSpn != NullableBool.Undefined)
    return usePortInSpn == NullableBool.True;
s_usePortInSpn = value ? NullableBool.True : NullableBool.False;

Testing

All affected libraries build successfully (System.Private.CoreLib, System.Console, System.Net.Http, System.Net.NameResolution, System.Net.Security, System.IO.MemoryMappedFiles, System.Diagnostics.Process). Windows CI build break (CS0246 in System.Net.NameResolution.Pal.Tests) resolved by adding NullableBool.cs to the test project's Windows ItemGroup.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Mar 8, 2026
…des, s_usePortInSpn, s_getAddrInfoExSupported, s_disableTlsResume with NullableBool

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI changed the title [WIP] Move NullableBool enum under Common and update usage Move NullableBool to Common with sbyte backing; replace scattered tri-state int patterns Mar 8, 2026
@github-actions github-actions bot added area-Meta and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Mar 8, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-meta
See info in area-owners.md if you want to be subscribed.

…hread safety comment

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@jkotas
Copy link
Member

jkotas commented Mar 8, 2026

@copilot Could you please check for other places throughout the repo that can be refactored to use NullableBool?

…ableBool

- Environment.cs: volatile sbyte s_privilegedProcess → NullableBool
- Interop.MemfdCreate.cs: volatile sbyte s_memfdSupported → NullableBool;
  removes Interlocked.CompareExchange (MemfdSupportedImpl is idempotent)
- System.IO.MemoryMappedFiles.csproj: add NullableBool.cs to unix group

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 8, 2026

@copilot Could you please check for other places throughout the repo that can be refactored to use NullableBool?

Found and refactored two additional sites (commit 728a0db):

  • Environment.css_privilegedProcess: volatile sbyte (0=unset, 1=true, -1=false) → volatile NullableBool. Already in namespace System so no extra using needed.
  • Interop.MemfdCreate.css_memfdSupported: volatile sbytevolatile NullableBool. Also removed the Interlocked.CompareExchange since MemfdSupportedImpl() is idempotent (read-only kernel version check + syscall), matching the pattern used throughout the rest of this PR. Added using System; and NullableBool.cs to System.IO.MemoryMappedFiles.csproj (unix/browser/wasi group).

Other patterns checked and ruled out:

  • DateTimeOffset.Android.cs s_androidTZDataLoaded — genuinely three-state (-1=unset, 0=loading-in-progress, 1=loaded), not a bool cache.
  • RuntimeInformation.Unix/Windows.cs s_osArchPlusOne — encodes an Architecture enum value as value+1, not bool.
  • ProcessManager.Linux.cs _procMatchesPidNamespace — uses 0/1/2 (not 0/1/-1), not NullableBool-compatible.

Copilot AI changed the title Move NullableBool to Common with sbyte backing; replace scattered tri-state int patterns Move NullableBool to Common with sbyte backing; replace scattered tri-state int/sbyte patterns Mar 8, 2026
@jkotas
Copy link
Member

jkotas commented Mar 8, 2026

ProcessManager.Linux.cs _procMatchesPidNamespace — uses 0/1/2 (not 0/1/-1), not NullableBool-compatible.

@copilot This is a good candidate for NullableBool. Please change it by remapping 0/1/2 to NullableBool equivalents.

…ableBool

Remap 0/1/2 (uninitialized/match/no-match) to NullableBool.Undefined/True/False.
Add NullableBool.cs to the linux ItemGroup in System.Diagnostics.Process.csproj.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 8, 2026

ProcessManager.Linux.cs _procMatchesPidNamespace — uses 0/1/2 (not 0/1/-1), not NullableBool-compatible.

@copilot This is a good candidate for NullableBool. Please change it by remapping 0/1/2 ...

Done in cf04cca. Remapped 0→NullableBool.Undefined, 1→NullableBool.True, 2→NullableBool.False, updated the check and return accordingly, and added NullableBool.cs to the linux ItemGroup in System.Diagnostics.Process.csproj. The old comment explaining the 0/1/2 encoding was also removed as it's no longer needed.

@jkotas jkotas marked this pull request as ready for review March 8, 2026 18:37
Copilot AI review requested due to automatic review settings March 8, 2026 18:37
@jkotas
Copy link
Member

jkotas commented Mar 8, 2026

@copilot Please fix this build break on Windows:

src\libraries\System.Net.NameResolution\src\System\Net\NameResolutionPal.Windows.cs(18,33): error CS0246: (NETCORE_ENGINEERING_TELEMETRY=Build) The type or namespace name 'NullableBool' could not be found (are you missing a using directive or an assembly reference?)

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR standardizes the repo’s “tri-state cached bool” pattern by introducing a shared System.NullableBool : sbyte in src/libraries/Common and migrating multiple call sites away from ad-hoc int/sbyte sentinel encodings and TextInfo’s local Tristate enum.

Changes:

  • Added internal enum NullableBool : sbyte (Undefined/False/True) in src/libraries/Common and linked it into affected projects.
  • Replaced local tri-state patterns in several libraries (CoreLib, Console, Http, NameResolution, Security, MemoryMappedFiles, Diagnostics.Process) with NullableBool.
  • Removed the redundant local NullableBool enum from SafeFileHandle.Unix.cs and Tristate from TextInfo.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs Replaces Tristate with NullableBool for ASCII casing cache.
src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Icu.cs Replaces Tristate with NullableBool for Turkish casing cache.
src/libraries/System.Private.CoreLib/src/System/Environment.cs Converts privileged-process cached tri-state from sbyte to NullableBool.
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems Links Common\System\NullableBool.cs into CoreLib shared items.
src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs Removes local NullableBool enum (now uses Common’s).
src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs Converts TLS resume switch cache from int tri-state to NullableBool.
src/libraries/System.Net.Security/src/System.Net.Security.csproj Links Common\System\NullableBool.cs into System.Net.Security.
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs Converts GetAddrInfoEx support cache from int tri-state to NullableBool.
src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj Links Common\System\NullableBool.cs into System.Net.NameResolution.
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs Converts SPN port switch cache from int tri-state to NullableBool.
src/libraries/System.Net.Http/src/System.Net.Http.csproj Links Common\System\NullableBool.cs into System.Net.Http.
src/libraries/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj Links Common\System\NullableBool.cs to support Common interop usage.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs Remaps _procMatchesPidNamespace tri-state encoding onto NullableBool.
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj Links Common\System\NullableBool.cs into System.Diagnostics.Process (Linux group).
src/libraries/System.Console/src/System.Console.csproj Links Common\System\NullableBool.cs into System.Console.
src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj Links Common\System\NullableBool.cs into Microsoft.Extensions.Logging.Console.
src/libraries/Common/src/System/NullableBool.cs Adds the shared tri-state enum definition (sbyte-backed).
src/libraries/Common/src/System/Console/ConsoleUtils.cs Converts ANSI color emission cache from int tri-state to NullableBool.
src/libraries/Common/src/Interop/Unix/System.Native/Interop.MemfdCreate.cs Converts memfd support cache from sbyte tri-state to NullableBool and removes interlocked CAS.

….Tests.csproj Windows ItemGroup

The test project directly includes NameResolutionPal.Windows.cs (which uses NullableBool)
but was missing the NullableBool.cs include, causing CS0246 on Windows CI builds.

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 8, 2026

@copilot Please fix this build break on Windows:

src\libraries\System.Net.NameResolution\src\System\Net\NameResolutionPal.Windows.cs(18,33): error CS0246: (NETCORE_ENGINEERING_...

Fixed in 54facbc. The System.Net.NameResolution.Pal.Tests.csproj test project directly compiles NameResolutionPal.Windows.cs in its Windows ItemGroup but was missing the NullableBool.cs include — added it alongside the other Windows sources.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@jkotas jkotas requested a review from stephentoub March 8, 2026 21:27
Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice refactoring!

…Protocol.cs

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! TBH I have not expected this pattern to be so common.

@jkotas jkotas merged commit 6b6bfe3 into main Mar 9, 2026
147 of 150 checks passed
@jkotas jkotas deleted the copilot/move-nullablebool-under-common branch March 9, 2026 17:24
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.

4 participants