@@ -52,7 +52,7 @@ protected SourceUserDefinedOperatorSymbolBase(
5252
5353 this . CheckUnsafeModifier ( declarationModifiers , diagnostics ) ;
5454
55- bool isIncrementDecrement = IsIncrementDecrementDeclaration ( syntax ) ;
55+ ( bool isIncrementDecrement , bool isCompoundAssignment ) = IsAssignmentOperatorDeclaration ( syntax ) ;
5656
5757 if ( isIncrementDecrement )
5858 {
@@ -66,6 +66,8 @@ protected SourceUserDefinedOperatorSymbolBase(
6666 }
6767 else
6868 {
69+ // PROTOTYPE: Cover explicit implementation scenarios
70+
6971 Binder . CheckFeatureAvailability ( syntax , MessageID . IDS_FeatureUserDefinedCompoundAssignmentOperators , diagnostics , ( ( OperatorDeclarationSyntax ) syntax ) . OperatorToken . GetLocation ( ) ) ;
7072
7173 if ( parameterCount is not ( 0 or 2 ) )
@@ -74,6 +76,11 @@ protected SourceUserDefinedOperatorSymbolBase(
7476 }
7577 }
7678 }
79+ else if ( isCompoundAssignment )
80+ {
81+ // PROTOTYPE: Cover explicit implementation scenarios
82+ Binder . CheckFeatureAvailability ( syntax , MessageID . IDS_FeatureUserDefinedCompoundAssignmentOperators , diagnostics , ( ( OperatorDeclarationSyntax ) syntax ) . OperatorToken . GetLocation ( ) ) ;
83+ }
7784
7885 if ( this . ContainingType . IsInterface &&
7986 ! ( IsAbstract || IsVirtual ) && ! IsExplicitInterfaceImplementation &&
@@ -97,12 +104,12 @@ protected SourceUserDefinedOperatorSymbolBase(
97104 // SPEC: static modifier
98105 if ( this . IsExplicitInterfaceImplementation )
99106 {
100- if ( ! this . IsStatic && ! isIncrementDecrement )
107+ if ( ! this . IsStatic && ! isIncrementDecrement && ! isCompoundAssignment )
101108 {
102109 diagnostics . Add ( ErrorCode . ERR_ExplicitImplementationOfOperatorsMustBeStatic , this . GetFirstLocation ( ) , this ) ;
103110 }
104111 }
105- else if ( isIncrementDecrement && ! this . IsStatic )
112+ else if ( ( isIncrementDecrement || isCompoundAssignment ) && ! this . IsStatic )
106113 {
107114 if ( this . DeclaredAccessibility != Accessibility . Public )
108115 {
@@ -176,9 +183,21 @@ protected SourceUserDefinedOperatorSymbolBase(
176183 ModifierUtils . CheckAccessibility ( this . DeclarationModifiers , this , isExplicitInterfaceImplementation : false , diagnostics , location ) ;
177184 }
178185
179- private static bool IsIncrementDecrementDeclaration ( CSharpSyntaxNode syntax )
186+ private static ( bool isIncrementDecrement , bool isCompoundAssignment ) IsAssignmentOperatorDeclaration ( CSharpSyntaxNode syntax )
180187 {
181- return syntax is OperatorDeclarationSyntax { OperatorToken . RawKind : ( int ) SyntaxKind . PlusPlusToken or ( int ) SyntaxKind . MinusMinusToken } ;
188+ if ( syntax is OperatorDeclarationSyntax operatorDeclaration )
189+ {
190+ if ( operatorDeclaration . OperatorToken . Kind ( ) is SyntaxKind . PlusPlusToken or SyntaxKind . MinusMinusToken )
191+ {
192+ return ( true , false ) ;
193+ }
194+ else if ( SyntaxFacts . IsOverloadableCompoundAssignmentOperator ( operatorDeclaration . OperatorToken . Kind ( ) ) )
195+ {
196+ return ( false , true ) ;
197+ }
198+ }
199+
200+ return ( false , false ) ;
182201 }
183202
184203 protected static DeclarationModifiers MakeDeclarationModifiers ( MethodKind methodKind , SourceMemberContainerTypeSymbol containingType , BaseMethodDeclarationSyntax syntax , Location location , BindingDiagnosticBag diagnostics )
@@ -191,6 +210,8 @@ protected static DeclarationModifiers MakeDeclarationModifiers(MethodKind method
191210 DeclarationModifiers . Extern |
192211 DeclarationModifiers . Unsafe ;
193212
213+ ( bool isIncrementDecrement , bool isCompoundAssignment ) = IsAssignmentOperatorDeclaration ( syntax ) ;
214+
194215 if ( ! isExplicitInterfaceImplementation )
195216 {
196217 allowedModifiers |= DeclarationModifiers . AccessibilityMask ;
@@ -205,7 +226,7 @@ protected static DeclarationModifiers MakeDeclarationModifiers(MethodKind method
205226 }
206227 }
207228
208- if ( IsIncrementDecrementDeclaration ( syntax ) )
229+ if ( isIncrementDecrement || isCompoundAssignment )
209230 {
210231 if ( inInterface )
211232 {
@@ -228,6 +249,11 @@ protected static DeclarationModifiers MakeDeclarationModifiers(MethodKind method
228249 allowedModifiers |= DeclarationModifiers . Abstract ;
229250 }
230251
252+ if ( isCompoundAssignment )
253+ {
254+ allowedModifiers &= ~ DeclarationModifiers . Static ;
255+ }
256+
231257 var result = ModifierUtils . MakeAndCheckNonTypeMemberModifiers (
232258 isOrdinaryMethod : false , isForInterfaceMember : inInterface ,
233259 syntax . Modifiers , defaultAccess , allowedModifiers , location , diagnostics , modifierErrors : out _ , hasExplicitAccessModifier : out _ ) ;
@@ -272,7 +298,7 @@ protected static DeclarationModifiers MakeDeclarationModifiers(MethodKind method
272298 Binder . CheckFeatureAvailability ( location . SourceTree , MessageID . IDS_DefaultInterfaceImplementation , diagnostics , location ) ;
273299 }
274300 }
275- else if ( ! isExplicitInterfaceImplementation && IsIncrementDecrementDeclaration ( syntax ) )
301+ else if ( ! isExplicitInterfaceImplementation && ( isIncrementDecrement || isCompoundAssignment ) )
276302 {
277303 if ( syntax . HasAnyBody ( ) )
278304 {
@@ -504,6 +530,29 @@ private void CheckOperatorSignatures(BindingDiagnosticBag diagnostics)
504530
505531 break ;
506532
533+ case WellKnownMemberNames . CheckedAdditionAssignmentOperatorName :
534+ case WellKnownMemberNames . AdditionAssignmentOperatorName :
535+ case WellKnownMemberNames . CheckedDivisionAssignmentOperatorName :
536+ case WellKnownMemberNames . DivisionAssignmentOperatorName :
537+ case WellKnownMemberNames . CheckedMultiplicationAssignmentOperatorName :
538+ case WellKnownMemberNames . MultiplicationAssignmentOperatorName :
539+ case WellKnownMemberNames . CheckedSubtractionAssignmentOperatorName :
540+ case WellKnownMemberNames . SubtractionAssignmentOperatorName :
541+ case WellKnownMemberNames . ModulusAssignmentOperatorName :
542+ case WellKnownMemberNames . BitwiseAndAssignmentOperatorName :
543+ case WellKnownMemberNames . BitwiseOrAssignmentOperatorName :
544+ case WellKnownMemberNames . ExclusiveOrAssignmentOperatorName :
545+ case WellKnownMemberNames . LeftShiftAssignmentOperatorName :
546+ case WellKnownMemberNames . RightShiftAssignmentOperatorName :
547+ case WellKnownMemberNames . UnsignedRightShiftAssignmentOperatorName :
548+ if ( ! this . ReturnsVoid )
549+ {
550+ diagnostics . Add ( ErrorCode . ERR_OperatorMustReturnVoid , this . GetFirstLocation ( ) ) ;
551+ }
552+
553+ // PROTOTYPE: Test/handle scenarios with ref modifiers on the parameter
554+ break ;
555+
507556 default :
508557 CheckBinarySignature ( diagnostics ) ;
509558 break ;
@@ -530,6 +579,21 @@ private bool DoesOperatorHaveCorrectArity(string name, int parameterCount)
530579 case WellKnownMemberNames . ImplicitConversionName :
531580 case WellKnownMemberNames . ExplicitConversionName :
532581 case WellKnownMemberNames . CheckedExplicitConversionName :
582+ case WellKnownMemberNames . CheckedAdditionAssignmentOperatorName :
583+ case WellKnownMemberNames . AdditionAssignmentOperatorName :
584+ case WellKnownMemberNames . CheckedDivisionAssignmentOperatorName :
585+ case WellKnownMemberNames . DivisionAssignmentOperatorName :
586+ case WellKnownMemberNames . CheckedMultiplicationAssignmentOperatorName :
587+ case WellKnownMemberNames . MultiplicationAssignmentOperatorName :
588+ case WellKnownMemberNames . CheckedSubtractionAssignmentOperatorName :
589+ case WellKnownMemberNames . SubtractionAssignmentOperatorName :
590+ case WellKnownMemberNames . ModulusAssignmentOperatorName :
591+ case WellKnownMemberNames . BitwiseAndAssignmentOperatorName :
592+ case WellKnownMemberNames . BitwiseOrAssignmentOperatorName :
593+ case WellKnownMemberNames . ExclusiveOrAssignmentOperatorName :
594+ case WellKnownMemberNames . LeftShiftAssignmentOperatorName :
595+ case WellKnownMemberNames . RightShiftAssignmentOperatorName :
596+ case WellKnownMemberNames . UnsignedRightShiftAssignmentOperatorName :
533597 return parameterCount == 1 ;
534598 default :
535599 return parameterCount == 2 ;
0 commit comments