Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for extending partial methods #991

Draft
wants to merge 2 commits into
base: draft-v9
Choose a base branch
from

Conversation

RexJaeschke
Copy link
Contributor

No description provided.

@RexJaeschke RexJaeschke added the type: feature This issue describes a new feature label Nov 13, 2023
@RexJaeschke RexJaeschke added this to the C# 9.0 milestone Nov 13, 2023
@RexJaeschke RexJaeschke marked this pull request as draft November 13, 2023 16:07

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

partial seems to be also recognized when it immediately precedes async:

using System.Threading.Tasks;
public partial class C {
    private partial Task M();
    private partial async Task M() {}
}

but I don't know which version of C# this requires.


Methods are classified according to what, if anything, they return:

- If `ref` is present, the method is ***returns-by-ref*** and returns a *variable reference*, that is optionally read-only;
- Otherwise, if *return_type* is `void`, the method is ***returns-no-value*** and does not return a value;
- Otherwise, the method is ***returns-by-value*** and returns a value.

The *return_type* of a returns-by-value or returns-no-value method declaration specifies the type of the result, if any, returned by the method. Only a returns-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 returns-by-value and the return type is a *task type* ([§15.15.1](classes.md#15151-general)).
The *return_type* of a returns-by-value or returns-no-value method declaration specifies the type of the result, if any, returned by the method. Only a returns-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 returns-by-value and the return type is a *task type* ([§15.15.1](classes.md#15151-general)).
Copy link
Contributor

@KalleOlaviNiemitalo KalleOlaviNiemitalo Nov 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert this change; public async int M() { throw null; } should still be disallowed, even though it is not a restricted partial method (nor an unrestricted partial method).

- 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this error specified?

public static partial class C {
    // error CS8796: Partial method 'C.M(out int)' must have accessibility modifiers because it has a non-void return type.
    partial int M(out int p);
    partial int M(out int p) { return p = 0; }
}

@@ -2886,7 +2917,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:
Copy link
Contributor

@KalleOlaviNiemitalo KalleOlaviNiemitalo Nov 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public partial class C {
    static partial void M(int i = 1);
    static partial void M(int j = 2) {}
    
    static void N() {
        // OK, the name of the parameter is "i", not "j".
        M(i: 4);
        
        // Calls M(1).  The default value 2 in the implementing declaration
        // has no effect on this call.
        M();
    }
}


Partial methods shall not define access modifiers; they are implicitly private. Their return type shall be `void`, and their parameters shall not have the `out` modifier. 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 *method_body* 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:
Copy link
Contributor

@KalleOlaviNiemitalo KalleOlaviNiemitalo Nov 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private extern partial void M(); should also be an implementing partial method declaration even though method_body is a semicolon.

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 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:

- The declarations shall have the same modifiers (although not necessarily in the same order), method name, number of type parameters and number of parameters.
- The declarations shall have the same modifiers (although not necessarily in the same order), method name, number of type parameters, and number of parameters.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The async and extern modifiers should disallowed on the defining partial method declaration, but allowed on the implementing partial method declaration, thus not required to match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: feature This issue describes a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants