From 692c320d011277d78fa3b079066a575aa1cd67e1 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 19 Nov 2023 10:24:31 -0500 Subject: [PATCH 01/13] Add support for attributes and extern on local functions Add support for attributes and extern on local functions fix md formatting --- standard/attributes.md | 8 +++++++- standard/statements.md | 17 ++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/standard/attributes.md b/standard/attributes.md index 730fb4ab3..ec2054a51 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -513,7 +513,7 @@ A class that is decorated with the `AttributeUsage` attribute shall derive from #### 23.5.3.1 General -The attribute `Conditional` enables the definition of ***conditional method***s and ***conditional attribute class***es. +The attribute `Conditional` enables the definition of ***conditional methods***, ***conditional local function***s, and ***conditional attribute class***es. #### 23.5.3.2 Conditional methods @@ -667,6 +667,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 ([§23.5.3.2](attributes.md#23532-conditional-methods)). + +A conditional local function shall have the modifier `static`. + #### 23.5.3.3 Conditional attribute classes An attribute class ([§23.2](attributes.md#232-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. diff --git a/standard/statements.md b/standard/statements.md index 4ef8a18e3..bcdb511be 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -486,15 +486,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 '(' parameter_list? ')' - | identifier type_parameter_list '(' parameter_list? ')' + : identifier parameter_list? + | identifier type_parameter_list parameter_list? type_parameter_constraints_clause* ; @@ -505,6 +505,7 @@ local_function_modifier ref_local_function_modifier : 'static' + | 'extern' | unsafe_modifier // unsafe code support ; @@ -512,11 +513,13 @@ local_function_body : block | '=>' null_conditional_invocation_expression ';' | '=>' expression ';' + | ';' ; ref_local_function_body : block | '=>' 'ref' variable_reference ';' + | ';' ; ``` @@ -561,7 +564,11 @@ Unless specified otherwise below, the semantics of all grammar elements is the s The *identifier* of a *local_function_declaration* shall 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.14](classes.md#1514-async-functions)) modifier and one `unsafe` ([§24.1](unsafe-code.md#241-general)) modifier. If the declaration includes the `async` modifier then the return type shall be `void` or a `«TaskType»` type ([§15.14.1](classes.md#15141-general)). If the declaration includes the `static` modifier, the function is a ***static local function***; otherwise, it is a ***non-static local function***. It is a compile-time error for *type_parameter_list* or *parameter_list* to contain *attributes*. If the local function is declared in an unsafe context ([§24.2](unsafe-code.md#242-unsafe-contexts)), the local function may include unsafe code, even if the local function declaration does not include the `unsafe` modifier. +A *local_function_declaration* may include one `async` ([§15.14](classes.md#1514-async-functions)) modifier and one `unsafe` ([§24.1](unsafe-code.md#241-general)) modifier. If the declaration includes the `async` modifier then the return type shall be `void` or a `«TaskType»` type ([§15.14.1](classes.md#15141-general)). If the declaration includes the `static` modifier, the function is a ***static local function***; otherwise, it is a ***non-static local function***. If the local function is declared in an unsafe context ([§24.2](unsafe-code.md#242-unsafe-contexts)), the local function may include unsafe code, even if the local function declaration doesn’t include the `unsafe` modifier. + +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. A non-static local function may capture variables from the enclosing scope while a static local function shall not (so it has no access to enclosing locals, parameters, non-static local functions, or `this`). It is a compile-time error if a captured variable is read by the body of a non-static local function but is not definitely assigned before each call to the function. A compiler shall determine which variables are definitely assigned on return ([§9.4.4.33](variables.md#94433-rules-for-variables-in-local-functions)). From 5574353f5be6c8a3976cffd85f49b5cdf5fdaf95 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Fri, 14 Nov 2025 10:45:47 -0500 Subject: [PATCH 02/13] restore parens --- standard/statements.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/statements.md b/standard/statements.md index bcdb511be..bd0fbd311 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -493,8 +493,8 @@ local_function_declaration ; local_function_header - : identifier parameter_list? - | identifier type_parameter_list parameter_list? + : identifier '(' parameter_list? ')' + | identifier type_parameter_list '(' parameter_list? ')' type_parameter_constraints_clause* ; From 1d2161e0b52f0bf3ab7d21a78dfd7c94bb2e37df Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Fri, 14 Nov 2025 10:52:35 -0500 Subject: [PATCH 03/13] add new text re local functions --- standard/attributes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/standard/attributes.md b/standard/attributes.md index ec2054a51..4573f06f5 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -842,6 +842,8 @@ 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. +For an invocation that occurs within a local function, the name of the method that calls that local function is used. Consider the following: if method `M` calls local function `F1`, which in turn calls local function `F2`, and `F2` has a parameter marked with this attribute, the method name passed to `F2` is `M`, because a local function is *not* a function member! + ### 23.5.7 Code analysis attributes #### 23.5.7.1 General From 8fbdc6582af3939c52c95f7495de82a68277dd86 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Fri, 14 Nov 2025 10:58:17 -0500 Subject: [PATCH 04/13] fix md --- standard/attributes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/attributes.md b/standard/attributes.md index 4573f06f5..e3644e067 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -842,7 +842,7 @@ 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. -For an invocation that occurs within a local function, the name of the method that calls that local function is used. Consider the following: if method `M` calls local function `F1`, which in turn calls local function `F2`, and `F2` has a parameter marked with this attribute, the method name passed to `F2` is `M`, because a local function is *not* a function member! +For an invocation that occurs within a local function, the name of the method that calls that local function is used. Consider the following: if method `M` calls local function `F1`, which in turn calls local function `F2`, and `F2` has a parameter marked with this attribute, the method name passed to `F2` is `M`, because a local function is *not* a function member! ### 23.5.7 Code analysis attributes From 33a1f03f09824a80cfc2f5b2ffa51273c1a3dc0e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 6 Jan 2026 13:20:40 -0500 Subject: [PATCH 05/13] Small wording edits This is now ready for committee review. --- standard/attributes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/standard/attributes.md b/standard/attributes.md index e3644e067..cf296e044 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -669,9 +669,9 @@ The use of conditional methods in an inheritance chain can be confusing. Calls m #### §conditional-local-function Conditional local functions -A local function may be made conditional in the same sense as a conditional method ([§23.5.3.2](attributes.md#23532-conditional-methods)). +A static local function may be made conditional in the same sense as a conditional method ([§23.5.3.2](attributes.md#23532-conditional-methods)). -A conditional local function shall have the modifier `static`. +A compile time error ocurrs if a non-static local function is made conditional. #### 23.5.3.3 Conditional attribute classes @@ -842,7 +842,7 @@ 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. -For an invocation that occurs within a local function, the name of the method that calls that local function is used. Consider the following: if method `M` calls local function `F1`, which in turn calls local function `F2`, and `F2` has a parameter marked with this attribute, the method name passed to `F2` is `M`, because a local function is *not* a function member! +For an invocation that occurs within a local function, the name of the member method that calls that local function is used. Consider the following: if member method `M` calls local function `F1`, which in turn calls local function `F2`, and `F2` has a parameter marked with this attribute, the method name passed to `F2` is `M`, because a local function is *not* a function member! ### 23.5.7 Code analysis attributes From 61bd38ccb32d9aa0e8b5220cde570d9cb3442ec4 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 29 Jan 2026 10:35:56 -0500 Subject: [PATCH 06/13] Apply suggestions from code review Co-authored-by: Joseph Musser --- standard/attributes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/attributes.md b/standard/attributes.md index cf296e044..ba25fbc13 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -513,7 +513,7 @@ A class that is decorated with the `AttributeUsage` attribute shall derive from #### 23.5.3.1 General -The attribute `Conditional` enables the definition of ***conditional methods***, ***conditional local function***s, and ***conditional attribute class***es. +The attribute `Conditional` enables the definition of ***conditional method***s, ***conditional local function***s, and ***conditional attribute class***es. #### 23.5.3.2 Conditional methods @@ -671,7 +671,7 @@ The use of conditional methods in an inheritance chain can be confusing. Calls m A static local function may be made conditional in the same sense as a conditional method ([§23.5.3.2](attributes.md#23532-conditional-methods)). -A compile time error ocurrs if a non-static local function is made conditional. +A compile time error occurs if a non-static local function is made conditional. #### 23.5.3.3 Conditional attribute classes From 3e9e2b7b4188ff1dddf5ceb6e20f56196cd8e4c4 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Thu, 29 Jan 2026 10:38:49 -0500 Subject: [PATCH 07/13] restore example (#1548) --- standard/attributes.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/standard/attributes.md b/standard/attributes.md index ba25fbc13..1027e1957 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -842,7 +842,38 @@ 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. -For an invocation that occurs within a local function, the name of the member method that calls that local function is used. Consider the following: if member method `M` calls local function `F1`, which in turn calls local function `F2`, and `F2` has a parameter marked with this attribute, the method name passed to `F2` is `M`, because a local function is *not* a function member! +> *Example*: Consider the following: +> +> +> ```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* ### 23.5.7 Code analysis attributes From 546e37f28e72b50a9eb0bfbf1159e36543344846 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 29 Jan 2026 11:00:53 -0500 Subject: [PATCH 08/13] Address remaining issues. --- standard/attributes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/standard/attributes.md b/standard/attributes.md index 1027e1957..46ea209c9 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -673,6 +673,8 @@ A static local function may be made conditional in the same sense as a condition A compile time error occurs if a non-static local function is made conditional. +> *Note*: This restriction protects against side-effects for non-static local functions that write to captured outer variables. *end note* + #### 23.5.3.3 Conditional attribute classes An attribute class ([§23.2](attributes.md#232-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. @@ -842,6 +844,8 @@ 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. +For an invocation that occurs within a local function or an anonymous function, the name of the member method that calls that function is used. + > *Example*: Consider the following: > > From c31e41d4d848ed5b0245a2f414f4881a0f538f91 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 25 Feb 2026 15:04:12 -0500 Subject: [PATCH 09/13] remove note. --- standard/attributes.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/standard/attributes.md b/standard/attributes.md index 46ea209c9..7ff3b0c08 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -673,8 +673,6 @@ A static local function may be made conditional in the same sense as a condition A compile time error occurs if a non-static local function is made conditional. -> *Note*: This restriction protects against side-effects for non-static local functions that write to captured outer variables. *end note* - #### 23.5.3.3 Conditional attribute classes An attribute class ([§23.2](attributes.md#232-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. From b5f89a5b536fc3763ad8040342195516579fcdd5 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 25 Feb 2026 15:26:07 -0500 Subject: [PATCH 10/13] Found additional locations to update There were a few additional changes necessary for attributes on local functions. --- standard/attributes.md | 11 +++++++---- standard/variables.md | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/standard/attributes.md b/standard/attributes.md index 7ff3b0c08..743644302 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -156,7 +156,7 @@ The types of positional and named parameters for an attribute class are limited ## 23.3 Attribute specification -Application of a previously defined attribute to a program entity is called ***attribute specification***. An attribute is a piece of additional declarative information that is specified for a program entity. Attributes can be specified at global scope (to specify attributes on the containing assembly or module) and for *type_declaration*s ([§14.7](namespaces.md#147-type-declarations)), *class_member_declaration*s ([§15.3](classes.md#153-class-members)), *interface_member_declaration*s ([§19.4](interfaces.md#194-interface-members)), *struct_member_declaration*s ([§16.3](structs.md#163-struct-members)), *enum_member_declaration*s ([§20.2](enums.md#202-enum-declarations)), *accessor_declaration*s ([§15.7.3](classes.md#1573-accessors)), *event_accessor_declaration*s ([§15.8](classes.md#158-events)), elements of *parameter_list*s ([§15.6.2](classes.md#1562-method-parameters)), and elements of *type_parameter_list*s ([§15.2.3](classes.md#1523-type-parameters)). +Application of a previously defined attribute to a program entity is called ***attribute specification***. An attribute is a piece of additional declarative information that is specified for a program entity. Attributes can be specified at global scope (to specify attributes on the containing assembly or module) and for *type_declaration*s ([§14.7](namespaces.md#147-type-declarations)), *class_member_declaration*s ([§15.3](classes.md#153-class-members)), *interface_member_declaration*s ([§19.4](interfaces.md#194-interface-members)), *struct_member_declaration*s ([§16.3](structs.md#163-struct-members)), *enum_member_declaration*s ([§20.2](enums.md#202-enum-declarations)), *accessor_declaration*s ([§15.7.3](classes.md#1573-accessors)), *event_accessor_declaration*s ([§15.8](classes.md#158-events)), *local_function_declaration*s ([§13.6.4](statements.md#1364-local-function-declarations)), elements of *parameter_list*s ([§15.6.2](classes.md#1562-method-parameters)), and elements of *type_parameter_list*s ([§15.2.3](classes.md#1523-type-parameters)). Attributes are specified in ***attribute section***s. An attribute section consists of a pair of square brackets, which surround a comma-separated list of one or more attributes. The order in which attributes are specified in such a list, and the order in which sections attached to the same program entity are arranged, is not significant. For instance, the attribute specifications `[A][B]`, `[B][A]`, `[A, B]`, and `[B, A]` are equivalent. @@ -252,10 +252,10 @@ The standardized *attribute_target* names are `event`, `field`, `method`, `param - `event` — an event. - `field` — a field. A field-like event (i.e., one without accessors) ([§15.8.2](classes.md#1582-field-like-events)) and an automatically implemented property ([§15.7.4](classes.md#1574-automatically-implemented-properties)) can also have an attribute with this target. -- `method` — a constructor, finalizer, method, operator, property get and set accessors, indexer get and set accessors, and event add and remove accessors. A field-like event (i.e., one without accessors) can also have an attribute with this target. -- `param` — a property set accessor, an indexer set accessor, event add and remove accessors, and a parameter in a constructor, method, and operator. +- `method` — a constructor, finalizer, method, local function, operator, property get and set accessors, indexer get and set accessors, and event add and remove accessors. A field-like event (i.e., one without accessors) can also have an attribute with this target. +- `param` — a property set accessor, an indexer set accessor, event add and remove accessors, and a parameter in a constructor, method, local function, and operator. - `property` — a property and an indexer. -- `return` — a delegate, method, operator, property get accessor, and indexer get accessor. +- `return` — a delegate, method, local function, operator, property get accessor, and indexer get accessor. - `type` — a delegate, class, struct, enum, and interface. - `typevar` — a type parameter. @@ -267,6 +267,9 @@ Certain contexts permit the specification of an attribute on more than one targe - For an attribute on a method declaration the default target is the method. Otherwise when the *attribute_target* is equal to: - `method` — the target is the method - `return` — the target is the return value +- For an attribute on a local function declaration the default target is the local function. Otherwise when the *attribute_target* is equal to: + - `method` — the target is the local function + - `return` — the target is the return value - For an attribute on an operator declaration the default target is the operator. Otherwise when the *attribute_target* is equal to: - `method` — the target is the operator - `return` — the target is the return value diff --git a/standard/variables.md b/standard/variables.md index afefc2726..c14ee9b5e 100644 --- a/standard/variables.md +++ b/standard/variables.md @@ -681,7 +681,7 @@ For an expression *expr*, which has subexpressions *expr₁*, *expr₂*, …, *e #### 9.4.4.24 Invocation expressions and object creation expressions -If the method to be invoked is a partial method that has no implementing partial method declaration, or is a conditional method for which the call is omitted ([§23.5.3.2](attributes.md#23532-conditional-methods)), then the definite-assignment state of *v* after the invocation is the same as the definite-assignment state of *v* before the invocation. Otherwise the following rules apply: +If the method to be invoked is a partial method that has no implementing partial method declaration, or is a conditional method or conditional local function for which the call is omitted ([§23.5.3.2](attributes.md#23532-conditional-methods), [§conditional-local-function](attributes.md#conditional-local-function)), then the definite-assignment state of *v* after the invocation is the same as the definite-assignment state of *v* before the invocation. Otherwise the following rules apply: For an invocation expression *expr* of the form: From bc9ef6ce1151a09682f7d6b45e8ea2b8530aa34e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 25 Feb 2026 15:39:48 -0500 Subject: [PATCH 11/13] Apply suggestion from @BillWagner --- standard/variables.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/variables.md b/standard/variables.md index c14ee9b5e..68ff994e9 100644 --- a/standard/variables.md +++ b/standard/variables.md @@ -681,7 +681,7 @@ For an expression *expr*, which has subexpressions *expr₁*, *expr₂*, …, *e #### 9.4.4.24 Invocation expressions and object creation expressions -If the method to be invoked is a partial method that has no implementing partial method declaration, or is a conditional method or conditional local function for which the call is omitted ([§23.5.3.2](attributes.md#23532-conditional-methods), [§conditional-local-function](attributes.md#conditional-local-function)), then the definite-assignment state of *v* after the invocation is the same as the definite-assignment state of *v* before the invocation. Otherwise the following rules apply: +If the method to be invoked is a partial method that has no implementing partial method declaration, or is a conditional method or conditional local function for which the call is omitted ([§23.5.3.2](attributes.md#23532-conditional-methods), §conditional-local-function), then the definite-assignment state of *v* after the invocation is the same as the definite-assignment state of *v* before the invocation. Otherwise the following rules apply: For an invocation expression *expr* of the form: From f1326aaff6e5506cbbe2725bd90ca94ed51801d5 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 15 Jul 2026 13:38:59 -0400 Subject: [PATCH 12/13] Add lambda example addresses https://github.com/dotnet/csharpstandard/pull/1466#pullrequestreview-4598113214 extend the example to include a lambda expression expansion. --- standard/attributes.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/standard/attributes.md b/standard/attributes.md index 743644302..ad3ed32cc 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -856,6 +856,8 @@ For an invocation that occurs within a local function or an anonymous function, > static void Main() > { > F1(); +> Action anonymousFunction = () => F2(); +> anonymousFunction(); > > void F1([CallerMemberName] string? name = null) > { @@ -876,9 +878,10 @@ For an invocation that occurs within a local function or an anonymous function, > ```console > F1 MemberName: |Main| > F2 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* +> 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 that invocation of `F2` is also `Main`. Similarly, when `F2` is called by the anonymous function assigned to `anonymousFunction`, the reported caller is the method `Main`, which calls that anonymous function. *end example* ### 23.5.7 Code analysis attributes From 7ded0f55aed3217bec9050f094d2c17cdb1ea9e7 Mon Sep 17 00:00:00 2001 From: Nigel-Ecma Date: Sat, 11 Jul 2026 09:35:28 +1200 Subject: [PATCH 13/13] Add sample for PR#1466 --- .../Attributes on Local Functions/ReadMe.md | 3 + .../Reference/sample.gruntree.red.txt | 0 .../Reference/sample.stderr.txt | 0 .../Reference/sample.tokens.txt | 78 + .../Reference/sample.tree.red.txt | 1 + .../Reference/sample.tree.svg | 1625 +++++++++++++++++ .../_Sample_Options.txt | 1 + .../Attributes on Local Functions/sample.cs | 20 + 8 files changed, 1728 insertions(+) create mode 100644 tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/ReadMe.md create mode 100644 tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.gruntree.red.txt create mode 100644 tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.stderr.txt create mode 100644 tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tokens.txt create mode 100644 tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tree.red.txt create mode 100644 tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tree.svg create mode 100644 tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/_Sample_Options.txt create mode 100644 tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/sample.cs diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/ReadMe.md b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/ReadMe.md new file mode 100644 index 000000000..9e85aeeb4 --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/ReadMe.md @@ -0,0 +1,3 @@ +# Sample: Attributes on Local Functions + +This is taken from §23.5.6.4 The CallerMemberName attribute diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.gruntree.red.txt b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.gruntree.red.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.stderr.txt b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tokens.txt b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tokens.txt new file mode 100644 index 000000000..1221ecd6d --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tokens.txt @@ -0,0 +1,78 @@ +[@0,0:4='using',<'using'>,1:0] +[@1,6:11='System',,1:6] +[@2,12:12=';',<';'>,1:12] +[@3,15:19='class',<'class'>,3:0] +[@4,21:27='Program',,3:6] +[@5,29:29='{',<'{'>,4:0] +[@6,35:40='static',<'static'>,5:4] +[@7,42:45='void',<'void'>,5:11] +[@8,47:50='Main',,5:16] +[@9,51:51='(',<'('>,5:20] +[@10,52:52=')',<')'>,5:21] +[@11,58:58='{',<'{'>,6:4] +[@12,68:69='F1',,7:8] +[@13,70:70='(',<'('>,7:10] +[@14,71:71=')',<')'>,7:11] +[@15,72:72=';',<';'>,7:12] +[@16,83:86='void',<'void'>,9:8] +[@17,88:89='F1',,9:13] +[@18,90:90='(',<'('>,9:15] +[@19,91:91='[',<'['>,9:16] +[@20,92:107='CallerMemberName',,9:17] +[@21,108:108=']',<']'>,9:33] +[@22,110:115='string',<'string'>,9:35] +[@23,116:116='?',<'?'>,9:41] +[@24,118:121='name',,9:43] +[@25,123:123='=',<'='>,9:48] +[@26,125:128='null',<'null'>,9:50] +[@27,129:129=')',<')'>,9:54] +[@28,139:139='{',<'{'>,10:8] +[@29,153:159='Console',,11:12] +[@30,160:160='.',<'.'>,11:19] +[@31,161:169='WriteLine',,11:20] +[@32,170:170='(',<'('>,11:29] +[@33,171:172='〔$"〕',,11:30] +[@34,173:188='〔F1 MemberName: |〕',,11:32] +[@35,189:189='{',<'{'>,11:48] +[@36,190:193='name',,11:49] +[@37,194:194='}',<'}'>,11:53] +[@38,195:195='〔|〕',,11:54] +[@39,196:196='〔"〕',,11:55] +[@40,197:197=')',<')'>,11:56] +[@41,198:198=';',<';'>,11:57] +[@42,212:213='F2',,12:12] +[@43,214:214='(',<'('>,12:14] +[@44,215:215=')',<')'>,12:15] +[@45,216:216=';',<';'>,12:16] +[@46,226:226='}',<'}'>,13:8] +[@47,237:242='static',<'static'>,15:8] +[@48,244:247='void',<'void'>,15:15] +[@49,249:250='F2',,15:20] +[@50,251:251='(',<'('>,15:22] +[@51,252:252='[',<'['>,15:23] +[@52,253:268='CallerMemberName',,15:24] +[@53,269:269=']',<']'>,15:40] +[@54,271:276='string',<'string'>,15:42] +[@55,277:277='?',<'?'>,15:48] +[@56,279:282='name',,15:50] +[@57,284:284='=',<'='>,15:55] +[@58,286:289='null',<'null'>,15:57] +[@59,290:290=')',<')'>,15:61] +[@60,300:300='{',<'{'>,16:8] +[@61,314:320='Console',,17:12] +[@62,321:321='.',<'.'>,17:19] +[@63,322:330='WriteLine',,17:20] +[@64,331:331='(',<'('>,17:29] +[@65,332:333='〔$"〕',,17:30] +[@66,334:349='〔F2 MemberName: |〕',,17:32] +[@67,350:350='{',<'{'>,17:48] +[@68,351:354='name',,17:49] +[@69,355:355='}',<'}'>,17:53] +[@70,356:356='〔|〕',,17:54] +[@71,357:357='〔"〕',,17:55] +[@72,358:358=')',<')'>,17:56] +[@73,359:359=';',<';'>,17:57] +[@74,369:369='}',<'}'>,18:8] +[@75,375:375='}',<'}'>,19:4] +[@76,377:377='}',<'}'>,20:0] +[@77,378:377='',,20:1] diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tree.red.txt b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tree.red.txt new file mode 100644 index 000000000..f231680ba --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tree.red.txt @@ -0,0 +1 @@ +(prog (compilation_unit (using_directive (using_namespace_directive using (namespace_name (identifier System)) ;)) (namespace_member_declaration (class_declaration class (identifier Program) (class_body { (class_member_declaration (method_declaration (method_modifiers (ref_method_modifier static)) (return_type void) (method_header (member_name (identifier Main)) ( )) (method_body (block { (statement_list (statement (expression_statement (statement_expression (invocation_expression (primary_expression (identifier F1)) ( ))) ;)) (statement (local_function_declaration (return_type void) (local_function_header (identifier F1) ( (parameter_list (fixed_parameter (attributes (attribute_section [ (attribute_list (identifier CallerMemberName)) ])) (type (nullable_reference_type (non_nullable_reference_type (class_type string)) (nullable_type_annotation ?))) (identifier name) (default_argument = (expression (null_literal null))))) )) (local_function_body (block { (statement_list (statement (expression_statement (statement_expression (invocation_expression (primary_expression (member_access (primary_expression (identifier Console)) . (identifier WriteLine))) ( (argument_list (interpolated_regular_string_expression 〔$"〕 〔F1 MemberName: |〕 { (regular_interpolation (identifier name)) } 〔|〕 〔"〕)) ))) ;)) (statement (expression_statement (statement_expression (invocation_expression (primary_expression (identifier F2)) ( ))) ;))) })))) (statement (local_function_declaration (local_function_modifier (ref_local_function_modifier static)) (return_type void) (local_function_header (identifier F2) ( (parameter_list (fixed_parameter (attributes (attribute_section [ (attribute_list (identifier CallerMemberName)) ])) (type (nullable_reference_type (non_nullable_reference_type (class_type string)) (nullable_type_annotation ?))) (identifier name) (default_argument = (expression (null_literal null))))) )) (local_function_body (block { (statement_list (expression_statement (statement_expression (invocation_expression (primary_expression (member_access (primary_expression (identifier Console)) . (identifier WriteLine))) ( (argument_list (interpolated_regular_string_expression 〔$"〕 〔F2 MemberName: |〕 { (regular_interpolation (identifier name)) } 〔|〕 〔"〕)) ))) ;)) }))))) })))) }))))) diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tree.svg b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tree.svg new file mode 100644 index 000000000..468c0202a --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/Reference/sample.tree.svg @@ -0,0 +1,1625 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +local_function_declaration + + + +conditional_expression + + + +conditional_expression + + + +[ + + + +name + + + +method_header + + + +nullable_reference_type + + + +statement_expression + + + +. + + + +conditional_or_expression + + + +relational_expression + + + +interpolated_regular_string_expression + + + +range_expression + + + +〔"〕 + + + +member_access + + + +invocation_expression + + + +identifier + + + +nullable_type_annotation + + + +declaration_statement + + + +expression + + + +attribute_section + + + +shift_expression + + + +〔F2·MemberName:·|〕 + + + +expression_statement + + + +( + + + +class_type + + + +attribute + + + +exclusive_or_expression + + + +null + + + +{ + + + +attribute_list + + + +switch_expression + + + +type + + + +type + + + +〔$"〕 + + + +ref_method_modifier + + + +statement_list + + + +reference_type + + + +null_coalescing_expression + + + +primary_expression + + + +member_access + + + +parameter_list + + + +default_argument + + + +identifier + + + +statement_list + + + +attribute + + + +unary_expression + + + +) + + + +method_modifiers + + + +class_body + + + +non_assignment_expression + + + +inclusive_or_expression + + + +multiplicative_expression + + + +identifier + + + +regular_interpolation + + + +class_declaration + + + +( + + + +exclusive_or_expression + + + +conditional_or_expression + + + +simple_name + + + +Console + + + +range_expression + + + +regular_interpolation + + + +} + + + +conditional_and_expression + + + +expression_statement + + + +primary_expression + + + +non_assignment_expression + + + +void + + + +literal + + + +exclusive_or_expression + + + +Program + + + +nullable_type_annotation + + + +attribute_list + + + +equality_expression + + + +null_literal + + + +reference_type + + + +fixed_parameters + + + +non_nullable_reference_type + + + +method_modifier + + + +embedded_statement + + + +attributes + + + +CallerMemberName + + + +static + + + +unary_expression + + + +System + + + +) + + + +method_body + + + +primary_expression + + + +〔F1·MemberName:·|〕 + + + +local_function_header + + + +CallerMemberName + + + +return_type + + + +expression_statement + + + +relational_expression + + + +primary_expression + + + +) + + + +〔"〕 + + + +) + + + +name + + + +unary_expression + + + +inclusive_or_expression + + + +identifier + + + +primary_expression + + + +identifier + + + +unary_expression + + + +namespace_or_type_name + + + +shift_expression + + + +shift_expression + + + +statement + + + +null_coalescing_expression + + + +additive_expression + + + +declaration_statement + + + +) + + + +. + + + +additive_expression + + + +simple_name + + + +expression + + + +conditional_expression + + + +expression + + + +additive_expression + + + +return_type + + + +equality_expression + + + +conditional_and_expression + + + +; + + + +) + + + +block + + + +equality_expression + + + +conditional_expression + + + +conditional_and_expression + + + +local_function_declaration + + + +attribute_name + + + +statement_expression + + + +conditional_or_expression + + + +string + + + +switch_expression + + + +statement_list + + + +argument_value + + + +relational_expression + + + +equality_expression + + + +additive_expression + + + +argument_value + + + +fixed_parameter + + + +identifier + + + +〔|〕 + + + +non_assignment_expression + + + +null_coalescing_expression + + + +( + + + +invocation_expression + + + +and_expression + + + +primary_expression + + + +argument_list + + + +unary_expression + + + +interpolated_string_expression + + + +compilation_unit + + + +conditional_expression + + + +relational_expression + + + +and_expression + + + +null_coalescing_expression + + + +{ + + + +primary_expression + + + +namespace_member_declaration + + + +and_expression + + + +relational_expression + + + +F2 + + + +block + + + +simple_name + + + +additive_expression + + + +statement + + + +simple_name + + + +prog + + + +exclusive_or_expression + + + +identifier + + + +type_declaration + + + +expression + + + +namespace_or_type_name + + + +non_assignment_expression + + + +statement + + + +identifier + + + +expression_statement + + + +interpolated_regular_string_expression + + + +local_function_modifier + + + +range_expression + + + +range_expression + + + +( + + + +conditional_and_expression + + + +identifier + + + +multiplicative_expression + + + +F1 + + + +embedded_statement + + + +and_expression + + + +} + + + +primary_expression + + + +invocation_expression + + + +simple_name + + + +switch_expression + + + +( + + + +] + + + +statement_expression + + + +shift_expression + + + +using + + + +non_assignment_expression + + + +fixed_parameters + + + +conditional_or_expression + + + +interpolated_string_expression + + + +attributes + + + +argument + + + +inclusive_or_expression + + + +conditional_and_expression + + + +expression + + + +primary_expression + + + +return_type + + + +( + + + +} + + + +string + + + +Main + + + +default_argument + + + +static + + + +method_declaration + + + +equality_expression + + + +{ + + + +primary_expression + + + +statement + + + +type_name + + + +〔$"〕 + + + +{ + + + +invocation_expression + + + +? + + + +multiplicative_expression + + + +literal + + + +parameter_list + + + +conditional_and_expression + + + +multiplicative_expression + + + +null_coalescing_expression + + + +) + + + +statement + + + +[ + + + +local_function_body + + + +null + + + +block + + + +non_assignment_expression + + + +member_name + + + +shift_expression + + + +statement_expression + + + +} + + + +] + + + +type_name + + + +attribute_section + + + +〔|〕 + + + +; + + + +} + + + +; + + + +unary_expression + + + +and_expression + + + +} + + + +and_expression + + + +WriteLine + + + +attribute_name + + + +? + + + +conditional_expression + + + +conditional_or_expression + + + +range_expression + + + +namespace_or_type_name + + + +identifier + + + +F1 + + + +identifier + + + +fixed_parameter + + + +range_expression + + + +{ + + + +ref_local_function_modifier + + + +simple_name + + + +argument + + + +switch_expression + + + +primary_expression + + + +equality_expression + + + +class_member_declaration + + + +non_nullable_reference_type + + + +using_directive + + + +conditional_or_expression + + + +identifier + + + +embedded_statement + + + +expression + + + +null_coalescing_expression + + + +identifier + + + +void + + + +multiplicative_expression + + + +switch_expression + + + +name + + + +name + + + +inclusive_or_expression + + + +; + + + +identifier + + + += + + + +exclusive_or_expression + + + +identifier + + + +local_function_header + + + +class_type + + + +F2 + + + +null_literal + + + +; + + + +additive_expression + + + +multiplicative_expression + + + +namespace_name + + + +relational_expression + + + +Console + + + +void + + + +identifier + + + +local_function_body + + + +statement + + + +using_namespace_directive + + + += + + + +inclusive_or_expression + + + +primary_expression + + + +switch_expression + + + +embedded_statement + + + +argument_list + + + +shift_expression + + + +nullable_reference_type + + + +( + + + +{ + + + +exclusive_or_expression + + + +WriteLine + + + +identifier + + + +class + + + +inclusive_or_expression + + \ No newline at end of file diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/_Sample_Options.txt b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/_Sample_Options.txt new file mode 100644 index 000000000..c3810f510 --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/_Sample_Options.txt @@ -0,0 +1 @@ +-ms Rules -rt \ No newline at end of file diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/sample.cs b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/sample.cs new file mode 100644 index 000000000..d34284a72 --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v9/Attributes on Local Functions/sample.cs @@ -0,0 +1,20 @@ +using System; + +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}|"); + } + } +} \ No newline at end of file