From 6ea702ef4f6ddc28fe49fa48d7c99df73f95bc85 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 30 Aug 2026 07:01:10 -0400 Subject: [PATCH 1/5] add support for partial events and constructors --- standard/classes.md | 68 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 055a5a927..e18246994 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -861,7 +861,7 @@ The *class_body*s `{}`, `{};`, and `;` are equivalent, and the *class_body*s `{ ### 15.2.7 Partial type declarations -The modifier `partial` is used when defining a class, struct, or interface type in multiple parts. The `partial` modifier is a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) and has special meaning in a *class_declaration*, a *struct_declaration*, or an *interface_declaration*. (A partial type may contain partial method declarations ([§15.6.9](classes.md#1569-partial-methods)), partial property declarations (§partial-properties), and partial indexer declarations (§partial-indexers)). +The modifier `partial` is used when defining a class, struct, or interface type in multiple parts. The `partial` modifier is a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) and has special meaning in a *class_declaration*, a *struct_declaration*, or an *interface_declaration*. (A partial type may contain partial method declarations ([§15.6.9](classes.md#1569-partial-methods)), partial property declarations (§partial-properties), partial indexer declarations (§partial-indexers), partial event declarations (§partial-events), and partial instance constructor declarations (§partial-constructors)). Each part of a ***partial type*** declaration shall include a `partial` modifier and shall be declared in the same namespace or containing type as the other parts. The `partial` modifier indicates that additional parts of the type declaration might exist elsewhere, but the existence of such additional parts is not a requirement; it is valid for the only declaration of a type to include the `partial` modifier. It is valid for only one declaration of a partial type to include the base class or implemented interfaces. However, all declarations of a base class or implemented interfaces shall match, including the nullability of any specified type arguments. @@ -4682,8 +4682,8 @@ Events are declared using *event_declaration*s: ```ANTLR event_declaration - : attributes? event_modifier* 'event' type variable_declarators ';' - | attributes? event_modifier* 'event' type member_name + : attributes? event_modifier* 'partial'? 'event' type variable_declarators ';' + | attributes? event_modifier* 'partial'? 'event' type member_name '{' event_accessor_declarations '}' ; @@ -4717,6 +4717,8 @@ remove_accessor_declaration ; ``` +However, a partial event (§partial-events) shall not have an `abstract` modifier. + *unsafe_modifier* ([§24.2](unsafe-code.md#242-unsafe-contexts)) is only available in unsafe code ([§24](unsafe-code.md#24-unsafe-code)). An *event_declaration* may include a set of *attributes* ([§23](attributes.md#23-attributes)) and any one of the permitted kinds of declared accessibility ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `static` ([§15.6.3](classes.md#1563-static-and-instance-methods), [§15.8.4](classes.md#1584-static-and-instance-events)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods), [§15.8.5](classes.md#1585-virtual-sealed-override-and-abstract-accessors)), `override` ([§15.6.5](classes.md#1565-override-methods), [§15.8.5](classes.md#1585-virtual-sealed-override-and-abstract-accessors)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods), [§15.8.5](classes.md#1585-virtual-sealed-override-and-abstract-accessors)) and `extern` ([§15.6.8](classes.md#1568-external-methods)) modifiers. Additionally an *event_declaration* that is contained directly by a *struct_declaration* may include the `readonly` modifier ([§16.6.12](structs.md#16612-methods)). @@ -4957,6 +4959,34 @@ It is a compile-time error for an overriding event declaration to include a `new Except for differences in declaration and invocation syntax, virtual, sealed, override, and abstract accessors behave exactly like virtual, sealed, override and abstract methods. Specifically, the rules described in [§15.6.4](classes.md#1564-virtual-methods), [§15.6.5](classes.md#1565-override-methods), [§15.6.6](classes.md#1566-sealed-methods), and [§15.6.7](classes.md#1567-abstract-methods) apply as if accessors were methods of a corresponding form. Each accessor corresponds to a method with a single value parameter of the event type, a `void` return type, and the same modifiers as the containing event. +### §partial-events Partial events + +When an *event_declaration* includes `partial`, that event is said to be a ***partial event***. Partial events may only be declared as members of partial types ([§15.2.7](classes.md#1527-partial-type-declarations)). + +Partial events may be defined in one part of a type declaration and implemented in another, or be defined and implemented in the same part. + +There are two kinds of partial event declarations: If the *event_accessor_declarations* are omitted and the event has no `extern` modifier, the declaration is said to be a ***defining partial event declaration***. Otherwise, the declaration is said to be an ***implementing partial event declaration***. + +Partial events are useful for allowing one part of a type declaration to customize the behavior of another part, e.g., one that is generated by a tool. + +Across the parts of a type declaration, there shall be only one defining partial event declaration with a given signature, and there shall be only one implementing partial event declaration with a given signature. + +The signature-matching requirements are as follows: + +1. Type and ref-kind differences between partial event declarations result in a compile-time error. +1. Differences in tuple element names within partial event declarations result in a compile-time error. +1. The event declarations shall have the same modifiers, though the modifiers may appear in a different order. However, this does not apply to the `extern` modifier, which may only appear on an implementing partial declaration. +1. All other syntactic differences in the signatures of partial event declarations result in a compile-time warning, with the following exceptions: + - Attribute lists do not need to match. + - Nullable context differences (such as oblivious vs. annotated) do not cause warnings. +1. Nullability differences which do not involve oblivious nullability result in warnings. + +In *event_declaration*, the identifier `partial` is recognized as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) only if it immediately precedes the event’s type. A partial event cannot explicitly implement interface events. + +Only a defining partial event participates in lookup. + +A partial event is not field-like ([§15.8.2]( classes.md#1582-field-like-events)). + ## 15.9 Indexers ### 15.9.1 General @@ -5551,7 +5581,7 @@ An ***instance constructor*** is a member that implements the actions required t ```ANTLR constructor_declaration - : attributes? constructor_modifier* constructor_declarator constructor_body + : attributes? constructor_modifier* 'partial'? constructor_declarator constructor_body ; constructor_modifier @@ -5935,6 +5965,36 @@ A warning shall be issued for primary constructor parameters under the following - For a ref parameter, if the parameter is not read or written to within any instance initializers or base initializer. A *class_declaration* may have a `method:` attribute target, which shall apply to the corresponding primary constructor, if any. If the class has no *delimited_parameter_list*, this attribute shall be ignored and a warning produced. +### §partial-constructors Partial constructors + +When a *constructor_declaration* includes a `partial` modifier, that constructor is said to be a ***partial constructor***. Partial constructors may only be declared as members of partial types ([§15.2.7](classes.md#1527-partial-type-declarations)), and are subject to a number of restrictions. + +Partial constructors may be defined in one part of a type declaration and implemented in another. + +The identifier `partial` is recognized as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) in a constructor declaration only if it appears immediately before the *constructor_declarator*. + +There are two kinds of partial constructor declarations: If the body of the constructor declaration is a semicolon and the event has no `extern` modifier, the declaration is said to be a ***defining partial constructor declaration***. If the body is other than a semicolon, the declaration is said to be an ***implementing partial constructor declaration***. Across the parts of a type declaration, there shall be only one defining partial constructor declaration with a given signature, and there shall be one implementing partial constructor declaration with a given signature. If an implementing partial constructor declaration is given, a corresponding defining partial constructor declaration shall exist, and the declarations shall match as specified in the following: + +1. Type and ref kind differences between partial declarations which are significant to the runtime result in a compile-time error. +2. Differences in tuple element names between partial declarations result in a compile-time error. +3. The declarations shall have the same modifiers, though the modifiers may appear in a different order; however, this does not apply to the `extern` modifier, which may only appear on the implementing declaration. +4. All other syntactic differences in the signatures of partial declarations result in a compile-time warning, with the following exceptions: + - Attribute lists need not match. + - Nullable context differences (such as oblivious vs. annotated) do not cause warnings. + - Default parameter values need not match, but a warning shall be reported when the implementing constructor declaration has default parameter values (because those would be ignored since only the defining declaration participates in lookup). +5. A warning shall occur when parameter names differ across defining and implementing constructor declarations. +6. Nullability differences which do not involve oblivious nullability result in warnings. + +Partial constructors are useful for allowing one part of a type declaration to customize the behavior of another part, e.g., one that is generated by a tool. + +The partial constructor gives rise to a constructor declaration similar to the implementing partial constructor declaration except for the following: + +- The `partial` modifier is not included. + +- The attributes in the resulting constructor declaration are the combined attributes of the defining and the implementing partial constructor declarations in unspecified order. Duplicates are not removed. + +- The attributes on the parameters of the resulting method declaration are the combined attributes of the corresponding parameters of the defining and the implementing partial constructor declaration in unspecified order. Duplicates are not removed. + ## 15.12 Static constructors A ***static constructor*** is a member that implements the actions required to initialize a closed class. Static constructors are declared using *static_constructor_declaration*s: From cca57f69c62d6aebb889c48df5d06444598454a6 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 30 Aug 2026 07:05:01 -0400 Subject: [PATCH 2/5] add support for partial events and constructors --- standard/attributes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/standard/attributes.md b/standard/attributes.md index c71b08865..998923268 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -290,9 +290,9 @@ Certain contexts permit the specification of an attribute on more than one targe - For an attribute specified on an event declaration that omits *event_accessor_declarations* the default target is the event declaration. Otherwise when the *attribute_target* is equal to: - `event` — the target is the event declaration - `field` — the target is the field - - `method` — the targets are the methods + - `method` — the targets are the methods (however, `method` is ignored on a partial event declaration) - In the case of an event declaration that does not omit *event_accessor_declarations* the default target is the method. - - `method` — the target is the associated method + - `method` — the target is the associated method (however, `method` is ignored on a partial event declaration) - `param` — the target is the lone parameter - For an attribute on a *lambda_expression* the default target is the method. Otherwise when the *attribute_target* is equal to: - `method` — the target is the method @@ -807,7 +807,7 @@ When an optional parameter is annotated with one of the caller-info attributes, Caller-info attributes can occur on optional parameters anywhere, including in delegate declarations. However, the specific caller-info attributes have restrictions on the types of the parameters they can attribute, so that there will always be an implicit conversion from a substituted value to the parameter type. -It is an error to have the same caller-info attribute on a parameter of both the defining and implementing part of a partial method or partial indexer declaration. Only caller-info attributes in the defining part are applied, whereas caller-info attributes occurring only in the implementing part are ignored. +It is an error to have the same caller-info attribute on a parameter of both the defining and implementing part of a partial method, partial indexer, partial event, or partial constructor declaration. Only caller-info attributes in the defining part are applied, whereas caller-info attributes occurring only in the implementing part are ignored. Caller information does not affect overload resolution. As the attributed optional parameters are still omitted from the source code of the caller, overload resolution ignores those parameters in the same way it ignores other omitted optional parameters ([§12.6.4](expressions.md#1264-overload-resolution)). From 89042f72205e8bd1920f1580cb797200cf2366c0 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 30 Aug 2026 07:08:39 -0400 Subject: [PATCH 3/5] add support for partial events and constructors --- standard/documentation-comments.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/documentation-comments.md b/standard/documentation-comments.md index 11239f2f6..8ba96ac5e 100644 --- a/standard/documentation-comments.md +++ b/standard/documentation-comments.md @@ -61,11 +61,11 @@ Although developers are free to create their own set of tags, a recommended set Note carefully that the documentation file does not provide full information about the type and members (for example, it does not contain any type information). To get such information about a type or member, the documentation file must be used in conjunction with reflection on the type or member. -A partial type, partial method, partial property, or partial indexer can be declared in multiple parts, each of which can be in one or more compilation units, and each of which can have one or more documentation comments. A partial method, partial property, or partial indexer typically has a “defining partial declaration” and an “implementing partial declaration.” +A partial type, partial method, partial property, partial indexer, partial event, or partial constructor can be declared in multiple parts, each of which can be in one or more compilation units, and each of which can have one or more documentation comments. A partial method, partial property, partial indexer, partial event, or partial constructor typically has a “defining partial declaration” and an “implementing partial declaration.” For a partial type, the document comments that apply directly to that type, if any, from each of its parts, are all written to the documentation file in some unspecified order. -For a partial method, partial property, or partial indexer: +For a partial method, partial property, partial indexer, partial event, or partial constructor: - If a defining partial declaration has no corresponding implementing partial declaration, any documentation comments in that defining partial declaration are ignored (as that declaration will be removed). - Otherwise, if the implementing partial declaration has any documentation comments, they are written to the documentation file, and any documentation comments in the defining partial declaration are ignored. From fd611d2c0b7f3b9351c054747cd7c1562767159a Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 30 Aug 2026 07:20:43 -0400 Subject: [PATCH 4/5] fix md --- standard/classes.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index e18246994..57f794c2e 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -4965,7 +4965,7 @@ When an *event_declaration* includes `partial`, that event is said to be a ***pa Partial events may be defined in one part of a type declaration and implemented in another, or be defined and implemented in the same part. -There are two kinds of partial event declarations: If the *event_accessor_declarations* are omitted and the event has no `extern` modifier, the declaration is said to be a ***defining partial event declaration***. Otherwise, the declaration is said to be an ***implementing partial event declaration***. +There are two kinds of partial event declarations: If the *event_accessor_declarations* are omitted and the event has no `extern` modifier, the declaration is said to be a ***defining partial event declaration***. Otherwise, the declaration is said to be an ***implementing partial event declaration***. Partial events are useful for allowing one part of a type declaration to customize the behavior of another part, e.g., one that is generated by a tool. @@ -5259,7 +5259,6 @@ The signature-matching requirements are as follows: 1. Differences in tuple element names within partial indexer declarations result in a compile-time error. 1. The property declarations and their accessor declarations shall have the same modifiers, though the modifiers may appear in a different order. However, this does not apply to the `extern` modifier, which may only appear on an implementing partial declaration. In the case of private accessibility on the indexer, both shall be implicitly private (that is, with no accessibility modifier) or both shall be explicitly `private`. Likewise, the corresponding accessors shall have the same implicit or same explicit accessibilities. 1. All other syntactic differences in the signatures of partial property declarations result in a compile-time warning, with the following exceptions: - - Attribute lists on or within partial indexer declarations do not need to match. Instead, merging of attributes in corresponding positions is performed in an unspecified order. Duplicates are not removed. - Nullable context differences do not cause warnings. In other words, a difference where one of the types is nullable-oblivious and the other type is either nullable-annotated or not-nullable-annotated does not result in any warnings. - Default argument values need not match, and any default arguments values in the implementing partial indexer declaration are ignored. From 62fd33c4f1c1882118e065e055dace6cadd5f005 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 30 Aug 2026 07:23:19 -0400 Subject: [PATCH 5/5] fix md --- standard/classes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/standard/classes.md b/standard/classes.md index 57f794c2e..b41efc811 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -5259,6 +5259,7 @@ The signature-matching requirements are as follows: 1. Differences in tuple element names within partial indexer declarations result in a compile-time error. 1. The property declarations and their accessor declarations shall have the same modifiers, though the modifiers may appear in a different order. However, this does not apply to the `extern` modifier, which may only appear on an implementing partial declaration. In the case of private accessibility on the indexer, both shall be implicitly private (that is, with no accessibility modifier) or both shall be explicitly `private`. Likewise, the corresponding accessors shall have the same implicit or same explicit accessibilities. 1. All other syntactic differences in the signatures of partial property declarations result in a compile-time warning, with the following exceptions: + - Attribute lists on or within partial indexer declarations do not need to match. Instead, merging of attributes in corresponding positions is performed in an unspecified order. Duplicates are not removed. - Nullable context differences do not cause warnings. In other words, a difference where one of the types is nullable-oblivious and the other type is either nullable-annotated or not-nullable-annotated does not result in any warnings. - Default argument values need not match, and any default arguments values in the implementing partial indexer declaration are ignored.