From a5307f222f4f7d5d90bd8b0cb638e152cf55ebfa Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 5 Feb 2026 13:35:09 -0500 Subject: [PATCH 1/2] Add the final C# 11 errors Fixes #49602 Add the final 2 message for static abstract interfaces. In addition, do a general edit pass for that file. Remove two duplicates in two different files. The additional errors that were removed from the "sorry" file aren't generated by roslyn anymore. Most were from `!!`, which was removed while in preview. Others have been subsumed by newer, better error messages. --- .../overloaded-operator-errors.md | 13 ++---- .../static-abstract-interfaces.md | 46 +++++++++++++++---- docs/csharp/language-reference/toc.yml | 6 +-- ...n-t-have-specifics-on-this-csharp-error.md | 6 --- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/overloaded-operator-errors.md b/docs/csharp/language-reference/compiler-messages/overloaded-operator-errors.md index 3815b8d86829f..21fe0f63d72ed 100644 --- a/docs/csharp/language-reference/compiler-messages/overloaded-operator-errors.md +++ b/docs/csharp/language-reference/compiler-messages/overloaded-operator-errors.md @@ -27,8 +27,6 @@ f1_keywords: - "CS0715" - "CS1037" - "CS1553" - - "CS8930" - - "CS8931" - "CS9023" - "CS9024" - "CS9025" @@ -66,8 +64,6 @@ helpviewer_keywords: - "CS0715" - "CS1037" - "CS1553" - - "CS8930" - - "CS8931" - "CS9023" - "CS9024" - "CS9025" @@ -115,8 +111,8 @@ That's by design. The text closely matches the text of the compiler error / warn - [**CS0715**](#operator-declaration-requirements): *Static classes cannot contain user-defined operators* - [**CS1037**](#operator-declaration-requirements): *Overloadable operator expected* - [**CS1553**](#operator-declaration-requirements): *Declaration is not valid; use 'modifier operator \ (...' instead* -- [**CS8930**](#operator-declaration-requirements): *Explicit implementation of a user-defined operator must be static.* -- [**CS8931**](#operator-declaration-requirements): *Explicit implementation must be declared public to implement interface member in type.* +- [**CS8930**](static-abstract-interfaces.md#errors-in-type-implementing-interface-declaration): *Explicit implementation of a user-defined operator must be declared static* +- [**CS8931**](static-abstract-interfaces.md#errors-in-interface-declaration): *User-defined conversion in an interface must convert to or from a type parameter on the enclosing type constrained to the enclosing type* - [**CS9023**](#checked-operators): *Operator cannot be made checked.* - [**CS9024**](#checked-operators): *Operator cannot be made unchecked.* - [**CS9025**](#checked-operators): *Operator requires a matching non-checked version to also be declared.* @@ -207,8 +203,6 @@ public class C6 - **CS0715**: *Static classes can't contain user-defined operators.* - **CS1037**: *Overloadable operator expected.* - **CS1553**: *Declaration isn't valid; use 'modifier operator \ (...' instead.* -- **CS8930**: *Explicit implementation of a user-defined operator must be static.* -- **CS8931**: *Explicit implementation must be declared public to implement interface member in type.* - **CS9308**: *User-defined operator must be declared public.* To declare operators correctly, follow these requirements for modifiers and containing types. For more information, see [Operator overloading](../operators/operator-overloading.md) and [User-defined conversion operators](../operators/user-defined-conversion-operators.md). @@ -217,7 +211,8 @@ To declare operators correctly, follow these requirements for modifiers and cont - Don't declare operators in static classes (**CS0715**). Use regular classes or structs. - Use valid, overloadable operator symbols (**CS1037**). - Follow the correct syntax for conversion operators: `public static implicit/explicit operator ( parameter)` (**CS1553**). -- Ensure explicit interface implementations of operators are `static` (**CS8930**) and `public` (**CS8931**). + +For errors related to explicit interface implementations of operators in static abstract interfaces, see [Static abstract and virtual interface member errors](static-abstract-interfaces.md#errors-in-type-implementing-interface-declaration). The following example demonstrates declaration errors: diff --git a/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md b/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md index 114aa243c2dfe..35fc2ba961493 100644 --- a/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md +++ b/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md @@ -13,6 +13,8 @@ f1_keywords: - "CS9030" - "CS8931" - "CS8932" + - "CS9044" + - "CS9046" helpviewer_keywords: - "CS8920" - "CS8921" @@ -25,7 +27,9 @@ helpviewer_keywords: - "CS8930" - "CS8931" - "CS8932" -ms.date: 11/29/2023 + - "CS9044" + - "CS9046" +ms.date: 02/06/2026 --- # Static abstract and virtual interface member errors and warnings @@ -45,6 +49,8 @@ That's be design. The text closely matches the text of the compiler error / warn - [**CS8930**](#errors-in-type-implementing-interface-declaration): *Explicit implementation of a user-defined operator must be declared static* - [**CS8931**](#errors-in-interface-declaration): *User-defined conversion in an interface must convert to or from a type parameter on the enclosing type constrained to the enclosing type* - [**CS8932**](#errors-in-type-implementing-interface-declaration): *'UnmanagedCallersOnly' method cannot implement interface member in type* +- [**CS9044**](#errors-in-type-implementing-interface-declaration): *Type does not implement interface member. Method cannot implicitly implement an inaccessible member.* +- [**CS9046**](#errors-in-interface-declaration): *One of the parameters of an equality, or inequality operator declared in an interface must be a type parameter constrained to the interface* These errors occur in three places in your code: @@ -54,7 +60,7 @@ These errors occur in three places in your code: ## Errors in interface declaration -The following errors might occur when you declare an interface with `static abstract` or `static virtual` members: +You might encounter the following errors when you declare an interface with `static abstract` or `static virtual` members: - **CS8921**: *The parameter of a unary operator must be the containing type, or its type parameter constrained to it.* - **CS8922**: *The parameter type for `++` or `--` operator must be the containing type, or its type parameter constrained to it.* @@ -62,28 +68,50 @@ The following errors might occur when you declare an interface with `static abst - **CS8924**: *One of the parameters of a binary operator must be the containing type, or its type parameter constrained to it.* - **CS8925**: *The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it* - **CS8931**: *User-defined conversion in an interface must convert to or from a type parameter on the enclosing type constrained to the enclosing type* +- **CS9046**: *One of the parameters of an equality, or inequality operator declared in interface must be a type parameter constrained to the interface* -All these rules are extensions of the rules for declaring overloaded operators. The distinction is that the parameter can be either the interface type, or the interface's type parameter if that type parameter is constrained to implement the interface for its type. For binary operators, only one parameter must satisfy this rule. +For unary operators declared in an interface, ensure the parameter is either the interface type itself or a type parameter `T` where `T` is constrained to implement the interface (**CS8921**). This constraint ensures the operator can only be applied to types that implement the interface, enabling the compiler to resolve the correct implementation at compile time. -For example, `INumber` can declare an `T operator++(T)` because `T` is constrained to implement `INumber`. +For increment (`++`) and decrement (`--`) operators, verify that the parameter follows the same rules as other unary operators (**CS8922**). Additionally, the return type must either match the parameter type, derive from it, or be the interface's type parameter constrained to the interface (**CS8923**). These rules ensure that increment and decrement operations return a compatible type that can be assigned back to the original variable. -To fix these errors, ensure that the parameters of any operators defined in the interface obey these rules. You can learn more in the language reference article on [static abstract members in interfaces](../keywords/interface.md#static-abstract-and-virtual-members) or in the tutorial to [explore static abstract interface members](../../advanced-topics/interface-implementation/static-virtual-interface-members.md). +For binary operators, at least one of the two parameters must be the containing interface type or a type parameter constrained to implement the interface (**CS8924**). This requirement allows the other parameter to be any type, enabling operators like `T operator +(T left, int right)` in generic math scenarios. + +For shift operators (`<<` and `>>`), the first operand must be the containing type or its constrained type parameter (**CS8925**). The second operand follows standard shift operator rules and is typically `int`. + +For user-defined conversion operators, the conversion must involve a type parameter that is constrained to the enclosing interface type (**CS8931**). You can't define conversions between arbitrary types in an interface; the conversion must relate to types that implement the interface. + +For equality (`==`) and inequality (`!=`) operators, at least one parameter must be a type parameter constrained to the interface, not just the interface type itself (**CS9046**). This stricter requirement for equality operators ensures proper type safety when comparing instances through the interface. + +For more information about the rules for operator declarations in interfaces, see [static abstract members in interfaces](../keywords/interface.md#static-abstract-and-virtual-members). For a practical guide to implementing these patterns, see [Explore static abstract interface members](../../advanced-topics/interface-implementation/static-virtual-interface-members.md). ## Errors in type implementing interface declaration -The following errors might occur when you define a type that implements an interface with `static abstract` or `static virtual` methods: +You might encounter the following errors when you define a type that implements an interface with `static abstract` or `static virtual` methods: - **CS8928**: *Type does not implement static interface member. The method cannot implement the interface member because it is not static.* - **CS8930**: *Explicit implementation of a user-defined operator must be declared static* - **CS8932**: *'UnmanagedCallersOnly' method cannot implement interface member in type* +- **CS9044**: *Type does not implement interface member. Method cannot implicitly implement an inaccessible member.* + +When you implement a static abstract or static virtual interface member, declare the implementing method by using the `static` modifier (**CS8928**). Unlike instance interface members that are implemented by instance methods, static abstract members require static implementations because the runtime invokes them on the type itself, not on an instance. -These errors all indicate that you declared the method that implements a static abstract interface member incorrectly. These members must be declared `static`; they can't be instance members. Methods that implement interface members can't have the attribute applied to them. +For explicit implementations of user-defined operators from an interface, include the `static` modifier in the implementation (**CS8930**). Explicit interface implementations of operators follow the same static requirement as implicit implementations. + +Remove the attribute from any method that implements an interface member (**CS8932**). Methods marked by using this attribute can only be called from unmanaged code and can't participate in interface implementation because the runtime needs to call them through the interface dispatch mechanism. + +If the implementing method has more restrictive accessibility than the interface member (for example, a `private` or `internal` method implementing a `public` interface member), use explicit interface implementation syntax instead of implicit implementation (**CS9044**). Implicit implementation requires the implementing member to be at least as accessible as the interface member it implements. + +For more information about implementing interface members, see [Interfaces](../../fundamentals/types/interfaces.md) and [explicit interface implementation](../../programming-guide/interfaces/explicit-interface-implementation.md). ## Errors calling static abstract interface members -The following errors might occur when you attempt to call a member defined as a `static abstract` or `static virtual` member of an interface: +You might see the following errors when you try to call a member defined as a `static abstract` or `static virtual` member of an interface: - **CS8920**: *The interface cannot be used as type argument. Static member does not have a most specific implementation in the interface.* - **CS8926**: *A static virtual or abstract interface member can be accessed only on a type parameter.* -Calls to interface members declared as `static abstract` or `static virtual` must be resolved to at compile-time. They must resolve to a static member defined in a type that implements that interface. That means you must access those members using either a concrete type that implements the interface, or a type parameter that is constrained to implement the interface. To fix these errors, change the type used to access the static member. +When you use an interface with static abstract members as a type argument, make sure that all static abstract members have a most specific implementation available (**CS8920**). You see this error when the compiler can't determine which implementation to use, typically because multiple interface hierarchies provide conflicting default implementations or no implementation exists. + +Access static abstract or static virtual interface members through a type parameter that is constrained to implement the interface, rather than through the interface type directly (**CS8926**). For example, use `T.MemberName` where `T` is constrained by `where T : IMyInterface`, rather than `IMyInterface.MemberName`. The compiler needs a concrete type to resolve which implementation to call, and a constrained type parameter provides that concrete type at compile time through generic specialization. + +For more information about accessing static abstract members, see [static abstract members in interfaces](../keywords/interface.md#static-abstract-and-virtual-members). diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index 49e5c8630503a..c62c7a2ae55cf 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -509,8 +509,8 @@ items: operator, overloaded operator, user defined operator, CS0056, CS0057, CS0215, CS0216, CS0217, CS0218, CS0448, CS0552, CS0553, CS0554, CS0555, CS0556, CS0557, CS0558, CS0559, CS0562, CS0563, CS0564, CS0567, CS0590, - CS0660, CS0661, CS0715, CS1037, CS1553, CS1554, CS8930, CS8931, CS9023, CS9024, - CS9025, CS9027, CS9308, CS9310, CS9311, CS9312, CS9313, CS9340, CS9341, CS9342 + CS0660, CS0661, CS0715, CS1037, CS1553, CS1554, CS9023, CS9024, CS9025, CS9027, + CS9308, CS9310, CS9311, CS9312, CS9313, CS9340, CS9341, CS9342 - name: Parameter / argument mismatch href: ./compiler-messages/parameter-argument-mismatch.md displayName: > @@ -666,7 +666,7 @@ items: href: ./compiler-messages/static-abstract-interfaces.md displayName: > CS8920, CS8921, CS8922, CS8923, CS8924, CS8925, CS8926, CS8928, CS8930, CS8931, - CS8932 + CS8932, CS9044, CS9046 - name: Thread synchronization href: ./compiler-messages/lock-semantics.md displayName: CS0185, CS9216, CS9217 diff --git a/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md b/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md index 2dbb319b7e2c7..4f00471374be6 100644 --- a/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md +++ b/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md @@ -446,12 +446,6 @@ f1_keywords: - "CS8973" - "CS8974" - "CS8976" - # C# 11 errors start here - - "CS8984" - - "CS8989" - - "CS9044" - - "CS9046" - - "CS9064" # Coming in C# 15 - "CS9343" - "CS9344" From f5a2951d2d4756c338a44f7e2a13a1887b79aef1 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 6 Feb 2026 09:03:18 -0500 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com> --- .../compiler-messages/static-abstract-interfaces.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md b/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md index 35fc2ba961493..4a29d942e91be 100644 --- a/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md +++ b/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md @@ -50,7 +50,7 @@ That's be design. The text closely matches the text of the compiler error / warn - [**CS8931**](#errors-in-interface-declaration): *User-defined conversion in an interface must convert to or from a type parameter on the enclosing type constrained to the enclosing type* - [**CS8932**](#errors-in-type-implementing-interface-declaration): *'UnmanagedCallersOnly' method cannot implement interface member in type* - [**CS9044**](#errors-in-type-implementing-interface-declaration): *Type does not implement interface member. Method cannot implicitly implement an inaccessible member.* -- [**CS9046**](#errors-in-interface-declaration): *One of the parameters of an equality, or inequality operator declared in an interface must be a type parameter constrained to the interface* +- [**CS9046**](#errors-in-interface-declaration): *One of the parameters of an equality or inequality operator declared in an interface must be a type parameter constrained to the interface* These errors occur in three places in your code: @@ -68,7 +68,7 @@ You might encounter the following errors when you declare an interface with `sta - **CS8924**: *One of the parameters of a binary operator must be the containing type, or its type parameter constrained to it.* - **CS8925**: *The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it* - **CS8931**: *User-defined conversion in an interface must convert to or from a type parameter on the enclosing type constrained to the enclosing type* -- **CS9046**: *One of the parameters of an equality, or inequality operator declared in interface must be a type parameter constrained to the interface* +- **CS9046**: *One of the parameters of an equality or inequality operator declared in interface must be a type parameter constrained to the interface* For unary operators declared in an interface, ensure the parameter is either the interface type itself or a type parameter `T` where `T` is constrained to implement the interface (**CS8921**). This constraint ensures the operator can only be applied to types that implement the interface, enabling the compiler to resolve the correct implementation at compile time.