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 attributes and extern on local functions #994

Draft
wants to merge 4 commits into
base: draft-v9
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion standard/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ A class that is decorated with the `AttributeUsage` attribute shall derive from

#### 22.5.3.1 General

The attribute `Conditional` enables the definition of ***conditional methods*** and ***conditional attribute classes***.
The attribute `Conditional` enables the definition of ***conditional methods***, ***conditional local functions***, and ***conditional attribute classes***.

#### 22.5.3.2 Conditional methods

Expand Down Expand Up @@ -688,6 +688,12 @@ The use of conditional methods in an inheritance chain can be confusing. Calls m
>
> *end example*

#### §conditional-local-function Conditional local functions

A local function may be made conditional in the same sense as a conditional method ([§22.5.3.2](attributes.md#22532-conditional-methods)).

A conditional local function shall have the modifier `static`.

#### 22.5.3.3 Conditional attribute classes

An attribute class ([§22.2](attributes.md#222-attribute-classes)) decorated with one or more `Conditional` attributes is a conditional attribute class. A conditional attribute class is thus associated with the conditional compilation symbols declared in its `Conditional` attributes.
Expand Down Expand Up @@ -852,6 +858,39 @@ For invocations that occur within field or event initializers, the member name u

For invocations that occur within declarations of instance constructors, static constructors, finalizers and operators the member name used is implementation-dependent.

> *Example*: Consider the following:
>
> <!-- Example: {template:"standalone-console", name:"CallerMemberName1", inferOutput:true} -->
> ```csharp
> class Program
> {
> static void Main()
> {
> F1();
>
> void F1([CallerMemberName] string? name = null)
> {
> Console.WriteLine($"F1 MemberName: |{name}|");
> F2();
> }
>
> static void F2([CallerMemberName] string? name = null)
> {
> Console.WriteLine($"F2 MemberName: |{name}|");
> }
> }
> }
> ```
>
> which produces the output
>
> ```console
> F1 MemberName: |Main|
> F2 MemberName: |Main|
> ```
>
> This attribute supplies the name of the calling function member, which for local function `F1` is the method `Main`. And even though `F2` is called by `F1`, a local function is *not* a function member, so the reported caller of `F2` is also `Main`. *end example*

## 22.6 Attributes for interoperation

For interoperation with other languages, an indexer may be implemented using indexed properties. If no `IndexerName` attribute is present for an indexer, then the name `Item` is used by default. The `IndexerName` attribute enables a developer to override this default and specify a different name.
Expand Down
19 changes: 13 additions & 6 deletions standard/statements.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,15 +487,15 @@ A *local_function_declaration* declares a local function.

```ANTLR
local_function_declaration
: local_function_modifier* return_type local_function_header
: attributes? local_function_modifier* return_type local_function_header
local_function_body
| ref_local_function_modifier* ref_kind ref_return_type
| attributes? ref_local_function_modifier* ref_kind ref_return_type
local_function_header ref_local_function_body
;

local_function_header
: identifier '(' formal_parameter_list? ')'
| identifier type_parameter_list '(' formal_parameter_list? ')'
: identifier parameter_list?
| identifier type_parameter_list parameter_list?
type_parameter_constraints_clause*
;

Expand All @@ -505,18 +505,21 @@ local_function_modifier
;

ref_local_function_modifier
: unsafe_modifier // unsafe code support
: 'extern'
| unsafe_modifier // unsafe code support
;

local_function_body
: block
| '=>' null_conditional_invocation_expression ';'
| '=>' expression ';'
| ';'
;

ref_local_function_body
: block
| '=>' 'ref' variable_reference ';'
| ';'
;
```

Expand Down Expand Up @@ -561,7 +564,11 @@ Unless specified otherwise below, the semantics of all grammar elements is the s

The *identifier* of a *local_function_declaration* must be unique in its declared block scope, including any enclosing local variable declaration spaces. One consequence of this is that overloaded *local_function_declaration*s are not allowed.

A *local_function_declaration* may include one `async` ([§15.15](classes.md#1515-async-functions)) modifier and one `unsafe` ([§23.1](unsafe-code.md#231-general)) modifier. If the declaration includes the `async` modifier then the return type shall be `void` or a `«TaskType»` type ([§15.15.1](classes.md#15151-general)). The `unsafe` modifier uses the containing lexical scope. The `async` modifier does not use the containing lexical scope. It is a compile-time error for *type_parameter_list* or *formal_parameter_list* to contain *attributes*.
A *local_function_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)), one `async` ([§15.15](classes.md#1515-async-functions)) modifier, one `extern` ([§15.6.8](classes.md#1568-external-methods)) modifier, and one `unsafe` ([§23.1](unsafe-code.md#231-general)) modifier. If the declaration includes the `async` modifier then the return type shall be `void` or a `«TaskType»` type ([§15.15.1](classes.md#15151-general)). The `unsafe` modifier uses the containing lexical scope. The `async` modifier does not use the containing lexical scope.

An external local function shall have the modifier `static`, and its *local_function_body* or *ref_local_function_body* shall be a semicolon.

A *local_function_body* or *ref_local_function_body* shall be a semicolon only for an external local function.

A local function is declared at block scope, and that function may capture variables from the enclosing scopes. It is a compile-time error if a captured variable is read by the body of the local function but is not definitely assigned before each call to the function. The compiler shall determine which variables are definitely assigned on return ([§9.4.4.33](variables.md#94433-rules-for-variables-in-local-functions)).

Expand Down
Loading