diff --git a/standard/expressions.md b/standard/expressions.md index e0823b247..f2333d68c 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -37,6 +37,155 @@ Most of the constructs that involve an expression ultimately require the express - The value of a property access expression is obtained by invoking the *get_accessor* of the property. If the property has no *get_accessor*, a compile-time error occurs. Otherwise, a function member invocation ([§11.6.6](expressions.md#1166-function-member-invocation)) is performed, and the result of the invocation becomes the value of the property access expression. - The value of an indexer access expression is obtained by invoking the *get_accessor* of the indexer. If the indexer has no *get_accessor*, a compile-time error occurs. Otherwise, a function member invocation ([§11.6.6](expressions.md#1166-function-member-invocation)) is performed with the argument list associated with the indexer access expression, and the result of the invocation becomes the value of the indexer access expression. +### §patterns-new-clause Patterns and pattern matching + +#### §patterns-new-clause-general General + +A ***pattern*** is a syntactic form that can be used with the `is` operator ([§11.11.11](expressions.md#111111-the-is-operator)) and in a *switch_statement* ([§12.8.3](statements.md#1283-the-switch-statement)) to express the shape of data against which incoming data is to be compared. A pattern is tested in the context of a switch expression or a *relational_expression* that is on the left-hand side of an `is` operator. Let us call this a ***pattern input value***. + +A pattern may have one of the following forms: + +```ANTLR +pattern + : declaration_pattern + | constant_pattern + | var_pattern + ; +``` + +A *declaration_pattern* and a *var_pattern* can result in the declaration of a local variable. The scope of such a variable is as follows: + +- If the pattern is a case label ([§12.8.3](statements.md#1283-the-switch-statement)), then the scope of the variable is the associated *case block*. +- Otherwise, the variable is part of the pattern that is the right-hand operand of the `is` operator ([§11.11.11](expressions.md#111111-the-is-operator)), and the variable’s scope is based on the construct immediately enclosing the `is` expression containing the pattern, as follows: + - If the expression is in an expression-bodied lambda, the variable's scope is the body of the lambda. + - If the expression is in an expression-bodied method or property, the variable's scope is the body of the method or property. + - If the expression is in a `when` clause of a `catch` clause, the variable's scope is that `catch` clause. + - If the expression is in an *iteration_statement*, the variable's scope is just that statement. + - If the expression is in a *constructor_initializer*, the variable's scope is the part of that *constructor_initializer* following the expression, and the body of the constructor. + - If the expression is in a *variable_initializer* of a field, the variable's scope is the part of that *variable_initializer* following the expression. + - If the expression is in a *query_expression* that is translated into the body of a lambda, the variable's scope is that *query_expression*. + - Otherwise if the expression is in some other statement form, the variable's scope is the scope containing the statement. + +For the purpose of determining the scope, an *embedded_statement* is considered to be in its own scope. + +#### §declaration-pattern-new-clause Declaration pattern + +A *declaration_pattern* is used to test that a value has a given type and if the test succeeds, to cast that value to that type. + +```ANTLR +declaration_pattern + : type simple_designation + ; +simple_designation + : single_variable_designation + ; +single_variable_designation + : identifier + ; +``` + +The runtime type of the value is tested against the *type* in the pattern. If it is of that runtime type (or some subtype), the result of the `is` operator is `true`. A pattern input value with value `null` never tests true for this pattern. + +Given a pattern context expression (§patterns-new-clause) *e*, if the *simple_designation* is the *identifier* `_`, it denotes a discard (§discards-new-clause) the value of *e* is not bound to anything. (Although a declared variable with the name `_` may be in scope at that point, that named variable is not seen in this context.) If *simple_designation* is any other identifier, a local variable ([§9.2.8](variables.md#928-local-variables)) of the given type named by the given identifier is introduced, and that local variable is definitely assigned ([§9.4](variables.md#94-definite-assignment)) with the value of the pattern context expression when the result of the pattern-matching operation is true. + +Certain combinations of static type of the pattern input value and the given type are considered incompatible and result in a compile-time error. A value of static type `E` is said to be ***pattern compatible*** with the type `T` if there exists an identity conversion, an implicit reference conversion, a boxing conversion, an explicit reference conversion, or an unboxing conversion from `E` to `T`, or if either `E` or `T` is an open type ([§8.4.3](types.md#843-open-and-closed-types)). It is a compile-time error if a value of type `E` is not pattern compatible with the type in a type pattern with which it is matched. + +> *Note*: The support for open types can be most useful when checking types that may be either struct or class types, and boxing is to be avoided. *end note* + + + +> *Example*: The declaration pattern is useful for performing run-time type tests of reference types, and replaces the idiom +> +> ```csharp +> var v = expr as Type; +> if (v != null) { /* code using v */ } +> ``` +> +> with the slightly more concise +> +> ```csharp +> if (expr is Type v) { /* code using v */ } +> ``` +> +> *end example* + +It is an error if *type* is a nullable value type. + +> *Example*: The declaration pattern can be used to test values of nullable types: a value of type `Nullable` (or a boxed `T`) matches a type pattern `T2 id` if the value is non-null and the type of `T2` is `T`, or some base type or interface of `T`. For example, in the code fragment +> +> ```csharp +> int? x = 3; +> if (x is int v) { /* code using v */ } +> ``` +> +> The condition of the `if` statement is `true` at runtime and the variable `v` holds the value `3` of type `int` inside the block. *end example* + +#### §constant-pattern-new-clause Constant pattern + +A *constant_pattern* is used to test the value of a pattern input value (§patterns-new-clause) against the given constant value. + +```ANTLR +constant_pattern + : constant_expression + ; +``` + +Given a pattern input value *e* and a *constant_expression* *c*, if *e* and *c* have integral types, the pattern is considered matched if the result of the expression `e == c` is `true`. Otherwise, the pattern is considered matched if `object.Equals(e, c)` returns `true`. In this case it is a compile-time error if the static type of *e* is not pattern compatible (§declaration-pattern-new-clause) with the type of the constant. + +> *Example*: +> +> ```csharp +> public static decimal GetGroupTicketPrice(int visitorCount) +> { +> switch (visitorCount) { +> case 1: return 12.0m; +> case 2: return 20.0m; +> case 3: return 27.0m; +> case 4: return 32.0m; +> case 0: return 0.0m; +> default: throw new ArgumentException(…); +> } +> } +> ``` +> +> *end example* + +#### §var-pattern-new-clause Var pattern + +A match of any pattern input value (§patterns-new-clause) to a *var_pattern* always succeeds. + +```ANTLR +var_pattern + : 'var' designation + ; +designation + : simple_designation + ; +``` + +Given a pattern input value *e*, if *designation* is the *identifier* `_`, it denotes a discard (§discards-new-clause), and the value of *e* is not bound to anything. (Although a declared variable with that name may be in scope at that point, that named variable is not seen in this context.) If *designation* is any other identifier, at runtime the value of *e* is bound to a newly introduced local variable ([§9.2.8](variables.md#928-local-variables)) of that name whose type is the static type of *e*, and that local variable is definitely assigned ([§9.4](variables.md#94-definite-assignment)) with the value of the pattern input value. + +It is an error if the name `var` binds to a type. + +> *Example*: +> +> ```csharp +> static bool IsAcceptable(int id, int absLimit) => +> SimulateDataFetch(id) is var results +> && results.Min() >= -absLimit +> && results.Max() <= absLimit; +> static int[] SimulateDataFetch(int id) +> { +> var rand = new Random(); +> return Enumerable +> .Range(start: 0, count: 5) +> .Select(s => rand.Next(minValue: -10, maxValue: 11)) +> .ToArray(); +> } +> ``` +> +> *end example* + ## 11.3 Static and Dynamic Binding ### 11.3.1 General @@ -3624,6 +3773,7 @@ relational_expression | relational_expression '<=' shift_expression | relational_expression '>=' shift_expression | relational_expression 'is' type + | relational_expression 'is' pattern | relational_expression 'as' type ; @@ -3952,6 +4102,8 @@ where `x` is an expression of a nullable value type, if operator overload resolu ### 11.11.11 The is operator +When the form `is` *pattern* is used, it is a compile-time error if the corresponding *relational_expression* does not designate a value or does not have a type. + The `is` operator is used to check if the run-time type of an object is compatible with a given type. The check is performed at runtime. The result of the operation `E is T`, where `E` is an expression and `T` is a type other than `dynamic`, is a Boolean value indicating whether `E` is non-null and can successfully be converted to type `T` by a reference conversion, a boxing conversion, an unboxing conversion, a wrapping conversion, or an unwrapping conversion. The operation is evaluated as follows: @@ -5948,6 +6100,7 @@ Constant expressions are required in the contexts listed below and this is indic - `goto case` statements ([§12.10.4](statements.md#12104-the-goto-statement)) - Dimension lengths in an array creation expression ([§11.7.15.5](expressions.md#117155-array-creation-expressions)) that includes an initializer. - Attributes ([§21](attributes.md#21-attributes)) +- In a *constant_pattern* (§constant-pattern-new-clause) An implicit constant expression conversion ([§10.2.11](conversions.md#10211-implicit-constant-expression-conversions)) permits a constant expression of type `int` to be converted to `sbyte`, `byte`, `short`, `ushort`, `uint`, or `ulong`, provided the value of the constant expression is within the range of the destination type. diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index e4f33d18f..751bb2fb4 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -64,13 +64,14 @@ The productions for *simple_name* ([§11.7.4](expressions.md#1174-simple-names)) > > *end example* -If a sequence of tokens can be parsed (in context) as a *simple_name* ([§11.7.4](expressions.md#1174-simple-names)), *member_access* ([§11.7.6](expressions.md#1176-member-access)), or *pointer_member_access* ([§22.6.3](unsafe-code.md#2263-pointer-member-access)) ending with a *type_argument_list* ([§8.4.2](types.md#842-type-arguments)), the token immediately following the closing `>` token is examined. If it is one of +If a sequence of tokens can be parsed (in context) as a *simple_name* ([§11.7.4](expressions.md#1174-simple-names)), *member_access* ([§11.7.6](expressions.md#1176-member-access)), or *pointer_member_access* ([§22.6.3](unsafe-code.md#2263-pointer-member-access)) ending with a *type_argument_list* ([§8.4.2](types.md#842-type-arguments)), the token immediately following the closing `>` token is examined, to see if it is -```csharp -( ) ] : ; , . ? == != -``` +- One of `( ) ] } : ; , . ? == != | ^ && || & [`; or +- One of the relational operators `< > <= >= is as`; or +- A contextual query keyword appearing inside a query expression; or +- In certain contexts, we treat *identifier* as a disambiguating token. Those contexts are where the sequence of tokens being disambiguated is immediately preceded by one of the keywords `is`, `case` or `out`, or arises while parsing the first element of a tuple literal (in which case the tokens are preceded by `(` or `:` and the identifier is followed by a `,`) or a subsequent element of a tuple literal. -then the *type_argument_list* is retained as part of the *simple_name*, *member_access*, or *pointer_member_access* and any other possible parse of the sequence of tokens is discarded. Otherwise, the *type_argument_list* is not considered part of the *simple_name*, *member_access*, or *pointer_member_access*, even if there is no other possible parse of the sequence of tokens. +If the following token is among this list, or an identifier in such a context, then the *type_argument_list* is retained as part of the *simple_name*, *member_access* or *pointer_member-access* and any other possible parse of the sequence of tokens is discarded. Otherwise, the *type_argument_list* is not considered to be part of the *simple_name*, *member_access* or *pointer_member_access*, even if there is no other possible parse of the sequence of tokens. (These rules are not applied when parsing a *type_argument_list* in a *namespace_or_type_name* [§7.8](basic-concepts.md#78-namespace-and-type-names).) > *Note*: These rules are not applied when parsing a *type_argument_list* in a *namespace_or_type_name* ([§7.8](basic-concepts.md#78-namespace-and-type-names)). *end note* @@ -101,10 +102,12 @@ then the *type_argument_list* is retained as part of the *simple_name*, *member_ > x = y is C && z; > ``` > -> the tokens `C` are interpreted as a *namespace_or_type_name* with a *type_argument_list* due to being on the right-hand side of the `is` operator ([§11.11.1](expressions.md#11111-general)). Because `C` parses as a *namespace_or_type_name*, not a *simple_name*, *member_access*, or *pointer_member_access*, the above rule does not apply, and it is considered to have a *type_argument_list* regardless of the token that follows. +> the tokens `C` are interpreted as a *namespace_or_type_name* with a *type_argument_list* due to being on the right-hand side of the `is` operator ([§11.11.11](expressions.md#111111-the-is-operator)). Because `C` parses as a *namespace_or_type_name*, not a *simple_name*, *member_access*, or *pointer_member_access*, the above rule does not apply, and it is considered to have a *type_argument_list* regardless of the token that follows. > > *end example* +A *relational_expression* ([§11.11.1](expressions.md#11111-general)) can have the form "*relational_expression* `is` *type*" or "*relational_expression* `is` *constant_pattern*," either of which might be a valid parse of a qualified identifier. In this case, an attempt is made to bind to the type; however, if that fails, the first thing found (which must be either a constant or a type) is bound. + ## 6.3 Lexical analysis ### 6.3.1 General diff --git a/standard/statements.md b/standard/statements.md index e8dd905cc..81d5d0d7c 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -524,29 +524,27 @@ switch_section ; switch_label - : 'case' constant_expression ':' + : 'case' pattern case_guard? ':' | 'default' ':' ; + +case_guard + : 'when' expression + ; ``` -A *switch_statement* consists of the keyword `switch`, followed by a parenthesized expression (called the ***switch expression***), followed by a *switch_block*. The *switch_block* consists of zero or more *switch_section*s, enclosed in braces. Each *switch_section* consists of one or more *switch_label*s followed by a *statement_list* ([§12.3.2](statements.md#1232-statement-lists)). - -The ***governing type*** of a `switch` statement is established by the switch expression. +A *switch_statement* consists of the keyword `switch`, followed by a parenthesized expression (called the ***switch expression***), followed by a *switch_block*. The *switch_block* consists of zero or more *switch_section*s, enclosed in braces. Each *switch_section* consists of one or more *switch_label*s followed by a *statement_list* ([§12.3.2](statements.md#1232-statement-lists)). Each *switch_label* containing `case` has an associated pattern (§patterns-new-clause) against which the value of the switch expression is tested. If *case-guard* is present, its expression shall be of type `bool` and that expression is evaluated as an additional condition to be satisfied for the case to be considered satisfied. -- If the type of the switch expression is `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `bool`, `string`, or an *enum_type*, or if it is the nullable value type corresponding to one of these types, then that is the governing type of the `switch` statement. -- Otherwise, exactly one user-defined implicit conversion shall exist from the type of the switch expression to one of the following possible governing types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `string`, or, a nullable value type corresponding to one of those types. -- Otherwise, a compile-time error occurs. - -The constant expression of each `case` label shall denote a value of a type that is implicitly convertible ([§10.2](conversions.md#102-implicit-conversions)) to the governing type of the `switch` statement. A compile-time error occurs if two or more case labels in the same switch statement specify the same constant value. +A compile-time error occurs if two or more case labels in the same switch statement specify the same pattern and case guard. There can be at most one `default` label in a `switch` statement. A `switch` statement is executed as follows: -- The switch expression is evaluated and converted to the governing type. -- If one of the constants specified in a `case` label in the same `switch` statement is equal to the value of the switch expression, control is transferred to the statement list following the matched `case` label. -- If none of the constants specified in `case` labels in the same `switch` statement is equal to the value of the switch expression, and if a `default` label is present, control is transferred to the statement list following the `default` label. -- If none of the constants specified in `case` labels in the same `switch` statement is equal to the value of the switch expression, and if no `default` label is present, control is transferred to the end point of the `switch` statement. +- The switch expression is evaluated. +- The lexically first pattern in the set of `case` labels in the same `switch` statement that matches the value of the switch expression, causes control to be transferred to the statement list following the matched `case` label. +- If none of the patterns specified in `case` labels in the same `switch` statement matches the value of the switch expression, and if a `default` label is present, control is transferred to the statement list following the `default` label. +- If none of the patterns specified in `case` labels in the same `switch` statement matches the value of the switch expression, and if no `default` label is present, control is transferred to the end point of the `switch` statement. If the end point of the statement list of a switch section is reachable, a compile-time error occurs. This is known as the “no fall through” rule. @@ -625,93 +623,87 @@ Multiple labels are permitted in a *switch_section*. > *end example* - -> *Note*: The “no fall through” rule prevents a common class of bugs that occur in C and C++ when `break` statements are accidentally omitted. For example, the sections of the `switch` statement above can be reversed without affecting the behavior of the statement: +The *statement_list*s of a *switch_block* may contain declaration statements ([§12.6](statements.md#126-declaration-statements)). The scope of a local variable or constant declared in a switch block is the switch block. + +Within a switch block, the meaning of a name used in an expression context shall always be the same ([§11.7.4](expressions.md#1174-simple-names)). + +The statement list of a given switch section is reachable if the `switch` statement is reachable and at least one of the following is true: + +- The switch expression value matches a `case` label in the switch section. +- The switch expression value doesn't match any `case` label, and the switch section contains the `default` label. +- A switch label of the switch section is referenced by a reachable `goto case` or `goto default` statement. + +The end point of a `switch` statement is reachable if at least one of the following is true: + +- The `switch` statement contains a reachable `break` statement that exits the `switch` statement. +- The `switch` statement is reachable, the switch expression is a non-constant value, and no `default` label is present. +- The `switch` statement is reachable, the switch expression is a constant value that doesn’t match any `case` label, and no `default` label is present. + +If a `case` label is unreachable, a compile-time occurs. (However, it is *not* a compile-time error for a `default` label to be unreachable). +> *Example*: > > ```csharp -> switch (i) +> switch (shape) > { +> … +> case var x: +> … +> case var _: // error: unreachable, as previous case always matches +> … > default: -> CaseAny(); -> break; -> case 1: -> CaseZeroOrOne(); -> goto default; -> case 0: -> CaseZero(); -> goto case 1; +> … // no error: unreachable, but permitted > } > ``` > -> *end note* - +> *end example* - -> *Note*: The statement list of a switch section typically ends in a `break`, `goto case`, or `goto default` statement, but any construct that renders the end point of the statement list unreachable is permitted. For example, a `while` statement controlled by the Boolean expression `true` is known to never reach its end point. Likewise, a `throw` or `return` statement always transfers control elsewhere and never reaches its end point. Thus, the following example is valid: +A pattern variable declared in a *switch_label* is definitely assigned ([§9.4](variables.md#94-definite-assignment)) in its case block if and only if that case block contains precisely one *switch_label*. + +> *Example*: > > ```csharp -> switch (i) +> public static double ComputeArea(object shape) > { -> case 0: -> while (true) -> { -> F(); -> } -> case 1: -> throw new ArgumentException(); -> case 2: -> return; +> switch (shape) +> { +> case Square s when s.Side == 0: +> case Circle c when c.Radius == 0: +> case Triangle t when t.Base == 0 || t.Height == 0: +> case Rectangle r when r.Length == 0 || r.Height == 0: +> // none of s, c, t, or r is definitely assigned +> return 0; +> case Square s: +> // s is definitely assigned +> return s.Side * s.Side; +> case Circle c: +> // c is definitely assigned +> return c.Radius * c.Radius * Math.PI; +> … +> } > } > ``` > -> *end note* - +> *end example* - -> *Example*: The governing type of a `switch` statement can be the type `string`. For example: +> *Example*: The following code shows a succinct use of the when clause: > > ```csharp -> void DoCommand(string command) +> static object CreateShape(string shapeDescription) > { -> switch (command.ToLower()) -> { -> case "run": -> DoRun(); -> break; -> case "save": -> DoSave(); -> break; -> case "quit": -> DoQuit(); -> break; +> switch (shapeDescription) +> { +> case "circle": +> return new Circle(2); +> … +> case var o when (o?.Trim().Length ?? 0) == 0: +> return null; > default: -> InvalidCommand(command); -> break; +> return "invalid shape description"; > } > } > ``` > -> *end example* - - - -> *Note*: Like the string equality operators ([§11.11.8](expressions.md#11118-string-equality-operators)), the `switch` statement is case sensitive and will execute a given switch section only if the switch expression string exactly matches a `case` label constant. *end note* -When the governing type of a `switch` statement is `string` or a nullable value type, the value `null` is permitted as a `case` label constant. - -The *statement_list*s of a *switch_block* may contain declaration statements ([§12.6](statements.md#126-declaration-statements)). The scope of a local variable or constant declared in a switch block is the switch block. - -The statement list of a given switch section is reachable if the `switch` statement is reachable and at least one of the following is true: - -- The switch expression is a non-constant value. -- The switch expression is a constant value that matches a `case` label in the switch section. -- The switch expression is a constant value that doesn’t match any `case` label, and the switch section contains the `default` label. -- A switch label of the switch section is referenced by a reachable `goto case` or `goto default` statement. - -The end point of a `switch` statement is reachable if at least one of the following is true: - -- The `switch` statement contains a reachable `break` statement that exits the `switch` statement. -- The `switch` statement is reachable, the switch expression is a non-constant value, and no `default` label is present. -- The `switch` statement is reachable, the switch expression is a constant value that doesn’t match any `case` label, and no `default` label is present. +> The var case matches `null`, the empty string, or any string that contains only white space. *end example* ## 12.9 Iteration statements @@ -1130,11 +1122,13 @@ The `goto` statement transfers control to a statement that is marked by a label. ```ANTLR goto_statement : 'goto' identifier ';' - | 'goto' 'case' constant_expression ';' + | 'goto' 'case' constant_pattern ';' | 'goto' 'default' ';' ; ``` +> Note to TG2 members: This grammar change is *not* substantive, as *constant_pattern* expands to *constant_expression* anyway, but now that we have introduced the notion of patterns, it seems appropriate to admit that the old-style case labels were really constant patterns. + The target of a `goto` *identifier* statement is the labeled statement with the given label. If a label with the given name does not exist in the current function member, or if the `goto` statement is not within the scope of the label, a compile-time error occurs. > *Note*: This rule permits the use of a `goto` statement to transfer control *out of* a nested scope, but not *into* a nested scope. In the example @@ -1177,10 +1171,12 @@ The target of a `goto` *identifier* statement is the labeled statement with the > > *end note* -The target of a `goto case` statement is the statement list in the immediately enclosing `switch` statement ([§12.8.3](statements.md#1283-the-switch-statement)) which contains a`case` label with the given constant value. If the `goto case` statement is not enclosed by a `switch` statement, if the *constant_expression* is not implicitly convertible ([§10.2](conversions.md#102-implicit-conversions)) to the governing type of the nearest enclosing `switch` statement, or if the nearest enclosing `switch` statement does not contain a `case` label with the given constant value, a compile-time error occurs. +The target of a `goto case` statement is the statement list in the immediately enclosing `switch` statement ([§12.8.3](statements.md#1283-the-switch-statement)) which contains a `case` label with the given *constant_pattern*. If the `goto case` statement is not enclosed by a `switch` statement or if the nearest enclosing `switch` statement does not contain a `case` label with the given *constant_pattern*, a compile-time error occurs. The target of a `goto default` statement is the statement list in the immediately enclosing `switch` statement ([§12.8.3](statements.md#1283-the-switch-statement)), which contains a `default` label. If the `goto default` statement is not enclosed by a `switch` statement, or if the nearest enclosing `switch` statement does not contain a `default` label, a compile-time error occurs. +It is a compile-time error for *constant_pattern* to target a *switch_label* containing a *case_guard*. + A `goto` statement cannot exit a `finally` block ([§12.11](statements.md#1211-the-try-statement)). When a `goto` statement occurs within a `finally` block, the target of the `goto` statement shall be within the same `finally` block, or otherwise a compile-time error occurs. A `goto` statement is executed as follows: diff --git a/standard/variables.md b/standard/variables.md index 658d681b8..26c0e2d38 100644 --- a/standard/variables.md +++ b/standard/variables.md @@ -112,7 +112,7 @@ Within an instance constructor of a struct type, the `this` keyword behaves exac ### 9.2.8 Local variables -A ***local variable*** is declared by a *local_variable_declaration*, *foreach_statement*, or *specific_catch_clause* of a *try_statement*. For a *foreach_statement*, the local variable is an iteration variable ([§12.9.5](statements.md#1295-the-foreach-statement)). For a *specific_catch_clause*, the local variable is an exception variable ([§12.11](statements.md#1211-the-try-statement)). A local variable declared by a *foreach_statement* or *specific_catch_clause* is considered initially assigned. +A ***local variable*** is declared by a *local_variable_declaration*, *foreach_statement*, or *specific_catch_clause* of a *try_statement*. A local variable can also be declared by certain kinds of *pattern*s (§patterns-new-clause). For a *foreach_statement*, the local variable is an iteration variable ([§12.9.5](statements.md#1295-the-foreach-statement)). For a *specific_catch_clause*, the local variable is an exception variable ([§12.11](statements.md#1211-the-try-statement)). A local variable declared by a *foreach_statement* or *specific_catch_clause* is considered initially assigned. A *local_variable_declaration* can occur in a *block*, a *for_statement*, a *switch_block*, or a *using_statement*.