From bf31866322e1a3155f3d4d8f9eb8a8fbf16b8a98 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Mon, 13 Nov 2023 11:05:27 -0500 Subject: [PATCH 01/15] Add support for extending partial methods fix md formatting revert to previous text handle imp/exp private allow partial with ref_kind returns change link's target name Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 63 +++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 6ecf9d731..88a35e72f 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2074,7 +2074,7 @@ ref_kind ; ref_method_modifiers - : ref_method_modifier* + : ref_method_modifier* 'partial'? ; method_header @@ -2151,7 +2151,8 @@ A declaration has a valid combination of modifiers if all of the following are t - The declaration may include the `abstract` and `override` modifiers so that an abstract member may override a virtual member. - If the declaration includes the `private` modifier, then the declaration does not include any of the following modifiers: `virtual`, `override`, or `abstract`. - If the declaration includes the `sealed` modifier, then the declaration also includes the `override` modifier. -- If the declaration includes the `partial` modifier, then it does not include any of the following modifiers: `new`, `public`, `protected`, `internal`, `private`, `virtual`, `sealed`, `override`, `abstract`, or `extern`. +- If the declaration includes the `partial` modifier, then it does not include the modifier `abstract`. +- If the declaration is for a restricted partial method ([§15.6.9](classes.md#1569-partial-methods)), then it does not include any of the following modifiers: `new`, `public`, `protected`, `internal`, `private`, `virtual`, `sealed`, `override`, or `extern`. Methods are classified according to what, if anything, they return: @@ -2159,7 +2160,7 @@ Methods are classified according to what, if anything, they return: - Otherwise, if *return_type* is `void`, the method is ***return-no-value*** and does not return a value; - Otherwise, the method is ***return-by-value*** and returns a value. -The *return_type* of a return-by-value or return-no-value method declaration specifies the type of the result, if any, returned by the method. Only a return-no-value method may include the `partial` modifier ([§15.6.9](classes.md#1569-partial-methods)). If the declaration includes the `async` modifier then *return_type* shall be `void` or the method return-by-value and the return type is a *task type* ([§15.14.1](classes.md#15141-general)). +The *return_type* of a return-by-value or return-no-value method declaration specifies the type of the result, if any, returned by the method. Only a return-no-value method may include the `partial` modifier ([§15.6.9](classes.md#1569-partial-methods)). If the declaration includes the `async` modifier then *return_type* for a restricted partial method shall be `void` or the method return-by-value and the return type is a *task type* ([§15.14.1](classes.md#15141-general)). The *ref_return_type* of a return-by-ref method declaration specifies the type of the variable referenced by the *variable_reference* returned by the method. @@ -2388,7 +2389,7 @@ For a `struct` type, within an instance method, instance accessor ([§12.2.1](ex A parameter declared with an `out` modifier is an ***output parameter***. For definite-assignment rules, see [§9.2.7](variables.md#927-output-parameters). -A method declared as a partial method ([§15.6.9](classes.md#1569-partial-methods)) shall not have output parameters. +A method declared as a restricted partial method ([§15.6.9](classes.md#1569-partial-methods)) shall not have output parameters. > *Note*: Output parameters are typically used in methods that produce multiple return values. *end note* @@ -3026,23 +3027,53 @@ The mechanism by which linkage to an external method is achieved is implementati ### 15.6.9 Partial methods -When a method declaration includes a `partial` modifier, that method is said to be a ***partial method***. Partial methods 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. +When a *method declaration* includes a `partial` modifier, that method is said to be a ***partial method***. Partial methods may only be declared as members of partial types ([§15.2.7](classes.md#1527-partial-type-declarations)). -Partial methods may be defined in one part of a type declaration and implemented in another. The implementation is optional; if no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts. +Partial methods may be defined in one part of a type declaration and implemented in another, or be defined and implemented in the same part. -Partial methods shall not define access modifiers; they are implicitly private. Their return type shall be `void`, and their parameters shall not be output parameters. The identifier `partial` is recognized as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) in a method declaration only if it appears immediately before the `void` keyword. A partial method cannot explicitly implement interface methods. +There are two kinds of partial method declarations: If the body of the method declaration is a semicolon, the declaration is said to be a ***defining partial method declaration***. Otherwise, the declaration is said to be an ***implementing partial method declaration***. Across the parts of a type declaration, there may be only one defining partial method declaration with a given signature, and there may be only one implementing partial method declaration with a given signature. If an implementing partial method declaration is given, a corresponding defining partial method declaration shall exist, and the declarations shall match as specified in the following: -There are two kinds of partial method declarations: If the body of the method declaration is a semicolon, the declaration is said to be a ***defining partial method declaration***. If the body is other than a semicolon, the declaration is said to be an ***implementing partial method declaration***. Across the parts of a type declaration, there shall be only one defining partial method declaration with a given signature, and there shall be at most only one implementing partial method declaration with a given signature. If an implementing partial method declaration is given, a corresponding defining partial method declaration shall exist, and the declarations shall match as specified in the following: - -- The declarations shall have the same method name, number of type parameters, and number of parameters. -- The declarations shall have the same modifiers (although not necessarily in the same order), with the exception of the `async` modifier which shall not appear on a defining part. -- Corresponding parameters in the declarations shall have the same modifiers (although not necessarily in the same order) and the same types, or identity convertible types (modulo differences in type parameter names). +- The declarations shall have the same modifiers (although not necessarily in the same order), with the exception of the `async` and `extern` modifiers which shall not appear on a defining part. +- In the case of private accessibility, both declarations shall be implicitly private (that is, with no accessibility modifier) or both shall be explicitly `private`. +- Corresponding parameters in the declarations shall have the same modifiers (although not necessarily in the same order) and the same types (modulo differences in type parameter names). - Corresponding type parameters in the declarations shall have the same constraints (modulo differences in type parameter names). -An implementing partial method declaration can appear in the same part as the corresponding defining partial method declaration. +Over time, the specification for partial methods has evolved, resulting in restricted and unrestricted versions. A ***restricted partial method*** has no explicit access modifiers (and is implicitly private), has a `void` return type, and has no out parameters. An ***unrestricted partial method*** is a partial method that has explicit access modifiers, a non-`void` return type, or any out parameters. + +For a restricted partial method, the implementation is optional; if no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts. For an unrestricted partial method both the definition and implementation shall exist. + +In *method_declaration*, the identifier `partial` is recognized as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) only if it immediately precedes the *return_type*. A partial method cannot explicitly implement interface methods. + +> *Example*: +> +> +> ```csharp +> // part containing defining partial method declarations +> partial class C +> { +> partial void M1(); // restricted, impl. optional +> private partial void M2(); // unrestricted, impl. required +> protected partial bool M3(); // unrestricted, impl. required +> public partial void M4(out int i); // unrestricted, impl. required +> } +> +> // part containing implementing partial method declarations +> partial class C +> { +> private partial void M2() { ... } +> protected partial bool M3() { ... } +> public partial void M4(out int i) { ... } +> } +> ``` +> +> *end example* + +Only a defining partial method participates in overload resolution. As such, in the case of a restricted partial method, whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. -Only a defining partial method participates in overload resolution. Thus, whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. Because a partial method always returns `void`, such invocation expressions will always be expression statements. Furthermore, because a partial method is implicitly `private`, such statements will always occur within one of the parts of the type declaration within which the partial method is declared. +> *Note*: Because a restricted partial method always returns `void`, such invocation expressions will always be expression statements. Furthermore, because a restricted partial method is implicitly `private`, such statements will always occur within one of the parts of the type declaration within which the partial method is declared. *end note* + + > *Note*: The definition of matching defining and implementing partial method declarations does not require parameter names to match. This can produce *surprising*, albeit *well defined*, behaviour when named arguments ([§12.6.2.1](expressions.md#12621-general)) are used. For example, given the defining partial method declaration for `M` in one file, and the implementing partial method declaration in another file: > > @@ -3065,7 +3096,7 @@ Only a defining partial method participates in overload resolution. Thus, whethe > > *end note* -If no part of a partial type declaration contains an implementing declaration for a given partial method, any expression statement invoking it is simply removed from the combined type declaration. Thus the invocation expression, including any subexpressions, has no effect at run-time. The partial method itself is also removed and will not be a member of the combined type declaration. +If a restricted partial method has no implementation, any expression statement invoking it is simply removed from the combined type declaration. Thus, the invocation expression, including any subexpressions, has no effect at run-time. The partial method itself is also removed and will not be a member of the combined type declaration. If an implementing declaration exists for a given partial method, the invocations of the partial methods are retained. The partial method gives rise to a method declaration similar to the implementing partial method declaration except for the following: @@ -3075,7 +3106,7 @@ If an implementing declaration exists for a given partial method, the invocation - 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 method declaration in unspecified order. Duplicates are not removed. -If a defining declaration but not an implementing declaration is given for a partial method `M`, the following restrictions apply: +If a defining declaration but not an implementing declaration is given for a restricted partial method `M`, the following restrictions apply: - It is a compile-time error to create a delegate from `M` ([§12.8.17.5](expressions.md#128175-delegate-creation-expressions)). From a1840d16626d64e2336c3ec90bfabb930b4b1c8a Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 8 Jan 2026 16:28:11 -0500 Subject: [PATCH 02/15] Address existing comments. Also, edit after moving text around. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 75 +++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 88a35e72f..5fc4c88a4 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2152,7 +2152,7 @@ A declaration has a valid combination of modifiers if all of the following are t - If the declaration includes the `private` modifier, then the declaration does not include any of the following modifiers: `virtual`, `override`, or `abstract`. - If the declaration includes the `sealed` modifier, then the declaration also includes the `override` modifier. - If the declaration includes the `partial` modifier, then it does not include the modifier `abstract`. -- If the declaration is for a restricted partial method ([§15.6.9](classes.md#1569-partial-methods)), then it does not include any of the following modifiers: `new`, `public`, `protected`, `internal`, `private`, `virtual`, `sealed`, `override`, or `extern`. +- If the declaration is for a restricted partial method (§restricted-partial-methods), then it does not include any of the following modifiers: `new`, `public`, `protected`, `internal`, `private`, `virtual`, `sealed`, `override`, or `extern`. Methods are classified according to what, if anything, they return: @@ -2160,7 +2160,7 @@ Methods are classified according to what, if anything, they return: - Otherwise, if *return_type* is `void`, the method is ***return-no-value*** and does not return a value; - Otherwise, the method is ***return-by-value*** and returns a value. -The *return_type* of a return-by-value or return-no-value method declaration specifies the type of the result, if any, returned by the method. Only a return-no-value method may include the `partial` modifier ([§15.6.9](classes.md#1569-partial-methods)). If the declaration includes the `async` modifier then *return_type* for a restricted partial method shall be `void` or the method return-by-value and the return type is a *task type* ([§15.14.1](classes.md#15141-general)). +The *return_type* of a return-by-value or return-no-value method declaration specifies the type of the result, if any, returned by the method. If the declaration includes the `async` modifier then *return_type* shall be `void` or the method return-by-value and the return type is a *task type* ([§15.14.1](classes.md#15141-general)). The *ref_return_type* of a return-by-ref method declaration specifies the type of the variable referenced by the *variable_reference* returned by the method. @@ -2389,7 +2389,7 @@ For a `struct` type, within an instance method, instance accessor ([§12.2.1](ex A parameter declared with an `out` modifier is an ***output parameter***. For definite-assignment rules, see [§9.2.7](variables.md#927-output-parameters). -A method declared as a restricted partial method ([§15.6.9](classes.md#1569-partial-methods)) shall not have output parameters. +A method declared as a restricted partial method (§restricted-partial-methods) shall not have output parameters. > *Note*: Output parameters are typically used in methods that produce multiple return values. *end note* @@ -3027,20 +3027,27 @@ The mechanism by which linkage to an external method is achieved is implementati ### 15.6.9 Partial methods +#### §partial-methods-general General + When a *method declaration* includes a `partial` modifier, that method is said to be a ***partial method***. Partial methods may only be declared as members of partial types ([§15.2.7](classes.md#1527-partial-type-declarations)). -Partial methods 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 versions of partial methods: restricted and unrestricted. A ***restricted partial method*** (§restricted-partial-methods) has no explicit access modifiers, and is implicitly private. An ***unrestricted partial method*** (§unrestricted-partial-methods) is a partial method that includes one or more explicit access modifiers. + +There are two kinds of partial method declarations: -There are two kinds of partial method declarations: If the body of the method declaration is a semicolon, the declaration is said to be a ***defining partial method declaration***. Otherwise, the declaration is said to be an ***implementing partial method declaration***. Across the parts of a type declaration, there may be only one defining partial method declaration with a given signature, and there may be only one implementing partial method declaration with a given signature. If an implementing partial method declaration is given, a corresponding defining partial method declaration shall exist, and the declarations shall match as specified in the following: +- A method with an *expression-body* or a *block-body* or is declared with the `extern` modifier is said to be an ***implementing partial method declaration***. +- Otherwise, a method declaration where the body of the method declaration is a semicolon is said to be a ***defining partial method declaration***. -- The declarations shall have the same modifiers (although not necessarily in the same order), with the exception of the `async` and `extern` modifiers which shall not appear on a defining part. -- In the case of private accessibility, both declarations shall be implicitly private (that is, with no accessibility modifier) or both shall be explicitly `private`. +Across the parts of a type declaration, there shall be exactly one defining partial method declaration with a given signature. For an implementing partial method declaration is given, a corresponding defining partial method declaration shall exist, and the declarations shall match as specified in the following: + +- The declarations shall have the same method name, number of type parameters, and number of parameters. +- The declarations shall have the same modifiers except for the `async` and `extern` modifiers. The `async` and `extern` modifiers are allowed only on the implementing partial method declaration. - Corresponding parameters in the declarations shall have the same modifiers (although not necessarily in the same order) and the same types (modulo differences in type parameter names). - Corresponding type parameters in the declarations shall have the same constraints (modulo differences in type parameter names). -Over time, the specification for partial methods has evolved, resulting in restricted and unrestricted versions. A ***restricted partial method*** has no explicit access modifiers (and is implicitly private), has a `void` return type, and has no out parameters. An ***unrestricted partial method*** is a partial method that has explicit access modifiers, a non-`void` return type, or any out parameters. +Partial methods may be defined in one part of a type declaration and implemented in another, or be defined and implemented in the same part. -For a restricted partial method, the implementation is optional; if no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts. For an unrestricted partial method both the definition and implementation shall exist. +For an unrestricted partial method both the definition and implementation shall exist. In *method_declaration*, the identifier `partial` is recognized as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) only if it immediately precedes the *return_type*. A partial method cannot explicitly implement interface methods. @@ -3068,12 +3075,8 @@ In *method_declaration*, the identifier `partial` is recognized as a contextual > > *end example* -Only a defining partial method participates in overload resolution. As such, in the case of a restricted partial method, whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. +Only a defining partial method participates in overload resolution. -> *Note*: Because a restricted partial method always returns `void`, such invocation expressions will always be expression statements. Furthermore, because a restricted partial method is implicitly `private`, such statements will always occur within one of the parts of the type declaration within which the partial method is declared. *end note* - - - > *Note*: The definition of matching defining and implementing partial method declarations does not require parameter names to match. This can produce *surprising*, albeit *well defined*, behaviour when named arguments ([§12.6.2.1](expressions.md#12621-general)) are used. For example, given the defining partial method declaration for `M` in one file, and the implementing partial method declaration in another file: > > @@ -3096,25 +3099,12 @@ Only a defining partial method participates in overload resolution. As such, in > > *end note* -If a restricted partial method has no implementation, any expression statement invoking it is simply removed from the combined type declaration. Thus, the invocation expression, including any subexpressions, has no effect at run-time. The partial method itself is also removed and will not be a member of the combined type declaration. - If an implementing declaration exists for a given partial method, the invocations of the partial methods are retained. The partial method gives rise to a method declaration similar to the implementing partial method declaration except for the following: -- The `partial` modifier is not included. - +- All modifiers except the `partial` modifier are combined, including any `extern` or `async` modifier declared on the implementing declaration. - The attributes in the resulting method declaration are the combined attributes of the defining and the implementing partial method declaration 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 method declaration in unspecified order. Duplicates are not removed. - -If a defining declaration but not an implementing declaration is given for a restricted partial method `M`, the following restrictions apply: - -- It is a compile-time error to create a delegate from `M` ([§12.8.17.5](expressions.md#128175-delegate-creation-expressions)). - -- It is a compile-time error to refer to `M` inside an anonymous function that is converted to an expression tree type ([§8.6](types.md#86-expression-tree-types)). - -- Expressions occurring as part of an invocation of `M` do not affect the definite assignment state ([§9.4](variables.md#94-definite-assignment)), which can potentially lead to compile-time errors. - -- `M` cannot be the entry point for an application ([§7.1](basic-concepts.md#71-application-startup-and-termination)). +- Any default arguments (§15.6.2) in the implementing declaration are removed. Partial methods 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. Consider the following partial class declaration: @@ -3198,6 +3188,31 @@ class Customer } ``` +#### §restricted-partial-methods Restricted partial methods + +A restricted partial method shall have a `void` return type, and shall not declare out parameters. There shall be zero or one implementing declaration for each defining declaration. If no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts. Whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. + +The implementing member for a restricted partial method shall not be an external method (§15.6.8). + +> *Note*: Because a restricted partial method always returns `void`, such invocation expressions will always be expression statements. Furthermore, because a restricted partial method is implicitly `private`, such statements will always occur within one of the parts of the type declaration within which the partial method is declared. *end note* + +If a restricted partial method has no implementation, any expression statement invoking it is removed from the combined type declaration. Thus, the invocation expression, including any subexpressions, has no effect at run-time. The partial method itself is also removed and will not be a member of the combined type declaration. + +If a defining declaration but not an implementing declaration is given for a restricted partial method `M`, the following restrictions apply: + +- It is a compile-time error to create a delegate from `M` ([§12.8.17.5](expressions.md#128175-delegate-creation-expressions)). +- It is a compile-time error to refer to `M` inside an anonymous function that is converted to an expression tree type ([§8.6](types.md#86-expression-tree-types)). +- Expressions occurring as part of an invocation of `M` do not affect the definite assignment state ([§9.4](variables.md#94-definite-assignment)), which can potentially lead to compile-time errors. +- `M` cannot be the entry point for an application ([§7.1](basic-concepts.md#71-application-startup)). + +#### §unrestricted-partial-methods Unrestricted partial methods + +An unrestriced partial method has an explicit access modifier. There shall be exactly one implementing partial method declaration. + +The implementing declaration for an unrestricted partial method may be an external method (§15.6.8). + +> *Note:* The `private` access modifier is required on both the ***defining partial method declaration*** and the ***implementing partial method declaration*** of an unrestricted partial method. *end note* + ### 15.6.10 Extension methods When the first parameter of a method includes the `this` modifier, that method is said to be an ***extension method***. Extension methods shall only be declared in non-generic, non-nested static classes. The first parameter of an extension method is restricted, as follows: @@ -4265,7 +4280,7 @@ The *event_accessor_declarations* of an event specify the executable statements The accessor declarations consist of an *add_accessor_declaration* and a *remove_accessor_declaration*. Each accessor declaration consists of the token add or remove followed by a *block*. The *block* associated with an *add_accessor_declaration* specifies the statements to execute when an event handler is added, and the *block* associated with a *remove_accessor_declaration* specifies the statements to execute when an event handler is removed. -Each *add_accessor_declaration* and *remove_accessor_declaration* corresponds to a method with a single value parameter of the event type, and a `void` return type. The implicit parameter of an event accessor is named `value`. When an event is used in an event assignment, the appropriate event accessor is used. Specifically, if the assignment operator is `+=` then the add accessor is used, and if the assignment operator is `–=` then the remove accessor is used. In either case, the right operand of the assignment operator is used as the argument to the event accessor. The block of an *add_accessor_declaration* or a *remove_accessor_declaration* shall conform to the rules for `void` methods described in [§15.6.11](classes.md#15611-method-body). In particular, `return` statements in such a block are not permitted to specify an expression. +Each *add_accessor_declaration* and *remove_accessor_declaration* corresponds to a method with a single value parameter of the event type, and a `void` return type. The implicit parameter of an event accessor is named `value`. When an event is used in an event assignment, the appropriate event accessor is used. Specifically, if the assignment operator is `+=` then the add accessor is used, and if the assignment operator is `–=` then the remove accessor is used. In either case, the right operand of the assignment operator is used as the argument to the event accessor. The block of an *add_accessor_declaration* or a *remove_accessor_declaration* shall conform to the rules for `void` methods described in §restricted-partial-methods. In particular, `return` statements in such a block are not permitted to specify an expression. Since an event accessor implicitly has a parameter named `value`, it is a compile-time error for a local variable or constant declared in an event accessor to have that name. From 16377406be89f6f5812c8ef1e61243312399fd6e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 9 Jan 2026 11:27:22 -0500 Subject: [PATCH 03/15] Some final edits Clean up a bit of language and flow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 5fc4c88a4..42946cc2a 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -3029,11 +3029,11 @@ The mechanism by which linkage to an external method is achieved is implementati #### §partial-methods-general General -When a *method declaration* includes a `partial` modifier, that method is said to be a ***partial method***. Partial methods may only be declared as members of partial types ([§15.2.7](classes.md#1527-partial-type-declarations)). +When a *method declaration* includes a `partial` modifier, that method is said to be a ***partial method***. Partial methods may only be declared as members of partial types ([§15.2.7](classes.md#1527-partial-type-declarations)). Partial methods may be defined in one part of a type declaration and implemented in another. -There are two versions of partial methods: restricted and unrestricted. A ***restricted partial method*** (§restricted-partial-methods) has no explicit access modifiers, and is implicitly private. An ***unrestricted partial method*** (§unrestricted-partial-methods) is a partial method that includes one or more explicit access modifiers. +In *method_declaration*, the identifier `partial` is recognized as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) only if it immediately precedes the *return_type*. A partial method cannot explicitly implement interface methods. -There are two kinds of partial method declarations: +There are classifications of a partial method declaration: - A method with an *expression-body* or a *block-body* or is declared with the `extern` modifier is said to be an ***implementing partial method declaration***. - Otherwise, a method declaration where the body of the method declaration is a semicolon is said to be a ***defining partial method declaration***. @@ -3045,12 +3045,10 @@ Across the parts of a type declaration, there shall be exactly one defining part - Corresponding parameters in the declarations shall have the same modifiers (although not necessarily in the same order) and the same types (modulo differences in type parameter names). - Corresponding type parameters in the declarations shall have the same constraints (modulo differences in type parameter names). -Partial methods 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 versions of partial methods: restricted and unrestricted. A ***restricted partial method*** (§restricted-partial-methods) has no explicit access modifiers, and is implicitly private. An ***unrestricted partial method*** (§unrestricted-partial-methods) is a partial method that includes one or more explicit access modifiers. For an unrestricted partial method both the definition and implementation shall exist. -In *method_declaration*, the identifier `partial` is recognized as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) only if it immediately precedes the *return_type*. A partial method cannot explicitly implement interface methods. - > *Example*: > > @@ -3101,7 +3099,7 @@ Only a defining partial method participates in overload resolution. If an implementing declaration exists for a given partial method, the invocations of the partial methods are retained. The partial method gives rise to a method declaration similar to the implementing partial method declaration except for the following: -- All modifiers except the `partial` modifier are combined, including any `extern` or `async` modifier declared on the implementing declaration. +- All modifiers except the `partial` modifier are included in the resulting, including any `extern` or `async` modifier declared on the implementing declaration. - The attributes in the resulting method declaration are the combined attributes of the defining and the implementing partial method declaration 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 method declaration in unspecified order. Duplicates are not removed. - Any default arguments (§15.6.2) in the implementing declaration are removed. @@ -3207,11 +3205,11 @@ If a defining declaration but not an implementing declaration is given for a res #### §unrestricted-partial-methods Unrestricted partial methods -An unrestriced partial method has an explicit access modifier. There shall be exactly one implementing partial method declaration. +An unrestriced partial method declartion incluces an explicit access modifier. There shall be exactly one implementing partial method declaration. -The implementing declaration for an unrestricted partial method may be an external method (§15.6.8). +The implementing declaration for an unrestricted partial method may be an external method (§15.6.8). The `extern` modifier is modifer allowed on an implementing partial declaration. It shall not be present on a defining partial declaration. -> *Note:* The `private` access modifier is required on both the ***defining partial method declaration*** and the ***implementing partial method declaration*** of an unrestricted partial method. *end note* +> *Note:* The `private` access modifier is required on both the ***defining partial method declaration*** and the ***implementing partial method declaration*** of a private unrestricted partial method. *end note* ### 15.6.10 Extension methods From 6f804889ecefb6bd452411ca180513059a1303db Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 29 Jan 2026 11:23:27 -0500 Subject: [PATCH 04/15] Apply suggestions from code review Co-authored-by: Jon Skeet Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 42946cc2a..3705cd5c5 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -3033,12 +3033,12 @@ When a *method declaration* includes a `partial` modifier, that method is said t In *method_declaration*, the identifier `partial` is recognized as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) only if it immediately precedes the *return_type*. A partial method cannot explicitly implement interface methods. -There are classifications of a partial method declaration: +Partial method declarations are classified as follows: - A method with an *expression-body* or a *block-body* or is declared with the `extern` modifier is said to be an ***implementing partial method declaration***. - Otherwise, a method declaration where the body of the method declaration is a semicolon is said to be a ***defining partial method declaration***. -Across the parts of a type declaration, there shall be exactly one defining partial method declaration with a given signature. For an implementing partial method declaration is given, a corresponding defining partial method declaration shall exist, and the declarations shall match as specified in the following: +Across the parts of a type declaration, there shall be exactly one defining partial method declaration with a given signature. If an implementing partial method declaration is given, a corresponding defining partial method declaration shall exist, and the declarations shall match as specified in the following: - The declarations shall have the same method name, number of type parameters, and number of parameters. - The declarations shall have the same modifiers except for the `async` and `extern` modifiers. The `async` and `extern` modifiers are allowed only on the implementing partial method declaration. @@ -3099,7 +3099,7 @@ Only a defining partial method participates in overload resolution. If an implementing declaration exists for a given partial method, the invocations of the partial methods are retained. The partial method gives rise to a method declaration similar to the implementing partial method declaration except for the following: -- All modifiers except the `partial` modifier are included in the resulting, including any `extern` or `async` modifier declared on the implementing declaration. +- All modifiers except the `partial` modifier are included in the resulting method declaration, including any `extern` or `async` modifier declared on the implementing declaration. - The attributes in the resulting method declaration are the combined attributes of the defining and the implementing partial method declaration 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 method declaration in unspecified order. Duplicates are not removed. - Any default arguments (§15.6.2) in the implementing declaration are removed. @@ -3205,7 +3205,7 @@ If a defining declaration but not an implementing declaration is given for a res #### §unrestricted-partial-methods Unrestricted partial methods -An unrestriced partial method declartion incluces an explicit access modifier. There shall be exactly one implementing partial method declaration. +An unrestricted partial method declaration incluces an explicit access modifier. There shall be exactly one implementing partial method declaration. The implementing declaration for an unrestricted partial method may be an external method (§15.6.8). The `extern` modifier is modifer allowed on an implementing partial declaration. It shall not be present on a defining partial declaration. From fec337347f25db3ef518917a1f446d2e64786d10 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 29 Jan 2026 13:54:47 -0500 Subject: [PATCH 05/15] Respond to meeting feedback Investigate and respond to feedback from reviews. Implement the proposed name change to "optional" and "required" Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 3705cd5c5..cbe3eebb7 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2152,7 +2152,7 @@ A declaration has a valid combination of modifiers if all of the following are t - If the declaration includes the `private` modifier, then the declaration does not include any of the following modifiers: `virtual`, `override`, or `abstract`. - If the declaration includes the `sealed` modifier, then the declaration also includes the `override` modifier. - If the declaration includes the `partial` modifier, then it does not include the modifier `abstract`. -- If the declaration is for a restricted partial method (§restricted-partial-methods), then it does not include any of the following modifiers: `new`, `public`, `protected`, `internal`, `private`, `virtual`, `sealed`, `override`, or `extern`. +- If the declaration is for a required partial method (§required-partial-methods), then it does not include any of the following modifiers: `new`, `public`, `protected`, `internal`, `private`, `virtual`, `sealed`, `override`, or `extern`. Methods are classified according to what, if anything, they return: @@ -2389,7 +2389,7 @@ For a `struct` type, within an instance method, instance accessor ([§12.2.1](ex A parameter declared with an `out` modifier is an ***output parameter***. For definite-assignment rules, see [§9.2.7](variables.md#927-output-parameters). -A method declared as a restricted partial method (§restricted-partial-methods) shall not have output parameters. +A method declared as a required partial method (§required-partial-methods) shall not have output parameters. > *Note*: Output parameters are typically used in methods that produce multiple return values. *end note* @@ -3042,12 +3042,12 @@ Across the parts of a type declaration, there shall be exactly one defining part - The declarations shall have the same method name, number of type parameters, and number of parameters. - The declarations shall have the same modifiers except for the `async` and `extern` modifiers. The `async` and `extern` modifiers are allowed only on the implementing partial method declaration. -- Corresponding parameters in the declarations shall have the same modifiers (although not necessarily in the same order) and the same types (modulo differences in type parameter names). -- Corresponding type parameters in the declarations shall have the same constraints (modulo differences in type parameter names). +- Corresponding parameters in the declarations shall have the same modifiers (although not necessarily in the same order) and the same types (modulo differences in type parameter names). Tuple types (§8.3.11) used as parameters or return types shall have the same item names in both the defining and implementing partial method declarations. +- Corresponding type parameters in the declarations shall have the same constraints. An implementation may choose to issue a warning if the type parameter names are different in the defining and implementing declarations. -There are two versions of partial methods: restricted and unrestricted. A ***restricted partial method*** (§restricted-partial-methods) has no explicit access modifiers, and is implicitly private. An ***unrestricted partial method*** (§unrestricted-partial-methods) is a partial method that includes one or more explicit access modifiers. +There are two classifications of partial methods: required and optional. A ***required partial method*** (§required-partial-methods) has no explicit access modifiers, and is implicitly private. An ***optional partial method*** (§optional-partial-methods) is a partial method that includes one or more explicit access modifiers. -For an unrestricted partial method both the definition and implementation shall exist. +For an optional partial method both the definition and implementation shall exist. > *Example*: > @@ -3056,10 +3056,10 @@ For an unrestricted partial method both the definition and implementation shall > // part containing defining partial method declarations > partial class C > { -> partial void M1(); // restricted, impl. optional -> private partial void M2(); // unrestricted, impl. required -> protected partial bool M3(); // unrestricted, impl. required -> public partial void M4(out int i); // unrestricted, impl. required +> partial void M1(); // implementation optional +> private partial void M2(); // required, impl. required +> protected partial bool M3(); // required, impl. required +> public partial void M4(out int i); // required, impl. required > } > > // part containing implementing partial method declarations @@ -3186,30 +3186,30 @@ class Customer } ``` -#### §restricted-partial-methods Restricted partial methods +#### §required-partial-methods Required partial methods -A restricted partial method shall have a `void` return type, and shall not declare out parameters. There shall be zero or one implementing declaration for each defining declaration. If no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts. Whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. +A required partial method shall have a `void` return type, and shall not declare out parameters. There shall be zero or one implementing declaration for each defining declaration. If no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts. Whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. -The implementing member for a restricted partial method shall not be an external method (§15.6.8). +The implementing member for a required partial method shall not be an external method (§15.6.8). -> *Note*: Because a restricted partial method always returns `void`, such invocation expressions will always be expression statements. Furthermore, because a restricted partial method is implicitly `private`, such statements will always occur within one of the parts of the type declaration within which the partial method is declared. *end note* +> *Note*: Because a required partial method always returns `void`, such invocation expressions will always be expression statements. Furthermore, because a required partial method is implicitly `private`, such statements will always occur within one of the parts of the type declaration within which the partial method is declared. *end note* -If a restricted partial method has no implementation, any expression statement invoking it is removed from the combined type declaration. Thus, the invocation expression, including any subexpressions, has no effect at run-time. The partial method itself is also removed and will not be a member of the combined type declaration. +If a required partial method has no implementation, any expression statement invoking it is removed from the combined type declaration. Thus, the invocation expression, including any subexpressions, has no effect at run-time. The partial method itself is also removed and will not be a member of the combined type declaration. -If a defining declaration but not an implementing declaration is given for a restricted partial method `M`, the following restrictions apply: +If a defining declaration but not an implementing declaration is given for a required partial method `M`, the following restrictions apply: - It is a compile-time error to create a delegate from `M` ([§12.8.17.5](expressions.md#128175-delegate-creation-expressions)). - It is a compile-time error to refer to `M` inside an anonymous function that is converted to an expression tree type ([§8.6](types.md#86-expression-tree-types)). - Expressions occurring as part of an invocation of `M` do not affect the definite assignment state ([§9.4](variables.md#94-definite-assignment)), which can potentially lead to compile-time errors. - `M` cannot be the entry point for an application ([§7.1](basic-concepts.md#71-application-startup)). -#### §unrestricted-partial-methods Unrestricted partial methods +#### optional-partial-methods Optional partial methods -An unrestricted partial method declaration incluces an explicit access modifier. There shall be exactly one implementing partial method declaration. +An optional partial method declaration incluces an explicit access modifier. There shall be exactly one implementing partial method declaration. -The implementing declaration for an unrestricted partial method may be an external method (§15.6.8). The `extern` modifier is modifer allowed on an implementing partial declaration. It shall not be present on a defining partial declaration. +The implementing declaration for an optional partial method may be an external method (§15.6.8). The `extern` modifier is modifer allowed on an implementing partial declaration. It shall not be present on a defining partial declaration. -> *Note:* The `private` access modifier is required on both the ***defining partial method declaration*** and the ***implementing partial method declaration*** of a private unrestricted partial method. *end note* +> *Note:* The `private` access modifier is required on both the ***defining partial method declaration*** and the ***implementing partial method declaration*** of a private optional partial method. *end note* ### 15.6.10 Extension methods @@ -4278,7 +4278,7 @@ The *event_accessor_declarations* of an event specify the executable statements The accessor declarations consist of an *add_accessor_declaration* and a *remove_accessor_declaration*. Each accessor declaration consists of the token add or remove followed by a *block*. The *block* associated with an *add_accessor_declaration* specifies the statements to execute when an event handler is added, and the *block* associated with a *remove_accessor_declaration* specifies the statements to execute when an event handler is removed. -Each *add_accessor_declaration* and *remove_accessor_declaration* corresponds to a method with a single value parameter of the event type, and a `void` return type. The implicit parameter of an event accessor is named `value`. When an event is used in an event assignment, the appropriate event accessor is used. Specifically, if the assignment operator is `+=` then the add accessor is used, and if the assignment operator is `–=` then the remove accessor is used. In either case, the right operand of the assignment operator is used as the argument to the event accessor. The block of an *add_accessor_declaration* or a *remove_accessor_declaration* shall conform to the rules for `void` methods described in §restricted-partial-methods. In particular, `return` statements in such a block are not permitted to specify an expression. +Each *add_accessor_declaration* and *remove_accessor_declaration* corresponds to a method with a single value parameter of the event type, and a `void` return type. The implicit parameter of an event accessor is named `value`. When an event is used in an event assignment, the appropriate event accessor is used. Specifically, if the assignment operator is `+=` then the add accessor is used, and if the assignment operator is `–=` then the remove accessor is used. In either case, the right operand of the assignment operator is used as the argument to the event accessor. The block of an *add_accessor_declaration* or a *remove_accessor_declaration* shall conform to the rules for `void` methods described in §required-partial-methods. In particular, `return` statements in such a block are not permitted to specify an expression. Since an event accessor implicitly has a parameter named `value`, it is a compile-time error for a local variable or constant declared in an event accessor to have that name. From f1fc3565e9af36af6d57e85e95dc762460315dc5 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 29 Jan 2026 14:00:20 -0500 Subject: [PATCH 06/15] fix build issues Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index cbe3eebb7..e75572840 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -3099,7 +3099,7 @@ Only a defining partial method participates in overload resolution. If an implementing declaration exists for a given partial method, the invocations of the partial methods are retained. The partial method gives rise to a method declaration similar to the implementing partial method declaration except for the following: -- All modifiers except the `partial` modifier are included in the resulting method declaration, including any `extern` or `async` modifier declared on the implementing declaration. +- The `partial` modifier is not included in the combined method declaration. - The attributes in the resulting method declaration are the combined attributes of the defining and the implementing partial method declaration 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 method declaration in unspecified order. Duplicates are not removed. - Any default arguments (§15.6.2) in the implementing declaration are removed. @@ -3203,7 +3203,7 @@ If a defining declaration but not an implementing declaration is given for a req - Expressions occurring as part of an invocation of `M` do not affect the definite assignment state ([§9.4](variables.md#94-definite-assignment)), which can potentially lead to compile-time errors. - `M` cannot be the entry point for an application ([§7.1](basic-concepts.md#71-application-startup)). -#### optional-partial-methods Optional partial methods +#### §optional-partial-methods Optional partial methods An optional partial method declaration incluces an explicit access modifier. There shall be exactly one implementing partial method declaration. From 9bd3200e77650a891d88ef98d327d3444e9f36fd Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 25 Feb 2026 13:54:42 -0500 Subject: [PATCH 07/15] Apply suggestions from code review Co-authored-by: Jon Skeet Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index e75572840..5647ec8e0 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2160,7 +2160,7 @@ Methods are classified according to what, if anything, they return: - Otherwise, if *return_type* is `void`, the method is ***return-no-value*** and does not return a value; - Otherwise, the method is ***return-by-value*** and returns a value. -The *return_type* of a return-by-value or return-no-value method declaration specifies the type of the result, if any, returned by the method. If the declaration includes the `async` modifier then *return_type* shall be `void` or the method return-by-value and the return type is a *task type* ([§15.14.1](classes.md#15141-general)). +The *return_type* of a return-by-value or return-no-value method declaration specifies the type of the result, if any, returned by the method. If the declaration includes the `async` modifier then *return_type* shall be `void` or the method return-by-value and the return type shall be a *task type* ([§15.14.1](classes.md#15141-general)). The *ref_return_type* of a return-by-ref method declaration specifies the type of the variable referenced by the *variable_reference* returned by the method. @@ -3047,7 +3047,7 @@ Across the parts of a type declaration, there shall be exactly one defining part There are two classifications of partial methods: required and optional. A ***required partial method*** (§required-partial-methods) has no explicit access modifiers, and is implicitly private. An ***optional partial method*** (§optional-partial-methods) is a partial method that includes one or more explicit access modifiers. -For an optional partial method both the definition and implementation shall exist. +For a required partial method both the definition and implementation shall exist. > *Example*: > From ca442d3db200eea00b881088f688b048ed31c4ba Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 25 Feb 2026 14:03:24 -0500 Subject: [PATCH 08/15] Respond to feedback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 5647ec8e0..ef82d6aab 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -3045,7 +3045,7 @@ Across the parts of a type declaration, there shall be exactly one defining part - Corresponding parameters in the declarations shall have the same modifiers (although not necessarily in the same order) and the same types (modulo differences in type parameter names). Tuple types (§8.3.11) used as parameters or return types shall have the same item names in both the defining and implementing partial method declarations. - Corresponding type parameters in the declarations shall have the same constraints. An implementation may choose to issue a warning if the type parameter names are different in the defining and implementing declarations. -There are two classifications of partial methods: required and optional. A ***required partial method*** (§required-partial-methods) has no explicit access modifiers, and is implicitly private. An ***optional partial method*** (§optional-partial-methods) is a partial method that includes one or more explicit access modifiers. +There are two variations of partial methods: required and optional. A ***required partial method*** (§required-partial-methods) is a partial method that includes one or more explicit access modifiers. An ***optional partial method*** (§optional-partial-methods) has no explicit access modifiers, and is implicitly private. For a required partial method both the definition and implementation shall exist. @@ -3186,30 +3186,30 @@ class Customer } ``` -#### §required-partial-methods Required partial methods +#### §optional-partial-methods Optional partial methods -A required partial method shall have a `void` return type, and shall not declare out parameters. There shall be zero or one implementing declaration for each defining declaration. If no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts. Whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. +An optional partial method shall have a `void` return type, and shall not declare out parameters. There shall be zero or one implementing declaration for each defining declaration. If no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts. Whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. -The implementing member for a required partial method shall not be an external method (§15.6.8). +The implementing member for an optional partial method shall not be an external method (§15.6.8). -> *Note*: Because a required partial method always returns `void`, such invocation expressions will always be expression statements. Furthermore, because a required partial method is implicitly `private`, such statements will always occur within one of the parts of the type declaration within which the partial method is declared. *end note* +> *Note*: Because an optional partial method always returns `void`, such invocation expressions will always be expression statements. Furthermore, because an optional partial method is implicitly `private`, such statements will always occur within one of the parts of the type declaration within which the partial method is declared. *end note* -If a required partial method has no implementation, any expression statement invoking it is removed from the combined type declaration. Thus, the invocation expression, including any subexpressions, has no effect at run-time. The partial method itself is also removed and will not be a member of the combined type declaration. +If an optional partial method has no implementation, any expression statement invoking it is removed from the combined type declaration. Thus, the invocation expression, including any subexpressions, has no effect at run-time. The partial method itself is also removed and will not be a member of the combined type declaration. -If a defining declaration but not an implementing declaration is given for a required partial method `M`, the following restrictions apply: +If a defining declaration but not an implementing declaration is given for an optional partial method `M`, the following restrictions apply: - It is a compile-time error to create a delegate from `M` ([§12.8.17.5](expressions.md#128175-delegate-creation-expressions)). - It is a compile-time error to refer to `M` inside an anonymous function that is converted to an expression tree type ([§8.6](types.md#86-expression-tree-types)). - Expressions occurring as part of an invocation of `M` do not affect the definite assignment state ([§9.4](variables.md#94-definite-assignment)), which can potentially lead to compile-time errors. - `M` cannot be the entry point for an application ([§7.1](basic-concepts.md#71-application-startup)). -#### §optional-partial-methods Optional partial methods +#### §required-partial-methods Required partial methods -An optional partial method declaration incluces an explicit access modifier. There shall be exactly one implementing partial method declaration. +An required partial method declaration includes an explicit access modifier. There shall be exactly one implementing partial method declaration. -The implementing declaration for an optional partial method may be an external method (§15.6.8). The `extern` modifier is modifer allowed on an implementing partial declaration. It shall not be present on a defining partial declaration. +The implementing declaration for a required partial method may be an external method (§15.6.8). The `extern` modifier is modifier allowed on an implementing partial declaration. It shall not be present on a defining partial declaration. -> *Note:* The `private` access modifier is required on both the ***defining partial method declaration*** and the ***implementing partial method declaration*** of a private optional partial method. *end note* +> *Note:* The `private` access modifier is required on both the ***defining partial method declaration*** and the ***implementing partial method declaration*** of a private required partial method. *end note* ### 15.6.10 Extension methods From 4e649420119940d140033408f1871944804e0162 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 25 Feb 2026 14:52:49 -0500 Subject: [PATCH 09/15] missed a couple... Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index ef82d6aab..e7d53607b 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2152,7 +2152,7 @@ A declaration has a valid combination of modifiers if all of the following are t - If the declaration includes the `private` modifier, then the declaration does not include any of the following modifiers: `virtual`, `override`, or `abstract`. - If the declaration includes the `sealed` modifier, then the declaration also includes the `override` modifier. - If the declaration includes the `partial` modifier, then it does not include the modifier `abstract`. -- If the declaration is for a required partial method (§required-partial-methods), then it does not include any of the following modifiers: `new`, `public`, `protected`, `internal`, `private`, `virtual`, `sealed`, `override`, or `extern`. +- If the declaration is for an optional partial method (§optional-partial-methods), then it does not include any of the following modifiers: `new`, `public`, `protected`, `internal`, `private`, `virtual`, `sealed`, `override`, or `extern`. Methods are classified according to what, if anything, they return: @@ -2389,7 +2389,7 @@ For a `struct` type, within an instance method, instance accessor ([§12.2.1](ex A parameter declared with an `out` modifier is an ***output parameter***. For definite-assignment rules, see [§9.2.7](variables.md#927-output-parameters). -A method declared as a required partial method (§required-partial-methods) shall not have output parameters. +A method declared as an optional partial method (§optional-partial-methods) shall not have output parameters. > *Note*: Output parameters are typically used in methods that produce multiple return values. *end note* From 075ba713cefd0b632583794377fc3844bdc86b18 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 25 Feb 2026 15:00:55 -0500 Subject: [PATCH 10/15] review and edit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index e7d53607b..1bdbec4ad 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2184,7 +2184,7 @@ If the *method_body* consists of a semicolon, the declaration shall not include The *ref_method_body* of a return-by-ref method is either a semicolon, a block body or an expression body. A block body consists of a *block*, which specifies the statements to execute when the method is invoked. An expression body consists of `=>`, followed by `ref`, a *variable_reference*, and a semicolon, and denotes a single *variable_reference* to evaluate when the method is invoked. -For abstract and extern methods, the *ref_method_body* consists simply of a semicolon; for all other methods, the *ref_method_body* is either a block body or an expression body. +For abstract and extern methods, the *ref_method_body* consists simply of a semicolon. For partial methods the *ref_method_body* may consist of either a semicolon, a block body or an expression body. For all other methods, the *ref_method_body* is either a block body or an expression body. The name, the number of type parameters, and the parameter list of a method define the signature ([§7.5](basic-concepts.md#75-signatures-and-overloading)) of the method. Specifically, the signature of a method consists of its name, the number of its type parameters, and the number, *parameter_mode_modifier*s ([§15.6.2.1](classes.md#15621-general)), and types of its parameters. The return type is not part of a method’s signature, nor are the names of the parameters, the names of the type parameters, or the constraints. When a parameter type references a type parameter of the method, the ordinal position of the type parameter (not the name of the type parameter) is used for type equivalence. @@ -3205,9 +3205,9 @@ If a defining declaration but not an implementing declaration is given for an op #### §required-partial-methods Required partial methods -An required partial method declaration includes an explicit access modifier. There shall be exactly one implementing partial method declaration. +A required partial method declaration includes an explicit access modifier. There shall be exactly one implementing partial method declaration. -The implementing declaration for a required partial method may be an external method (§15.6.8). The `extern` modifier is modifier allowed on an implementing partial declaration. It shall not be present on a defining partial declaration. +The implementing declaration for a required partial method may be an external method (§15.6.8). The `extern` modifier is allowed on an implementing partial declaration. It shall not be present on a defining partial declaration. > *Note:* The `private` access modifier is required on both the ***defining partial method declaration*** and the ***implementing partial method declaration*** of a private required partial method. *end note* @@ -4278,7 +4278,7 @@ The *event_accessor_declarations* of an event specify the executable statements The accessor declarations consist of an *add_accessor_declaration* and a *remove_accessor_declaration*. Each accessor declaration consists of the token add or remove followed by a *block*. The *block* associated with an *add_accessor_declaration* specifies the statements to execute when an event handler is added, and the *block* associated with a *remove_accessor_declaration* specifies the statements to execute when an event handler is removed. -Each *add_accessor_declaration* and *remove_accessor_declaration* corresponds to a method with a single value parameter of the event type, and a `void` return type. The implicit parameter of an event accessor is named `value`. When an event is used in an event assignment, the appropriate event accessor is used. Specifically, if the assignment operator is `+=` then the add accessor is used, and if the assignment operator is `–=` then the remove accessor is used. In either case, the right operand of the assignment operator is used as the argument to the event accessor. The block of an *add_accessor_declaration* or a *remove_accessor_declaration* shall conform to the rules for `void` methods described in §required-partial-methods. In particular, `return` statements in such a block are not permitted to specify an expression. +Each *add_accessor_declaration* and *remove_accessor_declaration* corresponds to a method with a single value parameter of the event type, and a `void` return type. The implicit parameter of an event accessor is named `value`. When an event is used in an event assignment, the appropriate event accessor is used. Specifically, if the assignment operator is `+=` then the add accessor is used, and if the assignment operator is `–=` then the remove accessor is used. In either case, the right operand of the assignment operator is used as the argument to the event accessor. The block of an *add_accessor_declaration* or a *remove_accessor_declaration* shall conform to the rules for `void` methods described in [§15.6.11](classes.md#15611-method-body). In particular, `return` statements in such a block are not permitted to specify an expression. Since an event accessor implicitly has a parameter named `value`, it is a compile-time error for a local variable or constant declared in an event accessor to have that name. From f86b34a6cd2ce538a0a7e6961e421aa0257f1c22 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 15 Jul 2026 15:37:24 -0400 Subject: [PATCH 11/15] Next round of edits - Add that return types must match. - Add rule on type parameter constraints. - Add text for extern implementations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 1bdbec4ad..3d2b62f5f 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2059,13 +2059,13 @@ A ***method*** is a member that implements a computation or action that can be p ```ANTLR method_declaration - : attributes? method_modifiers return_type method_header method_body - | attributes? ref_method_modifiers ref_kind ref_return_type method_header + : attributes? method_modifiers 'partial'? return_type method_header method_body + | attributes? ref_method_modifiers 'partial'? ref_kind ref_return_type method_header ref_method_body ; method_modifiers - : method_modifier* 'partial'? + : method_modifier* ; ref_kind @@ -2074,7 +2074,7 @@ ref_kind ; ref_method_modifiers - : ref_method_modifier* 'partial'? + : ref_method_modifier* ; method_header @@ -3031,19 +3031,20 @@ The mechanism by which linkage to an external method is achieved is implementati When a *method declaration* includes a `partial` modifier, that method is said to be a ***partial method***. Partial methods may only be declared as members of partial types ([§15.2.7](classes.md#1527-partial-type-declarations)). Partial methods may be defined in one part of a type declaration and implemented in another. -In *method_declaration*, the identifier `partial` is recognized as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) only if it immediately precedes the *return_type*. A partial method cannot explicitly implement interface methods. +In *method_declaration*, the identifier `partial` is recognized as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) only if it immediately precedes the *return_type* or *ref_kind*. A partial method cannot explicitly implement interface methods. Partial method declarations are classified as follows: -- A method with an *expression-body* or a *block-body* or is declared with the `extern` modifier is said to be an ***implementing partial method declaration***. +- A method with an *expression-body* or *block-body*, or a method declared with the `extern` modifier, is said to be an ***implementing partial method declaration***. - Otherwise, a method declaration where the body of the method declaration is a semicolon is said to be a ***defining partial method declaration***. Across the parts of a type declaration, there shall be exactly one defining partial method declaration with a given signature. If an implementing partial method declaration is given, a corresponding defining partial method declaration shall exist, and the declarations shall match as specified in the following: - The declarations shall have the same method name, number of type parameters, and number of parameters. - The declarations shall have the same modifiers except for the `async` and `extern` modifiers. The `async` and `extern` modifiers are allowed only on the implementing partial method declaration. +- The declarations shall have the same return type: they shall both return no value, or they shall both return by value or by reference with the same type (modulo differences in type parameter names). If they return by reference, the declarations shall have the same *ref_kind*. - Corresponding parameters in the declarations shall have the same modifiers (although not necessarily in the same order) and the same types (modulo differences in type parameter names). Tuple types (§8.3.11) used as parameters or return types shall have the same item names in both the defining and implementing partial method declarations. -- Corresponding type parameters in the declarations shall have the same constraints. An implementation may choose to issue a warning if the type parameter names are different in the defining and implementing declarations. +- Corresponding type parameters in the declarations, by ordinal position, shall have equivalent constraints after substituting each type parameter of one declaration with the corresponding type parameter of the other declaration. There are two variations of partial methods: required and optional. A ***required partial method*** (§required-partial-methods) is a partial method that includes one or more explicit access modifiers. An ***optional partial method*** (§optional-partial-methods) has no explicit access modifiers, and is implicitly private. From 3b17047c184ac98bbf66efcee38c83fd2aa80337 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 18 Aug 2026 10:40:40 -0400 Subject: [PATCH 12/15] Update for two omissions Review and make two small updates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/basic-concepts.md | 2 +- standard/classes.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/basic-concepts.md b/standard/basic-concepts.md index 715afbdbf..48eac401f 100644 --- a/standard/basic-concepts.md +++ b/standard/basic-concepts.md @@ -35,7 +35,7 @@ A method qualifies as a canditate entry point by satisfying the following requir - It shall be declared in a non-generic type. If the type declaring the method is a nested type, all of its enclosing types shall be non-generic. - The return type shall be `void`, `int`, `System.Threading.Tasks.Task`, or `System.Threading.Tasks.Task`. - If the `async` modifier is present, the method’s return type shall be `System.Threading.Tasks.Task` or `System.Threading.Tasks.Task`. -- It shall not be a partial method ([§15.6.9](classes.md#1569-partial-methods)) without an implementation. +- It shall not be an optional partial method (§optional-partial-methods) without an implementing declaration. - The parameter list shall either be empty, or have a single value parameter of type `string[]`. The declared accessibility ([§7.4.2](basic-concepts.md#742-declared-accessibility)) of a method is ignored for the purposes of qualifying as a candidate entry point. At application startup the selected entry point is invoked regardless of its declared accessibility. However any declared accessibility continues to apply if the selected candidate entry point is invoked after application startup. diff --git a/standard/classes.md b/standard/classes.md index 3d2b62f5f..742bcf3a2 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2248,7 +2248,7 @@ A parameter with a `ref`, `out` or `this` modifier cannot have a *default_argume The *expression* shall be implicitly convertible by an identity or nullable conversion to the type of the parameter. -If optional parameters occur in an implementing partial method declaration ([§15.6.9](classes.md#1569-partial-methods)), an explicit interface member implementation ([§19.6.2](interfaces.md#1962-explicit-interface-member-implementations)), a single-parameter indexer declaration ([§15.9](classes.md#159-indexers)), or in an operator declaration ([§15.10.1](classes.md#15101-general)) a compiler should give a warning, since these members can never be invoked in a way that permits arguments to be omitted. +If optional parameters occur in an implementing partial method declaration, a compiler should give a warning, since any default arguments are removed per §15.6.9. If optional parameters occur in an explicit interface member implementation ([§19.6.2](interfaces.md#1962-explicit-interface-member-implementations)), a single-parameter indexer declaration ([§15.9](classes.md#159-indexers)), or in an operator declaration ([§15.10.1](classes.md#15101-general)) a compiler should give a warning, since these members can never be invoked in a way that permits arguments to be omitted. A *parameter_array* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)), a `params` modifier, an *array_type*, and an *identifier*. A parameter array declares a single parameter of the given array type with the given name. The *array_type* of a parameter array shall be a single-dimensional array type ([§17.2](arrays.md#172-array-types)). In a method invocation, a parameter array permits either a single argument of the given array type to be specified, or it permits zero or more arguments of the array element type to be specified. Parameter arrays are described further in [§15.6.2.4](classes.md#15624-parameter-arrays). From d5d274842e657dfa91102931fc23da685fe306bf Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 13 Oct 2026 15:04:33 -0400 Subject: [PATCH 13/15] Reconcile partial-method entry-point reference with approved C9 heading Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21570b74-c6f5-4fc5-ab6d-7546918d6ddb --- standard/classes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 742bcf3a2..bb56481b4 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -3062,7 +3062,7 @@ For a required partial method both the definition and implementation shall exist > protected partial bool M3(); // required, impl. required > public partial void M4(out int i); // required, impl. required > } -> +> > // part containing implementing partial method declarations > partial class C > { @@ -3202,7 +3202,7 @@ If a defining declaration but not an implementing declaration is given for an op - It is a compile-time error to create a delegate from `M` ([§12.8.17.5](expressions.md#128175-delegate-creation-expressions)). - It is a compile-time error to refer to `M` inside an anonymous function that is converted to an expression tree type ([§8.6](types.md#86-expression-tree-types)). - Expressions occurring as part of an invocation of `M` do not affect the definite assignment state ([§9.4](variables.md#94-definite-assignment)), which can potentially lead to compile-time errors. -- `M` cannot be the entry point for an application ([§7.1](basic-concepts.md#71-application-startup)). +- `M` cannot be the entry point for an application ([§7.1](basic-concepts.md#71-application-startup-and-termination)). #### §required-partial-methods Required partial methods From ab68cee361edefb1f305b34d621816c2f64ee700 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 22 Oct 2026 15:57:43 -0400 Subject: [PATCH 14/15] Apply batched suggestions from code review Co-authored-by: Nigel-Ecma <6654683+Nigel-Ecma@users.noreply.github.com> --- standard/classes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index bb56481b4..58a1a8236 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2059,13 +2059,13 @@ A ***method*** is a member that implements a computation or action that can be p ```ANTLR method_declaration - : attributes? method_modifiers 'partial'? return_type method_header method_body - | attributes? ref_method_modifiers 'partial'? ref_kind ref_return_type method_header + : attributes? method_modifiers return_type method_header method_body + | attributes? ref_method_modifiers ref_kind ref_return_type method_header ref_method_body ; method_modifiers - : method_modifier* + : method_modifier* 'partial'? ; ref_kind @@ -2074,7 +2074,7 @@ ref_kind ; ref_method_modifiers - : ref_method_modifier* + : ref_method_modifier* 'partial'? ; method_header From d7bdea08954254ef547b36e18715af8a2753d9da Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 22 Oct 2026 16:30:34 -0400 Subject: [PATCH 15/15] Respond to remaining feedback. Address the remaining feedback on partial methods --- standard/classes.md | 8 +++++++ .../Samples/v9/More partial methods/ReadMe.md | 4 ++++ .../Samples/v9/More partial methods/sample.cs | 21 +++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 tools/GrammarTesting/Tests/Parsing/Samples/v9/More partial methods/ReadMe.md create mode 100644 tools/GrammarTesting/Tests/Parsing/Samples/v9/More partial methods/sample.cs diff --git a/standard/classes.md b/standard/classes.md index 58a1a8236..a37d1d32d 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -3061,6 +3061,7 @@ For a required partial method both the definition and implementation shall exist > private partial void M2(); // required, impl. required > protected partial bool M3(); // required, impl. required > public partial void M4(out int i); // required, impl. required +> private static partial void M5(); // required, impl. required > } > > // part containing implementing partial method declarations @@ -3069,9 +3070,16 @@ For a required partial method both the definition and implementation shall exist > private partial void M2() { ... } > protected partial bool M3() { ... } > public partial void M4(out int i) { ... } +> +> [System.Runtime.InteropServices.DllImport("NativeLibrary")] +> private static extern partial void M5(); > } > ``` > +> The implementation of `M1` may be omitted. In contrast, `M5` requires an +> implementing declaration, which uses `extern` and has a semicolon rather +> than a block body. +> > *end example* Only a defining partial method participates in overload resolution. diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v9/More partial methods/ReadMe.md b/tools/GrammarTesting/Tests/Parsing/Samples/v9/More partial methods/ReadMe.md new file mode 100644 index 000000000..d2ec092b5 --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v9/More partial methods/ReadMe.md @@ -0,0 +1,4 @@ +# Sample: More partial methods + +Required partial methods returning by reference, including read-only references, +and an external implementing declaration with a semicolon body (§15.6.9). diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v9/More partial methods/sample.cs b/tools/GrammarTesting/Tests/Parsing/Samples/v9/More partial methods/sample.cs new file mode 100644 index 000000000..5587351cd --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v9/More partial methods/sample.cs @@ -0,0 +1,21 @@ +partial class C +{ + private int value; + + public partial ref int M1(); + public partial ref readonly int M2(); + private static partial void M3(); +} + +partial class C +{ + public partial ref int M1() => ref value; + + public partial ref readonly int M2() + { + return ref value; + } + + [System.Runtime.InteropServices.DllImport("NativeLibrary")] + private static extern partial void M3(); +}