Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ f1_keywords:
- "CS9337"
- "CS9344"
- "CS9345"
- "CS9372"
helpviewer_keywords:
- "CS8116"
- "CS8117"
Expand Down Expand Up @@ -90,11 +91,13 @@ helpviewer_keywords:
- "CS9013"
- "CS9060"
- "CS9134"
- "CS9135"
- "CS9336"
- "CS9337"
- "CS9344"
- "CS9345"
ms.date: 03/16/2026
- "CS9372"
Comment thread
BillWagner marked this conversation as resolved.
ms.date: 06/26/2026
ai-usage: ai-assisted
---
# Resolve errors and warnings in pattern matching expressions
Expand Down Expand Up @@ -147,6 +150,7 @@ This article covers the following compiler errors and warnings:
- [**CS9337**](#pattern-completeness-and-redundancy): *The pattern is too complex to analyze for redundancy.*
- [**CS9344**](#switch-expression-syntax-errors): *The '==' operator is not supported in a pattern.*
- [**CS9345**](#switch-expression-syntax-errors): *The '!=' operator is not supported in a pattern. Use 'not' to represent a negated pattern.*
- [**CS9372**](#type-pattern-errors): *An expression of type cannot be handled by this pattern, see additional errors at this location.*

## Switch expression syntax errors

Expand Down Expand Up @@ -194,11 +198,11 @@ For more information about the correct syntax, see [Switch expression](../operat
- **CS9336**: *The pattern is redundant.*
- **CS9337**: *The pattern is too complex to analyze for redundancy.*

Reorder or remove unreachable case labels in `switch` statements (**CS8120**). A `case` label is unreachable when a previous case already handles all values that the later case would match. This occurs when a more general pattern appears before a more specific one, or when the pattern is impossible to match for the input type.
Reorder or remove unreachable case labels in `switch` statements (**CS8120**). A `case` label is unreachable when a previous case already handles all values that the later case would match. This situation occurs when a more general pattern appears before a more specific one, or when the pattern is impossible to match for the input type.

Add switch arms that handle all possible input values to create exhaustive switch expressions (**CS8509**, **CS8524**, **CS8846**). Switch expressions must cover every possible value of the input type. Otherwise, the compiler can't guarantee that the expression produces a result for all inputs. The compiler warns separately for unnamed enum values (**CS8524**) and for cases where a `when` clause might match an otherwise-unhandled value (**CS8846**). Use the discard pattern (`_`) as a final catch-all arm to match any remaining values that you don't need to handle explicitly.

Reorder or remove unreachable switch expression arms (**CS8510**). Like **CS8120** for `switch` statements, this error indicates that a switch expression arm is unreachable because a previous arm already handles all values that the later arm would match.
Reorder or remove unreachable switch expression arms (**CS8510**). Like **CS8120** for `switch` statements, this error indicates that a switch expression arm is unreachable because a previous arm already handles all values that the later arm would match.

Review patterns that can never match or always match the input (**CS8518**, **CS8519**, **CS8520**, **CS8793**, **CS8794**). These diagnostics indicate that the compiler can determine at compile time whether a pattern always or never matches. An always-matching pattern is redundant, and a never-matching pattern is dead code. Both can indicate logic errors.

Expand All @@ -219,6 +223,7 @@ For more information about exhaustiveness requirements and pattern optimization,
- **CS8782**: *Relational patterns may not be used for a floating-point NaN.*
- **CS8978**: *'...' cannot be made nullable.*
- **CS9060**: *Cannot use a numeric constant or relational pattern on '...' because it inherits from or extends 'INumberBase<T>'. Consider using a type pattern to narrow to a specific numeric type.*
- **CS9372**: *An expression of type cannot be handled by this pattern, see additional errors at this location.*

Use the underlying type instead of the nullable type in patterns (**CS8116**). You can't use a nullable value type like `int?` directly in a type pattern. Instead, use the underlying type (`int`), and the pattern matches both nullable and non-nullable values.

Expand All @@ -240,6 +245,8 @@ Use the underlying type directly in patterns when working with types that can't

Use type patterns to narrow generic numeric types to specific numeric types before applying numeric constants or relational patterns (**CS9060**). You can't match generic numeric types that implement `INumberBase<T>` directly by using numeric constants or relational patterns. The compiler can't determine which specific numeric type is being matched. You must first narrow the value to a concrete numeric type like `int`, `double`, or `decimal`.

Use the correct pattern form when matching against a [union](../builtin-types/union.md) value (**CS9372**). Patterns on a union type apply to the union's `Value` property, not the union value itself. If the compiler reports that a pattern can't handle the expression, check that you're matching against the case types listed in the union declaration. Review the additional errors at the same location for details about which specific pattern is invalid.

For more information about type patterns, see [Nullable value types](../builtin-types/nullable-value-types.md), [Patterns](../operators/patterns.md), and [Generic math](../../../standard/generics/math.md).

## List pattern errors
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,63 @@
---
title: "Resolve errors and warnings related to union type declarations"
description: "This article helps you diagnose and correct compiler errors and warnings related to union type declarations."
title: "Resolve errors and warnings related to union type and closed hierarchy declarations"
description: "This article helps you diagnose and correct compiler errors and warnings related to union type and closed hierarchy declarations."
f1_keywords:
- "CS9370"
- "CS9371"
- "CS9372"
- "CS9373"
- "CS9374"
- "CS9375"
- "CS9380"
- "CS9381"
- "CS9382"
- "CS9383"
- "CS9384"
- "CS9385"
- "CS9386"
- "CS9387"
helpviewer_keywords:
- "CS9370"
- "CS9371"
- "CS9372"
- "CS9373"
- "CS9374"
- "CS9375"
ms.date: 04/03/2026
- "CS9380"
- "CS9381"
- "CS9382"
- "CS9383"
- "CS9384"
- "CS9385"
- "CS9386"
- "CS9387"
ms.date: 06/26/2026
ai-usage: ai-assisted
---
# Resolve errors and warnings for union type declarations
# Resolve errors and warnings for union type and closed hierarchy declarations

The C# compiler generates errors when you misuse [union types](../builtin-types/union.md). Union types represent a value that can be one of several *case types*, with implicit conversions and exhaustive pattern matching. These diagnostics help you follow the rules for declaring and using union types.
The C# compiler generates errors when you misuse [union types](../builtin-types/union.md) or closed type hierarchies. Union types represent a value that can be one of several *case types*, with implicit conversions and exhaustive pattern matching. Closed hierarchies restrict which types can derive from a base type. These diagnostics help you follow the rules for declaring and using union types and closed hierarchies.
Comment thread
BillWagner marked this conversation as resolved.
Outdated

<!-- The text in this list generates issues for Acrolinx, because they don't use contractions.
That's by design. The text closely matches the text of the compiler error / warning for SEO purposes.
-->

- [**CS9370**](#union-declaration-requirements): *A union declaration must specify at least one case type.*
- [**CS9371**](#union-declaration-requirements): *Cannot convert type to 'object' via an implicit reference or boxing conversion.*
- [**CS9372**](#pattern-matching-limitations): *An expression of type cannot be handled by this pattern, see additional errors at this location.*
- [**CS9373**](#union-member-restrictions): *Instance fields, auto-properties, or field-like events are not permitted in a 'union' declaration.*
- [**CS9371**](#union-declaration-requirements): *Cannot convert type 'type' to 'object' via an implicit reference or boxing conversion.*
- [**CS9373**](#union-member-restrictions): *Instance fields, auto-properties or field-like events are not permitted in a 'union' declaration.*
- [**CS9374**](#union-member-restrictions): *Explicitly declared public constructors with a single parameter are not permitted in a 'union' declaration.*
- [**CS9375**](#union-member-restrictions): *A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor.*
- [**CS9380**](#closed-hierarchy-restrictions): *Types and aliases cannot be named 'closed'.*
- [**CS9381**](#closed-hierarchy-restrictions): *'type': a closed type cannot be sealed or static*
- [**CS9382**](#closed-hierarchy-restrictions): *'type': cannot use a closed type 'type' from another assembly as a base type.*
- [**CS9383**](#closed-hierarchy-restrictions): *'type': The type parameter 'parameter' must be referenced in the base type 'type' because the base type is closed.*
- [**CS9384**](#closed-hierarchy-restrictions): *'type': a closed type cannot be marked abstract because it is always implicitly abstract.*
- [**CS9385**](#union-member-provider-requirements): *A union type must have at least one union creation member.*
- [**CS9386**](#union-member-provider-requirements): *A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor.*
- [**CS9387**](#union-member-provider-requirements): *A 'union' declaration cannot use a union member provider interface.*

## Union declaration requirements

- **CS9370**: *A union declaration must specify at least one case type.*
- **CS9371**: *Cannot convert type to 'object' via an implicit reference or boxing conversion.*
- **CS9371**: *Cannot convert type 'type' to 'object' via an implicit reference or boxing conversion.*

A [union declaration](../builtin-types/union.md#union-declarations) specifies a name and a list of case types. These errors enforce the structural requirements of a valid union declaration. For the complete rules, see the [union types feature specification](~/_csharplang/proposals/unions.md).

Expand All @@ -47,7 +68,7 @@ To correct these errors, apply the following changes to your union declaration:

## Union member restrictions

- **CS9373**: *Instance fields, auto-properties, or field-like events are not permitted in a 'union' declaration.*
- **CS9373**: *Instance fields, auto-properties or field-like events are not permitted in a 'union' declaration.*
- **CS9374**: *Explicitly declared public constructors with a single parameter are not permitted in a 'union' declaration.*
- **CS9375**: *A constructor declared in a 'union' declaration must have a 'this' initializer that calls a synthesized constructor or an explicitly declared constructor.*

Expand All @@ -59,10 +80,34 @@ To correct these errors, apply the following changes to your union members:
- Remove or change the accessibility of any explicitly declared public constructor that takes a single parameter (**CS9374**). The compiler generates a public single-parameter constructor for each case type to support implicit union conversions. An explicit constructor with the same shape conflicts with those generated constructors. If you need a single-parameter constructor, make it `internal` or `private`.
- Add a `this` initializer to any explicitly declared constructor so that it chains to a synthesized constructor or another explicitly declared constructor (**CS9375**). The compiler-generated constructors initialize the union's internal storage correctly. Constructors that don't chain through them might leave the union in an invalid state. Use `: this(someValue)` to chain to a generated case-type constructor, or `: this()` to chain to an explicit parameterless constructor you declare.

## Pattern matching limitations
## Union member provider requirements

- **CS9372**: *An expression of type cannot be handled by this pattern, see additional errors at this location.*
- **CS9385**: *A union type must have at least one union creation member.*
- **CS9386**: *A union member provider type must have an instance 'Value' property of type 'object?' or 'object'. The property must have a public get accessor.*
- **CS9387**: *A 'union' declaration cannot use a union member provider interface.*

This error arises when you use an incorrect pattern form with a union type. For the complete rules on union pattern matching, see [union matching](../builtin-types/union.md#union-pattern-matching).
A union member provider is a type that implements the union pattern through an interface rather than the `union` keyword. These errors enforce the structural requirements for types participating in the union member provider pattern. For the complete rules, see the [union types feature specification](~/_csharplang/proposals/unions.md).

To correct this error, use the correct pattern form when matching against a union value (**CS9372**). Patterns on a union apply to the union's `Value` property, not the union value itself. If the compiler reports that a pattern can't handle the expression, check that you're matching against the case types listed in the union declaration. Review the additional errors at the same location for details about which pattern is invalid.
To correct these errors, apply the following changes to your union member provider:

- Add at least one union creation member to the type (**CS9385**). A union type must expose at least one creation member (such as a static factory method or implicit conversion) so that values of the union can be constructed from the case types.
- Add a public instance `Value` property of type `object?` or `object` with a public `get` accessor to the member provider type (**CS9386**). The `Value` property is how the runtime retrieves the stored value from the union. Without it, the union can't expose its contents for pattern matching or direct access.
- Remove the union member provider interface from the `union` declaration (**CS9387**). A `union` declaration synthesizes its own member provider implementation. You can't specify a union member provider interface on a type that uses the `union` keyword directly. Use the member provider interface only on types that implement the union pattern manually.

## Closed hierarchy restrictions

- **CS9380**: *Types and aliases cannot be named 'closed'.*
Comment thread
BillWagner marked this conversation as resolved.
Outdated
- **CS9381**: *'type': a closed type cannot be sealed or static*
- **CS9382**: *'type': cannot use a closed type 'type' from another assembly as a base type.*
- **CS9383**: *'type': The type parameter 'parameter' must be referenced in the base type 'type' because the base type is closed.*
- **CS9384**: *'type': a closed type cannot be marked abstract because it is always implicitly abstract.*

A closed type hierarchy restricts which types can derive from a base type. The compiler enforces these restrictions to ensure that the set of derived types is known and exhaustive. For the complete rules, see the [closed hierarchies feature specification](~/_csharplang/proposals/closed-hierarchies.md).

To correct these errors, apply the following changes to your closed hierarchy declaration:

- Rename any type or alias named `closed`, because `closed` is a reserved keyword in this context (**CS9380**). Choose a different name that doesn't conflict with the keyword.
- Remove the `sealed` or `static` modifier from a closed type (**CS9381**). A closed type is implicitly abstract (it must be derived from), so marking it `sealed` (which prevents derivation) or `static` (which prevents instantiation and derivation) contradicts its purpose.
- Don't derive from a closed type declared in another assembly (**CS9382**). Closed hierarchies must have all their subtypes defined in the same assembly as the base type. This restriction enables the compiler to perform exhaustive pattern matching. Move the derived type into the same assembly as the closed base type, or remove the inheritance relationship.
- Ensure that each type parameter of a generic subtype appears in the base type reference when the base type is closed (**CS9383**). Because a closed hierarchy requires exhaustive knowledge of all subtypes, every type parameter on a subtype must be constrained through the base type. If a type parameter isn't referenced in the base type, the compiler can't enumerate all possible instantiations.
- Remove the `abstract` modifier from a closed type declaration (**CS9384**). A closed type is always implicitly abstract because it serves as a base for a finite set of derived types. Adding `abstract` explicitly is redundant and disallowed to avoid confusion about whether the type has different semantics than other closed types.
13 changes: 7 additions & 6 deletions docs/csharp/language-reference/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -519,11 +519,12 @@ items:
CS8851, CS8857, CS8858, CS8859, CS8860, CS8864, CS8865, CS8866, CS8869, CS8870,
CS8871, CS8872, CS8873, CS8874, CS8875, CS8876, CS8877, CS8879, CS8906, CS8907,
CS8908, CS8913
- name: Union type declarations
- name: Union types and closed hierarchies
href: ./compiler-messages/union-declaration-errors.md
displayName: >
union, union type, case type,
CS9370, CS9371, CS9372, CS9373, CS9374, CS9375
union, union type, case type, closed hierarchy, closed type,
CS9370, CS9371, CS9373, CS9374, CS9375, CS9380, CS9381, CS9382, CS9383, CS9384,
CS9385, CS9386, CS9387
- name: Constructors and module initializers
href: ./compiler-messages/constructor-errors.md
displayName: >
Expand Down Expand Up @@ -657,9 +658,9 @@ items:
displayName: >
CS8116, CS8117, CS8119, CS8120, CS8121, CS8208, CS8502, CS8503, CS8504, CS8505,
CS8506, CS8508, CS8509, CS8510, CS8512, CS8513, CS8515, CS8516, CS8517, CS8518,
CS8519, CS8520, CS8521, CS8522, CS8523, CS8524, CS8525, CS8780, CS8781, CS8782, CS8793,
CS8794, CS8846, CS8918, CS8978, CS8979, CS8980, CS8985, CS9013, CS9060, CS9134,
CS9135, CS9335, CS9336, CS9337, CS9344, CS9345
CS8519, CS8520, CS8521, CS8522, CS8523, CS8524, CS8525, CS8780, CS8781, CS8782,
CS8793, CS8794, CS8846, CS8918, CS8978, CS8979, CS8980, CS8985, CS9013, CS9060,
CS9134, CS9135, CS9336, CS9337, CS9344, CS9345, CS9372
- name: String literal declarations
href: ./compiler-messages/string-literal.md
displayName: >
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,26 +270,8 @@ f1_keywords:
- "CS9357"
- "CS9358"
- "CS9359"
# More unions:
- "CS9369"
- "CS9370"
- "CS9371"
- "CS9372"
- "CS9373"
- "CS9374"
- "CS9375"
# Shebang
- "CS9378"
# More union / closed
- "CS9380"
- "CS9381"
- "CS9382"
- "CS9383"
- "CS9384"
# More unions:
- "CS9385"
- "CS9386"
- "CS9387"
helpviewer_keywords:
- "errors [C#], additional information"
---
Expand Down
Loading