You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Update statements.md
* Update unsafe-code.md
* Add semantics and example for local functions v7.0 feature
* removed local function unsafe grammar extension
With the consolidation of the unsafe grammar in PR #233, this text is no longer needed.
* include support for local functions
* add support for local functions
* fix build issues
* Apply suggestions from code review
Co-authored-by: KalleOlaviNiemitalo <[email protected]>
* clarify definite assignment, add examples
Addresses comments in committee meeting:
- #104 (comment)
- #104 (comment)
* respond to feedback.
* grammar updates
* Incorporate Andy's text
In this commit, create the new clause for the definite assignment rules for local functions. Move the existing example to that clause. Add text from Andy's comments and notes.
* finish local functions and definite assignment.
Incorporate the rules for definite assignment for captured variables in local functions. This is both for local function calls and for delegate conversion.
* typo
* Apply suggestions from code review
Co-authored-by: Nigel-Ecma <[email protected]>
* Apply suggestions from code review
* Update standard/statements.md
Co-authored-by: Jon Skeet <[email protected]>
* Update standard/statements.md
* Update standard/statements.md
Co-authored-by: Neal Gafter <[email protected]>
* Update standard/statements.md
* Update standard/statements.md
* edits based on September committee meeting
* fix link text
* fix section renumbering issue
* Final edits
We resolved these two discussions during the committee meeting. Edits reflect those decisions.
* updates from code review.
* one more bit of feedback.
Co-authored-by: Bill Wagner <[email protected]>
Co-authored-by: KalleOlaviNiemitalo <[email protected]>
Co-authored-by: Nigel-Ecma <[email protected]>
Co-authored-by: Jon Skeet <[email protected]>
Co-authored-by: Neal Gafter <[email protected]>
Copy file name to clipboardExpand all lines: standard/basic-concepts.md
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -64,8 +64,9 @@ There are several different types of declaration spaces, as described in the fol
64
64
- Each non-partial class, struct, or interface declaration creates a new declaration space. Each partial class, struct, or interface declaration contributes to a declaration space shared by all matching parts in the same program ([§15.2.3](structs.md#1523-partial-modifier)).Names are introduced into this declaration space through *class_member_declaration*s, *struct_member_declaration*s, *interface_member_declaration*s, or *type_parameter*s. Except for overloaded instance constructor declarations and static constructor declarations, a class or struct cannot contain a member declaration with the same name as the class or struct. A class, struct, or interface permits the declaration of overloaded methods and indexers. Furthermore, a class or struct permits the declaration of overloaded instance constructors and operators. For example, a class, struct, or interface may contain multiple method declarations with the same name, provided these method declarations differ in their signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)). Note that base classes do not contribute to the declaration space of a class, and base interfaces do not contribute to the declaration space of an interface. Thus, a derived class or interface is allowed to declare a member with the same name as an inherited member. Such a member is said to ***hide*** the inherited member.
65
65
- Each delegate declaration creates a new declaration space. Names are introduced into this declaration space through formal parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s.
66
66
- Each enumeration declaration creates a new declaration space. Names are introduced into this declaration space through *enum_member_declarations*.
67
-
- Each method declaration, property declaration, property accessor declaration, indexer declaration, indexer accessor declaration, operator declaration, instance constructor declaration and anonymous function creates a new declaration space called a ***local variable declaration space***. Names are introduced into this declaration space through formal parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s. The set accessor for a property or an indexer introduces the name `value` as a formal parameter. The body of the function member or anonymous function, if any, is considered to be nested within the local variable declaration space. It is an error for a local variable declaration space and a nested local variable declaration space to contain elements with the same name. Thus, within a nested declaration space it is not possible to declare a local variable or constant with the same name as a local variable or constant in an enclosing declaration space. It is possible for two declaration spaces to contain elements with the same name as long as neither declaration space contains the other.
68
-
- Each *block* or *switch_block*, as well as a `for`, `foreach`, and `using` statement, creates a local variable declaration space for local variables and local constants. Names are introduced into this declaration space through *local_variable_declaration*s and *local_constant_declaration*s. Note that blocks that occur as or within the body of a function member or anonymous function are nested within the local variable declaration space declared by those functions for their parameters. Thus, it is an error to have, for example, a method with a local variable and a parameter of the same name.
67
+
- Each method declaration, property declaration, property accessor declaration, indexer declaration, indexer accessor declaration, operator declaration, instance constructor declaration, anonymous function, and local function creates a new declaration space called a ***local variable declaration space***. Names are introduced into this declaration space through formal parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s. The set accessor for a property or an indexer introduces the name `value` as a formal parameter. The body of the function member, anonymous function, or local function, if any, is considered to be nested within the local variable declaration space. It is an error for a local variable declaration space and a nested local variable declaration space to contain elements with the same name. Thus, within a nested declaration space it is not possible to declare a local variable or constant with the same name as a local variable or constant in an enclosing declaration space. It is possible for two declaration spaces to contain elements with the same name as long as neither declaration space contains the other.
68
+
- Each *block* or *switch_block*, as well as a `for`, `foreach`, and `using` statement, creates a local variable declaration space for local variables and local constants. Names are introduced into this declaration space through *local_variable_declaration*s and *local_constant_declaration*s. Note that blocks that occur as or within the body of a function member, anonymous function, or local function are nested within the local variable declaration space declared by those functions for their parameters. Thus, it is an error to have, for example, a method with a local variable and a parameter of the same name.
69
+
69
70
- Each *block* or *switch_block* creates a separate declaration space for labels. Names are introduced into this declaration space through *labeled_statement*s, and the names are referenced through *goto_statement*s. The ***label declaration space*** of a block includes any nested blocks. Thus, within a nested block it is not possible to declare a label with the same name as a label in an enclosing block.
70
71
71
72
The textual order in which names are declared is generally of no significance. In particular, textual order is not significant for the declaration and use of namespaces, constants, methods, properties, events, indexers, operators, instance constructors, finalizers, static constructors, and types. Declaration order is significant in the following ways:
Copy file name to clipboardExpand all lines: standard/statements.md
+98-1Lines changed: 98 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -270,15 +270,18 @@ In addition to the reachability provided by normal flow of control, a labeled st
270
270
271
271
### 12.6.1 General
272
272
273
-
A *declaration_statement* declaresalocalvariableorconstant. Declarationstatementsarepermittedinblocks, butarenotpermittedasembeddedstatements.
273
+
A *declaration_statement* declaresalocalvariable, localconstant, orlocalfunction. Declarationstatementsarepermittedinblocks, butarenotpermittedasembeddedstatements.
274
274
275
275
```ANTLR
276
276
declaration_statement
277
277
: local_variable_declaration ';'
278
278
| local_constant_declaration ';'
279
+
| local_function_declaration
279
280
;
280
281
```
281
282
283
+
A local variable is declared using a *local_variable_declaration* ([§12.6.2](statements.md#1262-local-variable-declarations)). A local constant is declared using a *local_constant_declaration* ([§12.6.3](statements.md#1263-local-constant-declarations)). A local function is declared using a *local_function_declaration* (§local-function-declarations-new-clause).
284
+
282
285
### 12.6.2 Local variable declarations
283
286
284
287
A *local_variable_declaration* declares one or more local variables.
@@ -414,6 +417,100 @@ The scope of a local constant is the block in which the declaration occurs. It i
414
417
415
418
A local constant declaration that declares multiple constants is equivalent to multiple declarations of single constants with the same type.
416
419
420
+
### §local-function-declarations-new-clause Local function declarations
421
+
422
+
A *local_function_declaration* declares a local function.
Grammar note: When recognising a *local_function_body* if both the *null_conditional_invocation_expression* and *expression* alternatives are applicable then the former shall be chosen. (§14.6.1)
446
+
447
+
> *Example*: There are two common use cases for local functions: iterator methods and async methods. In iterator methods, any exceptions are observed only when calling code that enumerates the returned sequence. In async methods, any exceptions are only observed when the returned Task is awaited. The following example demonstrates separating parameter validation from the iterator implementation using a local function:
Alocalfunctionmaybecalledfromalexicalpointpriortoitsdeclaration. However, itisacompile-timeerrorforthefunctiontobedeclaredlexicallypriortothedeclarationofavariableusedinthelocalfunction (§7.7).
Copy file name to clipboardExpand all lines: standard/unsafe-code.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,12 +18,12 @@ An implementation that does not support unsafe code is required to diagnose any
18
18
19
19
## 22.2 Unsafe contexts
20
20
21
-
The unsafe features of C# are available only in unsafe contexts. An unsafe context is introduced by including an `unsafe` modifier in the declaration of a typeor member, or by employing an *unsafe_statement*:
21
+
The unsafe features of C# are available only in unsafe contexts. An unsafe context is introduced by including an `unsafe` modifier in the declaration of a type, member, or local function, or by employing an *unsafe_statement*:
22
22
23
23
- A declaration of a class, struct, interface, or delegate may include an `unsafe` modifier, in which case, the entire textual extent of that type declaration (including the body of the class, struct, or interface) is considered an unsafe context.
24
24
> *Note*: If the *type_declaration* is partial, only that part is an unsafe context. *end note*
25
-
- A declaration of a field, method, property, event, indexer, operator, instance constructor, finalizer, or static constructor may include an `unsafe` modifier, in which case, the entire textual extent of that member declaration is considered an unsafe context.
26
-
- An *unsafe_statement* enables the use of an unsafe context within a *block*. The entire textual extent of the associated *block* is considered an unsafe context.
25
+
- A declaration of a field, method, property, event, indexer, operator, instance constructor, finalizer, static constructor, or local function may include an `unsafe` modifier, in which case, the entire textual extent of that member declaration is considered an unsafe context.
26
+
- An *unsafe_statement* enables the use of an unsafe context within a *block*. The entire textual extent of the associated *block* is considered an unsafe context. A local function declared within an unsafe context is itself unsafe.
27
27
28
28
The associated grammar extensions are shown below and in subsequent subclauses.
Copy file name to clipboardExpand all lines: standard/variables.md
+59-2Lines changed: 59 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -82,7 +82,7 @@ For the purpose of definite-assignment checking, a value parameter is considered
82
82
83
83
A parameter declared with a `ref` modifier is a ***reference parameter***.
84
84
85
-
A reference parameter does not create a new storage location. Instead, a reference parameter represents the same storage location as the variable given as the argument in the function memberor anonymous function invocation. Thus, the value of a reference parameter is always the same as the underlying variable.
85
+
A reference parameter does not create a new storage location. Instead, a reference parameter represents the same storage location as the variable given as the argument in the function member, anonymous function, or local function invocation. Thus, the value of a reference parameter is always the same as the underlying variable.
86
86
87
87
The following definite-assignment rules apply to reference parameters.
88
88
@@ -106,7 +106,7 @@ The following definite-assignment rules apply to output parameters.
Withinaninstanceconstructorofastructtype, the `this` keywordbehavesexactlyasanoutputorreferenceparameterofthestructtype, dependingonwhethertheconstructordeclarationincludesaconstructorinitializer ([§11.7.12](expressions.md#11712-this-access)).
112
112
@@ -802,6 +802,63 @@ For a *lambda_expression* or *anonymous_method_expression* *expr* with a body (e
802
802
>
803
803
>*endexample*
804
804
805
+
#### §definite-assignment-rules-for-local-function Rules for variables in local functions
806
+
807
+
Localfunctionsareanalyzedinthecontextoftheirparentmethod. Therearetwocontrolflowpathsthatmatterfor local functions: function calls and delegate conversions.
808
+
809
+
Definite assignment for the body of each local function is defined separately for each call site. At each invocation, variables captured by the local function are considered definitely assigned if they were definitely assigned at the point of call. A control flow path also exists to the local function body at this point and is considered reachable. After a call to the local function, captured variables that were definitely assigned at every control point leaving the function (`return` statements, `yield` statements, `await` expressions) areconsidereddefinitelyassignedafterthecalllocation.
810
+
811
+
Delegateconversionshaveacontrolflowpathtothelocalfunctionbody. Capturedvariablesaredefinitelyassignedfor the body if they are definitely assigned before the conversion. Variables assigned by the local function are not considered assigned after the conversion.
812
+
813
+
> *Note:* the above implies that bodies are re-analyzed for definite assignment at every local function invocation or delegate conversion. Compilers are not required to re-analyze the body of a local function at each invocation or delegate conversion. The implementation must produce results equivalent to that description.
814
+
<!-- markdownlint-disable MD028 -->
815
+
816
+
<!-- markdownlint-enable MD028 -->
817
+
> *Example*: The following example demonstrates definite assignment for captured variables in local functions. If a local function reads a captured variable before writing it, the captured variable must be definitely assigned before calling the local function. The local function `F1` reads `s` without assigning it. It is an error if `F1` is called before `s` is definitely assigned. `F2` assigns `i` before reading it. It may be called before `i` is definitely assigned. Furthermore, `F3` may be called after `F2` because `s2` is definitely assigned in `F2`.
818
+
>
819
+
> ```csharp
820
+
> void M()
821
+
> {
822
+
>strings;
823
+
>inti;
824
+
>strings2;
825
+
>
826
+
>// Error: Use of unassigned local variable s:
827
+
>F1();
828
+
>// OK, F2 assigns i before reading it.
829
+
>F2();
830
+
>
831
+
>// OK, i is definitely assigned in the body of F2:
832
+
>s=i.ToString();
833
+
>
834
+
>// OK. s is now definitely assigned.
835
+
>F1();
836
+
>
837
+
>// OK, F3 reads s2, which is definitely assigned in F2.
838
+
>F3();
839
+
>
840
+
>voidF1()
841
+
> {
842
+
>Console.WriteLine(s);
843
+
> }
844
+
>
845
+
>voidF2()
846
+
> {
847
+
>i=5;
848
+
>// OK. i is definitely assigned.
849
+
>Console.WriteLine(i);
850
+
>s2=i.ToString();
851
+
> }
852
+
>
853
+
>voidF3()
854
+
> {
855
+
>Console.WriteLine(s2);
856
+
> }
857
+
> }
858
+
> ```
859
+
>
860
+
>*endexample*
861
+
805
862
## 9.5 Variable references
806
863
807
864
A*variable_reference*isan *expression* thatisclassifiedasavariable. A *variable_reference* denotesastoragelocationthatcanbeaccessedbothtofetchthecurrentvalueandtostoreanewvalue.
0 commit comments