Page: https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/union
1. "a pattern like pet is Pet typically doesn't match"
The note under Union pattern matching says this pattern typically doesn't match, because Pet is tested against the union's contents. On .NET 11 RC 1 the result is the opposite: it always matches, including when Value is null. The compiler also flags it as a constant result:
Pet real = new Dog("Rex");
Pet none = default;
Console.WriteLine(real is Pet); // True
Console.WriteLine(none is Pet); // True
// warning CS0183: The given expression is always of the provided ('Pet') type
This matches the feature specification, which says the union instance is tested first and then its value. The note should say that pet is Pet is always true, and so is useless as a has-a-value test. pet.Value is not null or pet is not null are the correct checks.
2. The Union exhaustiveness null-handling sample
The text says that when Value's null state is "maybe null", you must also handle null to avoid a warning. It then says this can happen when the union expression is the default value, "as shown in the preceding sample" (Pet pet = default;).
But in that sample (and whenever no case type is nullable), the compiler gives no warning if the null arm is removed. This is consistent with the Nullability rules further down the same page: Value defaults to "not null" when no case type is nullable. The compiler team confirmed that rule as the current design in dotnet/roslyn#85054. Without the arm, the switch compiles clean and then throws at runtime:
Pet pet = default;
var name = pet switch { Dog d => d.Name, Cat c => c.Name, Bird b => b.Name }; // no warning
// System.Runtime.CompilerServices.SwitchExpressionException at runtime
The same holds for an array slot (new Pet[1][0]), an unassigned field, and a parameter. CS8655 appears only when a case type is nullable, or after the code has already tested is null.
Suggested wording: say that the null arm is needed for correctness whenever a union can be default (fields, array elements, default(T)), and that the compiler will not ask for it unless a case type is nullable. The current text implies a safety net that doesn't exist.
Environment: .NET SDK 11.0.100-rc.1.26425.128, <Nullable>enable</Nullable>, Windows 11 x64.
Associated WorkItem - 632609
Page: https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/union
1. "a pattern like
pet is Pettypically doesn't match"The note under Union pattern matching says this pattern typically doesn't match, because
Petis tested against the union's contents. On .NET 11 RC 1 the result is the opposite: it always matches, including whenValueisnull. The compiler also flags it as a constant result:This matches the feature specification, which says the union instance is tested first and then its value. The note should say that
pet is Petis always true, and so is useless as a has-a-value test.pet.Value is not nullorpet is not nullare the correct checks.2. The Union exhaustiveness null-handling sample
The text says that when
Value's null state is "maybe null", you must also handlenullto avoid a warning. It then says this can happen when the union expression is the default value, "as shown in the preceding sample" (Pet pet = default;).But in that sample (and whenever no case type is nullable), the compiler gives no warning if the
nullarm is removed. This is consistent with the Nullability rules further down the same page:Valuedefaults to "not null" when no case type is nullable. The compiler team confirmed that rule as the current design in dotnet/roslyn#85054. Without the arm, the switch compiles clean and then throws at runtime:The same holds for an array slot (
new Pet[1][0]), an unassigned field, and a parameter.CS8655appears only when a case type is nullable, or after the code has already testedis null.Suggested wording: say that the
nullarm is needed for correctness whenever a union can bedefault(fields, array elements,default(T)), and that the compiler will not ask for it unless a case type is nullable. The current text implies a safety net that doesn't exist.Environment: .NET SDK
11.0.100-rc.1.26425.128,<Nullable>enable</Nullable>, Windows 11 x64.Associated WorkItem - 632609