Skip to content

Commit 2d86b34

Browse files
Nigel-Ecmajskeet
authored andcommitted
Revision of §13.6.2 *Local variable declarations* to fix errors and tidy up.
This clause has evolved over time as first implicitly typed, and now in v7 ref locals, have been introduced; the result ending up as something worthy of Heath Robinson or Professor Branestawm ;-) The result alas is also not entirely correct, the initial version was (almost), but subsequent kinds of local variables don't follow exactly the same rules... As a simple example of what ended up going wrong is the assertion: > A local variable declaration that declares multiple variables is equivalent to multiple declarations of single variables with the same type and *ref_kind*. and its associated example. This was (almost) correct originally, but is not correct for implicitly typed or ref local declarations where the initialization cannot be split from the declaration. (It was “almost” is it didn't allow for *for_initializer* or *resource_acqusition* cases where such a split is not possible either.) The rework divides local variable declarations into three subgroups, there really are four but we can get away with three (whether we should can be debated). These groups are directly represented in the reworked grammar, which also replaces a lot of conditional English prose. The clause starts with the general rules and then has a section for each subgroup detailing just the rules that apply in that case. The changes have been kept to the §13.6.2 clause; there are related issues in at least §7.7.1 Scopes:General and §13.14 The using statement – neither of these for example define the scope of a variable introduced in a *resource_acqusition*. Such issues are left for future (pre-v8) work!
1 parent 2f26a52 commit 2d86b34

File tree

1 file changed

+104
-63
lines changed

1 file changed

+104
-63
lines changed

standard/statements.md

Lines changed: 104 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -298,67 +298,24 @@ A *local_variable_declaration* declares one or more local variables.
298298

299299
```ANTLR
300300
local_variable_declaration
301-
: ref_kind? local_variable_type local_variable_declarators
302-
;
303-
304-
local_variable_type
305-
: type
306-
| 'var'
307-
;
308-
309-
local_variable_declarators
310-
: local_variable_declarator
311-
| local_variable_declarators ',' local_variable_declarator
312-
;
313-
314-
local_variable_declarator
315-
: identifier
316-
| identifier '=' local_variable_initializer
317-
;
318-
319-
local_variable_initializer
320-
: expression
321-
| 'ref' variable_reference
322-
| array_initializer
301+
: implicitly_typed_local_variable_declaration
302+
| explicitly_typed_local_variable_declaration
303+
| ref_local_variable_declaration
323304
;
324305
```
325306

326-
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`.
307+
Local variable declarations fall into one of the three categories: implicitly typed, explicitly typed, and ref local.
327308

328-
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)).
329-
330-
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`.
331-
332-
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)).
333-
334-
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:
335-
336-
- The *local_variable_declaration* cannot include multiple *local_variable_declarator*s.
337-
- The *local_variable_declarator* shall include a *local_variable_initializer*.
338-
- The *local_variable_initializer* shall be an *expression*, optionally preceded by `ref`.
339-
- The initializer *expression* shall have a compile-time type.
340-
- The initializer *expression* cannot refer to the declared variable itself.
341-
342-
> *Example*: The following are incorrect implicitly typed local variable declarations:
343-
>
344-
> <!-- Example: {template:"standalone-console-without-using", name:"LocalVariableDecls1", expectedErrors:["CS0818","CS0820","CS0815","CS8917","CS0841"], ignoredWarnings:["CS0168"]} -->
345-
> ```csharp
346-
> var x; // Error, no initializer to infer type from
347-
> var y = {1, 2, 3}; // Error, array initializer not permitted
348-
> var z = null; // Error, null does not have a type
349-
> var u = x => x + 1; // Error, anonymous functions do not have a type
350-
> var v = v++; // Error, initializer cannot refer to v itself
351-
> ```
352-
>
353-
> *end example*
309+
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:
354310

355-
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.
311+
- If there is no type named `var` in scope and the input matches *implicitly_typed_local_variable_declaration* then it is chosen;
312+
- Otherwise if a type named `var` is in scope then *implicitly_typed_local_variable_declaration* is not considered as a possible match.
356313

357-
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.
314+
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.
358315

359-
A local variable declaration that declares multiple variables is equivalent to multiple declarations of single variables with the same type and *ref_kind*.
316+
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#945-declaration-statements)).
360317

361-
> *Example*: The example
318+
> *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:
362319
>
363320
> <!-- Example: {template:"standalone-console-without-using", name:"LocalVariableDecls2", ignoredWarnings:["CS0168","CS8321"]} -->
364321
> ```csharp
@@ -368,21 +325,47 @@ A local variable declaration that declares multiple variables is equivalent to m
368325
> }
369326
> ```
370327
>
371-
> corresponds exactly to
328+
> is equivalent to:
372329
>
373330
> <!-- Example: {template:"standalone-console-without-using", name:"LocalVariableDecls3", ignoredWarnings:["CS0168","CS8321"]} -->
374331
> ```csharp
375332
> void F()
376333
> {
377-
> int x; x = 1;
334+
> int x = 1;
378335
> int y;
379-
> int z; z = x * 2;
336+
> int z = x * 2;
380337
> }
381338
> ```
382339
>
383-
> *end example*
340+
> *end note*
341+
342+
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#99-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#945-declaration-statements)).
343+
344+
The scope of a local variable introduced by a *local_variable_declaration* is defined as follows ([§7.7](basic-concepts.md#77-scopes)):
345+
346+
- If the declaration occurs as a *for_initializer* then the scope is the *local_variable_declaration* from the *declarator* for the variable to the end of the declaration, the *for_condition*, the *for_iterator*, and the *embedded_statement* ([§13.9.4](statements.md#1394-the-for-statement));
347+
- 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));
348+
- Otherwise the scope is the block in which the declaration occurs.
349+
350+
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.
351+
352+
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*.
353+
354+
#### Implicitly typed local variable declarations
355+
356+
```ANTLR
357+
implicitly_typed_local_variable_declaration
358+
: 'var' implicitly_typed_local_variable_declarator
359+
| ref_kind 'var' ref_local_variable_declarator
360+
;
361+
362+
implicitly_typed_local_variable_declarator
363+
: identifier '=' expression
364+
;
365+
```
366+
367+
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 variant declares a variable with type `T` and an initial value of *expression*. The second variant declares a ref variable with type `ref T` and an initial value of `ref` *variable_reference*.
384368

385-
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.
386369

387370
> *Example*:
388371
>
@@ -410,8 +393,66 @@ In an implicitly typed local variable declaration, the type of the local variabl
410393
> ref readonly int k = ref i;
411394
> ```
412395
>
396+
> The following are incorrect implicitly typed local variable declarations:
397+
>
398+
> <!-- Example: {template:"standalone-console-without-using", name:"LocalVariableDecls1", expectedErrors:["CS0818","CS0820","CS0815","CS8917","CS0841"], ignoredWarnings:["CS0168"]} -->
399+
> ```csharp
400+
> var x; // Error, no initializer to infer type from
401+
> var y = {1, 2, 3}; // Error, array initializer not permitted
402+
> var z = null; // Error, null does not have a type
403+
> var u = x => x + 1; // Error, anonymous functions do not have a type
404+
> var v = v++; // Error, initializer cannot refer to v itself
405+
> ```
406+
>
413407
> *end example*
414408
409+
#### Explicitly typed local variable declarations
410+
411+
```ANTLR
412+
explicitly_typed_local_variable_declaration
413+
: type explicitly_typed_local_variable_declarators
414+
;
415+
416+
explicitly_typed_local_variable_declarators
417+
: explicitly_typed_local_variable_declarator (',' explicitly_typed_local_variable_declarator)*
418+
;
419+
420+
explicitly_typed_local_variable_declarator
421+
: identifier ('=' local_variable_initializer)?
422+
;
423+
424+
local_variable_initializer
425+
: expression
426+
| array_initializer
427+
;
428+
```
429+
430+
An *explicity_typed_local_variable_declaration* introduces one or more local variables with the specified *type*.
431+
432+
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.
433+
434+
#### Ref local variable declarations
435+
436+
```ANTLR
437+
ref_local_variable_declaration
438+
: ref_kind type ref_local_variable_declarators
439+
;
440+
441+
ref_local_variable_declarators
442+
: ref_local_variable_declarator (',' ref_local_variable_declarator)*
443+
;
444+
445+
ref_local_variable_declarator
446+
: identifier '=' 'ref' variable_reference
447+
;
448+
```
449+
450+
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)).
451+
452+
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.
453+
454+
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)).
455+
415456
### 13.6.3 Local constant declarations
416457

417458
A *local_constant_declaration* declares one or more local constants.
@@ -537,15 +578,15 @@ Local function bodies are always reachable. The endpoint of a local function dec
537578
>
538579
> <!-- Example: {template:"standalone-lib-without-using", name:"LocalFunctionDeclarations2", expectedWarnings:["CS0162"]} -->
539580
> ```csharp
540-
> class C
581+
> class C
541582
> {
542-
> int M()
583+
> int M()
543584
> {
544585
> L();
545586
> return 1;
546-
>
587+
>
547588
> // Beginning of L is not reachable
548-
> int L()
589+
> int L()
549590
> {
550591
> // The body of L is reachable
551592
> return 2;
@@ -677,7 +718,7 @@ switch_label
677718
: 'case' pattern case_guard? ':'
678719
| 'default' ':'
679720
;
680-
721+
681722
case_guard
682723
: 'when' expression
683724
;

0 commit comments

Comments
 (0)