diff --git a/standard/basic-concepts.md b/standard/basic-concepts.md index df840ee0c..7ea526184 100644 --- a/standard/basic-concepts.md +++ b/standard/basic-concepts.md @@ -597,7 +597,7 @@ The ***scope*** of a name is the region of program text within which it is possi - The scope of a label declared in a *labeled_statement* ([§13.5](statements.md#135-labeled-statements)) is the *block* in which the declaration occurs. - The scope of a local variable declared in a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)) is the *block* in which the declaration occurs. - The scope of a local variable declared in a *switch_block* of a `switch` statement ([§13.8.3](statements.md#1383-the-switch-statement)) is the *switch_block*. -- The scope of a local variable declared in a *for_initializer* of a `for` statement ([§13.9.4](statements.md#1394-the-for-statement)) is the *for_initializer*, the *for_condition*, the *for_iterator*, and the contained *statement* of the `for` statement. +- The scope of a local variable declared in a *for_initializer* of a `for` statement ([§13.9.4](statements.md#1394-the-for-statement)) is the *for_initializer*, *for_condition*, *for_iterator*, and *embedded_statement* of the `for` statement. - The scope of a local constant declared in a *local_constant_declaration* ([§13.6.3](statements.md#1363-local-constant-declarations)) is the *block* in which the declaration occurs. It is a compile-time error to refer to a local constant in a textual position that precedes its *constant_declarator*. - The scope of a variable declared as part of a *foreach_statement*, *using_statement*, *lock_statement* or *query_expression* is determined by the expansion of the given construct. @@ -622,7 +622,7 @@ Within the scope of a namespace, class, struct, or enumeration member it is poss > > *end example* -Within the scope of a local variable, it is a compile-time error to refer to the local variable in a textual position that precedes the *local_variable_declarator* of the local variable. +Within the scope of a local variable, it is a compile-time error to refer to the local variable in a textual position that precedes its declarator. > *Example*: > @@ -651,7 +651,7 @@ Within the scope of a local variable, it is a compile-time error to refer to the > } > ``` > -> In the `F` method above, the first assignment to `i` specifically does not refer to the field declared in the outer scope. Rather, it refers to the local variable and it results in a compile-time error because it textually precedes the declaration of the variable. In the `G` method, the use of `j` in the initializer for the declaration of `j` is valid because the use does not precede the *local_variable_declarator*. In the `H` method, a subsequent *local_variable_declarator* correctly refers to a local variable declared in an earlier *local_variable_declarator* within the same *local_variable_declaration*. +> In the `F` method above, the first assignment to `i` specifically does not refer to the field declared in the outer scope. Rather, it refers to the local variable and it results in a compile-time error because it textually precedes the declaration of the variable. In the `G` method, the use of `j` in the initializer for the declaration of `j` is valid because the use does not precede the declarator. In the `H` method, a subsequent declarator correctly refers to a local variable declared in an earlier declarator within the same *local_variable_declaration*. > > *end example* diff --git a/standard/expressions.md b/standard/expressions.md index 6b0906611..bf6523ebe 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -3143,7 +3143,7 @@ stackalloc_element_initializer A *stackalloc_expression* is only permitted in two contexts: -1. The *expression*, `E`, of a *local_variable_initializer* of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)); and +1. The initializing *expression*, `E`, of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)); and 2. The right operand *expression*, `E`, of a simple assignment ([$12.21.2](expressions.md#12212-simple-assignment)) which itself occurs as a *expression_statement* ([§13.7](statements.md#137-expression-statements)) In both contexts the *stackalloc_expression* is only permitted to occur as: @@ -4705,6 +4705,11 @@ A declaration expression declares a local variable. declaration_expression : local_variable_type identifier ; + +local_variable_type + : type + | 'var' + ; ``` The *simple_name* `_` is also considered a declaration expression if simple name lookup did not find an associated declaration ([§12.8.4](expressions.md#1284-simple-names)). When used as a declaration expression, `_` is called a *simple discard*. It is semantically equivalent to `var _`, but is permitted in more places. diff --git a/standard/statements.md b/standard/statements.md index 6a0c07a97..b05675284 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -298,67 +298,24 @@ A *local_variable_declaration* declares one or more local variables. ```ANTLR local_variable_declaration - : ref_kind? local_variable_type local_variable_declarators - ; - -local_variable_type - : type - | 'var' - ; - -local_variable_declarators - : local_variable_declarator - | local_variable_declarators ',' local_variable_declarator - ; - -local_variable_declarator - : identifier - | identifier '=' local_variable_initializer - ; - -local_variable_initializer - : expression - | 'ref' variable_reference - | array_initializer + : implicitly_typed_local_variable_declaration + | explicitly_typed_local_variable_declaration + | ref_local_variable_declaration ; ``` -The *local_variable_type* of a *local_variable_declaration* either directly specifies the type of the variables introduced by the declaration, or indicates with the identifier `var` that the type should be inferred based on an initializer. The type is followed by a list of *local_variable_declarator*s, each of which introduces a new variable. A *local_variable_declarator* consists of an *identifier* that names the variable, optionally followed by an “`=`” token and a *local_variable_initializer* that gives the initial value of the variable. However, it is a compile-time error to omit *local_variable_initializer* from a *local_variable_declarator* for a variable declared `ref` or `ref readonly`. +Local variable declarations fall into one of the three categories: implicitly typed, explicitly typed, and ref local. -A *local_variable_initializer* for a variable declared `ref` or `ref readonly` shall be of the form “`ref` *variable_reference*”. It is a compile time error if the scope of the local variable is wider than the ref-safe-context of the *variable_reference* ([§9.7.2](variables.md#972-ref-safe-contexts)). - -If *local_variable_declaration* contains `ref readonly`, the *identifier*s being declared are references to variables that are treated as read-only, and their corresponding *local_variable_initializer*s shall each contain `ref`. Otherwise, if *local_variable_declaration* contains `ref` without `readonly`, the *identifier*s being declared are references to variables that shall be writable, and their corresponding *local_variable_initializer* shall each contain `ref`. - -It is a compile-time error to declare a local variable `ref` or `ref readonly` or a variable of a `ref struct` type within a method declared with the *method_modifier* `async`, or an iterator ([§15.14](classes.md#1514-iterators)). - -In the context of a local variable declaration, the identifier `var` acts as a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)). When the *local_variable_type* is specified as `var` and no type named `var` is in scope, the declaration is an ***implicitly typed local variable declaration***, whose type is inferred from the type of the associated initializer expression. Implicitly typed local variable declarations are subject to the following restrictions: - -- The *local_variable_declaration* cannot include multiple *local_variable_declarator*s. -- The *local_variable_declarator* shall include a *local_variable_initializer*. -- The *local_variable_initializer* shall be an *expression*, optionally preceded by `ref`. -- The initializer *expression* shall have a compile-time type. -- The initializer *expression* cannot refer to the declared variable itself. - -> *Example*: The following are incorrect implicitly typed local variable declarations: -> -> -> ```csharp -> var x; // Error, no initializer to infer type from -> var y = {1, 2, 3}; // Error, array initializer not permitted -> var z = null; // Error, null does not have a type -> var u = x => x + 1; // Error, anonymous functions do not have a type -> var v = v++; // Error, initializer cannot refer to v itself -> ``` -> -> *end example* +Implicitly typed declarations contain the contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) `var` resulting in a syntactic ambiguity between the three categories which is resolved as follows: -The value of a local variable is obtained in an expression using a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)). A local variable shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) at each location where its value is obtained. +- If there is no type named `var` in scope and the input matches *implicitly_typed_local_variable_declaration* then it is chosen; +- Otherwise if a type named `var` is in scope then *implicitly_typed_local_variable_declaration* is not considered as a possible match. -The scope of a local variable declared in a *local_variable_declaration* is the block in which the declaration occurs. It is an error to refer to a local variable in a textual position that precedes the *local_variable_declarator* of the local variable. Within the scope of a local variable, it is a compile-time error to declare another local variable, local function or constant with the same name. +Within a *local_variable_declaration* each variable is introduced by a ***declarator***, which is one of *implicitly_typed_local_variable_declarator*, *explicitly_typed_local_variable_declarator* or *ref_local_variable_declarator* for impicitly typed, explicitly typed and ref local variables respectively. The declarator defines the name (*identifier*) and initial value, if any, of the introduced variable. -A local variable declaration that declares multiple variables is equivalent to multiple declarations of single variables with the same type and *ref_kind*. +If there are multiple declarators in a declaration then they are processed, including any initializing expressions, in order left to right ([§9.4.4.5](variables.md#9445-declaration-statements)). -> *Example*: The example +> *Note*: For a *local_variable_declaration* not occuring as a *for_initializer* ([§13.9.4](statements.md#1394-the-for-statement)) or *resource_acquisition* ([§13.14](statements.md#1314-the-using-statement)) this left to right order is equivalent to each declarator being within a separate *local_variable_declaration*. For example: > > > ```csharp @@ -368,21 +325,46 @@ A local variable declaration that declares multiple variables is equivalent to m > } > ``` > -> corresponds exactly to +> is equivalent to: > > > ```csharp > void F() > { -> int x; x = 1; +> int x = 1; > int y; -> int z; z = x * 2; +> int z = x * 2; > } > ``` > -> *end example* +> *end note* + +The value of a local variable is obtained in an expression using a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)). A local variable shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) at each location where its value is obtained. Each local variable introduced by a *local_variable_declaration* is *initially unassigned* ([§9.4.3](variables.md#943-initially-unassigned-variables)). If a declarator has an initializing expression then the introduced local variable is classified as *assigned* at the end of the declarator ([§9.4.4.5](variables.md#9445-declaration-statements)). + +The scope of a local variable introduced by a *local_variable_declaration* is defined as follows ([§7.7](basic-concepts.md#77-scopes)): + +- If the declaration occurs as a *for_initializer* then the scope is the *for_initializer*, *for_condition*, *for_iterator*, and *embedded_statement* ([§13.9.4](statements.md#1394-the-for-statement)); +- If the declaration occurs as a *resource_acquisition* then the scope is the outermost block of the semantically equivalent expansion of the *using_statement* ([§13.14](statements.md#1314-the-using-statement)); +- Otherwise the scope is the block in which the declaration occurs. + +It is an error to refer to a local variable by name in a textual position that precedes its declarator, or within any initializing expression within its declarator. Within the scope of a local variable, it is a compile-time error to declare another local variable, local function or constant with the same name. + +The ref-safe-context ([§9.7.2](variables.md#972-ref-safe-contexts)) of a ref local variable is the ref-safe-context of its initializing *variable_reference*. The ref-safe-context of non-ref local variables is *declaration-block*. + +#### Implicitly typed local variable declarations + +```ANTLR +implicitly_typed_local_variable_declaration + : 'var' implicitly_typed_local_variable_declarator + | ref_kind 'var' ref_local_variable_declarator + ; + +implicitly_typed_local_variable_declarator + : identifier '=' expression + ; +``` -In an implicitly typed local variable declaration, the type of the local variable being declared is taken to be the same as the type of the expression used to initialize the variable. +An *implicity_typed_local_variable_declaration* introduces a single local variable, *identifier*. The *expression* or *variable_reference* must have a compile-time type, `T`. The first alternative declares a variable with type `T` and an initial value of *expression*. The second alternative declares a ref variable with type `ref T` and an initial value of `ref` *variable_reference*. > *Example*: > @@ -410,8 +392,66 @@ In an implicitly typed local variable declaration, the type of the local variabl > ref readonly int k = ref i; > ``` > +> The following are incorrect implicitly typed local variable declarations: +> +> +> ```csharp +> var x; // Error, no initializer to infer type from +> var y = {1, 2, 3}; // Error, array initializer not permitted +> var z = null; // Error, null does not have a type +> var u = x => x + 1; // Error, anonymous functions do not have a type +> var v = v++; // Error, initializer cannot refer to v itself +> ``` +> > *end example* +#### Explicitly typed local variable declarations + +```ANTLR +explicitly_typed_local_variable_declaration + : type explicitly_typed_local_variable_declarators + ; + +explicitly_typed_local_variable_declarators + : explicitly_typed_local_variable_declarator (',' explicitly_typed_local_variable_declarator)* + ; + +explicitly_typed_local_variable_declarator + : identifier ('=' local_variable_initializer)? + ; + +local_variable_initializer + : expression + | array_initializer + ; +``` + +An *explicity_typed_local_variable_declaration* introduces one or more local variables with the specified *type*. + +If a *local_variable_initializer* is present then its type must be appropriate according to the rules of simple assignment ([§12.21.2](expressions.md#12212-simple-assignment)) or array initialization ([§17.7](arrays.md#177-array-initializers)) and its value is assigned as the initial value of the variable. + +#### Ref local variable declarations + +```ANTLR +ref_local_variable_declaration + : ref_kind type ref_local_variable_declarators + ; + +ref_local_variable_declarators + : ref_local_variable_declarator (',' ref_local_variable_declarator)* + ; + +ref_local_variable_declarator + : identifier '=' 'ref' variable_reference + ; +``` + +The initializing *variable_reference* must have type *type* and meet the same requirements as for a *ref assignment* ([§12.21.3](expressions.md#12213-ref-assignment)). + +If *ref_kind* is `ref readonly`, the *identifier*(s) being declared are references to variables that are treated as read-only. Otherwise, if *ref_kind* is `ref`, the *identifier*(s) being declared are references to variables that shall be writable. + +It is a compile-time error to declare a ref local variable, or a variable of a `ref struct` type, within a method declared with the *method_modifier* `async`, or within an iterator ([§15.14](classes.md#1514-iterators)). + ### 13.6.3 Local constant declarations A *local_constant_declaration* declares one or more local constants. @@ -533,15 +573,15 @@ Local function bodies are always reachable. The endpoint of a local function dec > > > ```csharp -> class C +> class C > { -> int M() +> int M() > { > L(); > return 1; -> +> > // Beginning of L is not reachable -> int L() +> int L() > { > // The body of L is reachable > return 2; @@ -673,7 +713,7 @@ switch_label : 'case' pattern case_guard? ':' | 'default' ':' ; - + case_guard : 'when' expression ; @@ -1019,7 +1059,7 @@ statement_expression_list ; ``` -The *for_initializer*, if present, consists of either a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)) or a list of *statement_expression*s ([§13.7](statements.md#137-expression-statements)) separated by commas. The scope of a local variable declared by a *for_initializer* starts at the *local_variable_declarator* for the variable and extends to the end of the embedded statement. The scope includes the *for_condition* and the *for_iterator*. +The *for_initializer*, if present, consists of either a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)) or a list of *statement_expression*s ([§13.7](statements.md#137-expression-statements)) separated by commas. The scope of a local variable declared by a *for_initializer* is the *for_initializer*, *for_condition*, *for_iterator*, and *embedded_statement*. The *for_condition*, if present, shall be a *boolean_expression* ([§12.24](expressions.md#1224-boolean-expressions)). diff --git a/standard/unsafe-code.md b/standard/unsafe-code.md index b9064ca0c..aadfe72b1 100644 --- a/standard/unsafe-code.md +++ b/standard/unsafe-code.md @@ -1049,7 +1049,7 @@ When the outermost containing struct variable of a fixed-size buffer member is a See [§12.8.21](expressions.md#12821-stack-allocation) for general information about the operator `stackalloc`. Here, the ability of that operator to result in a pointer is discussed. -In an unsafe context if a *stackalloc_expression* ([§12.8.21](expressions.md#12821-stack-allocation)) occurs as the *local_variable_initializer* of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)), where the *local_variable_type* is either a pointer type ([§23.3](unsafe-code.md#233-pointer-types)) or inferred (`var`), then the result of the *stackalloc_expression* is a pointer of type `T *` to be beginning of the allocated block, where `T` is the *unmanaged_type* of the *stackalloc_expression*. +In an unsafe context if a *stackalloc_expression* ([§12.8.21](expressions.md#12821-stack-allocation)) occurs as the initializing expression of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)), where the *local_variable_type* is either a pointer type ([§23.3](unsafe-code.md#233-pointer-types)) or inferred (`var`), then the result of the *stackalloc_expression* is a pointer of type `T *` to be beginning of the allocated block, where `T` is the *unmanaged_type* of the *stackalloc_expression*. In all other respects the semantics of *local_variable_declaration*s ([§13.6.2](statements.md#1362-local-variable-declarations)) and *stackalloc_expression*s ([§12.8.21](expressions.md#12821-stack-allocation)) in unsafe contexts follow those defined for safe contexts. diff --git a/standard/variables.md b/standard/variables.md index 1b2547e50..4137dcd9b 100644 --- a/standard/variables.md +++ b/standard/variables.md @@ -124,7 +124,7 @@ A ***local variable*** is declared by a *local_variable_declaration*, *declarati A *local_variable_declaration* can occur in a *block*, a *for_statement*, a *switch_block*, or a *using_statement*. A *declaration_expression* can occur as an `out` *argument_value*, and as a *tuple_element* that is the target of a deconstructing assignment ([§12.21.2](expressions.md#12212-simple-assignment)). -The lifetime of a local variable is the portion of program execution during which storage is guaranteed to be reserved for it. This lifetime extends from entry into the scope with which it is associated, at least until execution of that scope ends in some way. (Entering an enclosed *block*, calling a method, or yielding a value from an iterator block suspends, but does not end, execution of the current scope.) If the local variable is captured by an anonymous function ([§12.19.6.2](expressions.md#121962-captured-outer-variables)), its lifetime extends at least until the delegate or expression tree created from the anonymous function, along with any other objects that come to reference the captured variable, are eligible for garbage collection. If the parent scope is entered recursively or iteratively, a new instance of the local variable is created each time, and its *local_variable_initializer*, if any, is evaluated each time. +The lifetime of a local variable is the portion of program execution during which storage is guaranteed to be reserved for it. This lifetime extends from entry into the scope with which it is associated, at least until execution of that scope ends in some way. (Entering an enclosed *block*, calling a method, or yielding a value from an iterator block suspends, but does not end, execution of the current scope.) If the local variable is captured by an anonymous function ([§12.19.6.2](expressions.md#121962-captured-outer-variables)), its lifetime extends at least until the delegate or expression tree created from the anonymous function, along with any other objects that come to reference the captured variable, are eligible for garbage collection. If the parent scope is entered recursively or iteratively, a new instance of the local variable is created each time, and its initializer, if any, is evaluated each time. > *Note*: A local variable is instantiated each time its scope is entered. This behavior is visible to user code containing anonymous methods. *end note* @@ -142,7 +142,7 @@ The lifetime of a local variable is the portion of program execution during whic A local variable introduced by a *local_variable_declaration* or *declaration_expression* is not automatically initialized and thus has no default value. Such a local variable is considered initially unassigned. -> *Note*: A *local_variable_declaration* that includes a *local_variable_initializer* is still initially unassigned. Execution of the declaration behaves exactly like an assignment to the variable ([§9.4.4.5](variables.md#9445-declaration-statements)). Using a variable before its *local_variable_initializer* has been executed; e.g., within the initializer expression itself or by using a *goto_statement* which bypasses the initializer; is a compile-time error: +> *Note*: A *local_variable_declaration* that includes an initializer is still initially unassigned. Execution of the declaration behaves exactly like an assignment to the variable ([§9.4.4.5](variables.md#9445-declaration-statements)). Using a variable before its initializer has been executed; e.g., within the initializer expression itself or by using a *goto_statement* which bypasses the initializer; is a compile-time error: > > > ```csharp @@ -153,7 +153,7 @@ A local variable introduced by a *local_variable_declaration* or *declaration_ex > L: x += 1; // error: x not definitely assigned > ``` > -> Within the scope of a local variable, it is a compile-time error to refer to that local variable in a textual position that precedes its *local_variable_declarator*. +> Within the scope of a local variable, it is a compile-time error to refer to that local variable in a textual position that precedes its declarator. > > *end note*