From 5ff42569f6518d3366a36add45811953c1c11f5d Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Tue, 24 Nov 2020 12:42:49 -0500 Subject: [PATCH 01/20] Update lexical-structure.md --- standard/lexical-structure.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index e245b8a51..c44326b14 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -65,9 +65,9 @@ The productions for *simple_name* ([§12.8.4](expressions.md#1284-simple-names)) > > *end example* -If a sequence of tokens can be parsed (in context) as a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)), *member_access* ([§12.8.7](expressions.md#1287-member-access)), or *pointer_member_access* ([§23.6.3](unsafe-code.md#2363-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 +If a sequence of tokens can be parsed (in context) as a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)), *member_access* ([§12.8.7](expressions.md#1286-member-access)), or *pointer_member_access* ([§23.6.3](unsafe-code.md#2363-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 the following: -- One of `( ) ] } : ; , . ? == != | ^ && || & [`; or +` ( ) ] : ; , . ? == !=` *identifier* - 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. @@ -77,7 +77,8 @@ If the following token is among this list, or an identifier in such a context, t > *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* - +> *Note*: In an *argument_value* of the form `out local_variable_type? variable_reference`, *local_variable_type* may be a generic type; for example: `F(out A name)`. As the language grammar for the argument uses *variable_reference* (which is really *expression*), this context is subject to the disambiguation rule. In this case the closing `>` is followed by an identifier. *end note* + > *Example*: The statement: > > @@ -123,6 +124,7 @@ If the following token is among this list, or an identifier in such a context, t > The case label `case A C:` uses a declaration pattern. > > *end example* + A *relational_expression* ([§12.12.1](expressions.md#12121-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 it as a type (XREF TO 7.8.1 NAMESPACES AND TYPES); however, if that fails, it is bound as an expression, and the result must be a constant. @@ -560,6 +562,10 @@ The semantics of an identifier named `_` depends on the context in which it appe Identifiers containing two consecutive underscore characters (`U+005F`) are reserved for use by the implementation; however, no diagnostic is required if such an identifier is defined. > *Note*: For example, an implementation might provide extended keywords that begin with two underscores. *end note* + + + +> *Note*: Although a programmer can declare an identifier named `_`, in certain contexts, that name has pre-defined semantics. See §discards-new-clause. *end note* ### 6.4.4 Keywords From bb1a2888881b4bec06c11c8024a7a0dc6db91cc1 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Tue, 24 Nov 2020 12:52:20 -0500 Subject: [PATCH 02/20] Update variables.md --- standard/variables.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/variables.md b/standard/variables.md index 36a276785..fb8485b06 100644 --- a/standard/variables.md +++ b/standard/variables.md @@ -12,7 +12,7 @@ As described in the following subclauses, variables are either ***initially assi ### 9.2.1 General -C# defines seven categories of variables: static variables, instance variables, array elements, value parameters, reference parameters, output parameters, and local variables. The subclauses that follow describe each of these categories. +C# defines the following categories of variables: static variables, instance variables, array elements, value parameters, reference parameters, output parameters, local variables, and discards. The subclauses that follow describe each of these categories. > *Example*: In the following code > @@ -974,7 +974,7 @@ For an expression *expr* of the form: ## 9.5 Variable references -A *variable_reference* is an *expression* that is classified as a variable. A *variable_reference* denotes a storage location that can be accessed both to fetch the current value and to store a new value. +A *variable_reference* is an *expression* that is classified as a variable. Except in the case of a discard (§discards-new-clause), a *variable_reference* denotes a storage location that can be accessed both to fetch the current value and to store a new value. ```ANTLR variable_reference From 26f27278a8c67aa753f9574475fc1637eeffffe7 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Tue, 24 Nov 2020 13:08:12 -0500 Subject: [PATCH 03/20] Update expressions.md --- standard/expressions.md | 56 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 8a97f737a..ec05a9b0f 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -549,7 +549,7 @@ argument_name argument_value : expression | 'ref' variable_reference - | 'out' variable_reference + | 'out' local_variable_type? variable_reference ; ``` @@ -559,7 +559,55 @@ The *argument_value* can take one of the following forms: - An *expression*, indicating that the argument is passed as a value parameter ([§15.6.2.2](classes.md#15622-value-parameters)). - The keyword `ref` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as a reference parameter ([§15.6.2.3](classes.md#15623-reference-parameters)). A variable shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) before it can be passed as a reference parameter. -- The keyword `out` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as an output parameter ([§15.6.2.4](classes.md#15624-output-parameters)). A variable is considered definitely assigned ([§9.4](variables.md#94-definite-assignment)) following a function member invocation in which the variable is passed as an output parameter. +- The keyword `out`, optionally followed by *local_variable_type* ([§13.6.2](statements.md#1362-local-variable-declarations)), followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as an output parameter ([§15.6.2.4](classes.md#15624-output-parameters)). If *variable_reference* is not a discard, the variable it designates is considered definitely assigned ([§9.4](variables.md#94-definite-assignment)) following a function member invocation in which the variable is passed as an output parameter. In this context, the variable designated by *variable_reference* is known as an *out variable*. + +If an out variable has no *local_variable_type* and its *variable_reference* is not `_`, its *variable_reference* shall designate an in-scope variable whose type is the same as that of the corresponding parameter in the signature of the method selected by overload resolution. + +If *local_variable_type* is present and its *variable_reference* is not `_`, the out variable is declared as a local variable. If *local_variable_type* is `var`, the local variable is implicitly typed to that of the corresponding parameter in the signature of the method selected by overload resolution. Otherwise, the local variable is explicitly typed, and that type shall be the same as that of the corresponding parameter in the signature of the method selected by overload resolution. + +A local variable’s scope is the same as for a *pattern_variable* ([$$]()). Within that scope, it is an error to refer to that local variable in a textual position that precedes its declaration. It is also an error to reference an implicitly typed out variable in the same argument list that immediately contains its declaration. + +> TODO: Resolve link to *pattern_variable* + +For an out variable with a *variable_reference* `_`, if no variable named `_` is in scope, the *variable_reference* is a discard. Otherwise, a variable named `_` is in scope, in which case, if the out variable has a *local_variable_type*, the *variable_reference* is a discard; otherwise, *variable_reference* refers to the named variable. + +> *Example*: +> Given the following method definition: +> +> ```csharp +> static void M(out string p1, out double p2, out int p3) { … } +> ``` +> +> here are some valid and invalid calls to it: +> +> ```csharp +> string ps1; double pd1; int pi1; +> M(out ps1, out pd1, out pi1); // 3 existing variables with compatible types +> M(out pd1, out pi1, out ps1); // Error: 3 existing with incompatible types +> M(out ps1, out double pd2, out int pi2); // 1 existing; 2 new ones declared +> var ps2 = ""; +> M(out ps2, out var pd3, out int pi3); // 1 existing; 2 new ones declared +> M(out _, out var _, out int _); // Error: forward ref to local variable, 2 discards +> M(out string _, out var _, out int _); // 3 discards +> string _; // declare local variable _ +> M(out _, out pd1, out pi1); // 3 existing variables +> M(out _, out var _, out int _); // 1 existing variable, 2 discards +> M(out string _, out var _, out int _); // 3 discards +> M(out _, out _, out _); // Error: 3 local variables, last 2 have incompatible types +> ``` +> +> Given the previous method definition, here are some valid and invalid calls to it. No local variable called `_` is in scope of the calls: +> +> ```csharp +> double pd1; int pi1; +> M(out _, out pd1, out pi1); // 1 untyped discard, 2 existing variables +> M(out _, out var _, out int _); // 1 untyped discard, 2 typed discards +> M(out _, out float _, out char _); // Error: typed discards have incompatible types +> M(out string _, out var _, out int _); // 3 typed discards +> M(out _, out _, out _); // 3 untyped discards +> ``` +> +> *end example* The form determines the ***parameter-passing mode*** of the argument: *value*, *reference*, or *output*, respectively. @@ -6051,7 +6099,7 @@ assignment_operator The left operand of an assignment shall be an expression classified as a variable, a property access, an indexer access, an event access or a tuple. A declaration expression is not directly permitted as a left operand, but may occur as a step in the evaluation of a deconstructing assignment. -The `=` operator is called the ***simple assignment operator***. It assigns the value or values of the right operand to the variable, property, indexer element or tuple elements given by the left operand. The left operand of the simple assignment operator shall not be an event access (except as described in [§15.8.2](classes.md#1582-field-like-events)). The simple assignment operator is described in [§12.21.2](expressions.md#12212-simple-assignment). +The `=` operator is called the ***simple assignment operator***. When the left operand is not a discard (§9.2.8.1), this operator assigns the value of the right operand to the variable, property, or indexer element given by the left operand. Otherwise, the right operand is evaluated with its value going unused. The left operand of the simple assignment operator shall not be an event access (except as described in [§15.8.2](classes.md#1582-field-like-events)). The simple assignment operator is described in [§12.21.2](expressions.md#12212-simple-assignment). The assignment operators other than the `=` operator are called the ***compound assignment operators***. These operators perform the indicated operation on the two operands, and then assign the resulting value to the variable, property, or indexer element given by the left operand. The left operand of a compound assignment operator shall not be a tuple or a discard. The compound assignment operators are described in [§12.21.3](expressions.md#12213-compound-assignment). @@ -6065,6 +6113,8 @@ The assignment operators are right-associative, meaning that operations are grou The `=` operator is called the simple assignment operator. +If the left operand of a simple assignment is a discard (§9.2.8.1), the right operand is evaluated. Otherwise, the remainder of this subclause applies. + If the left operand of a simple assignment is of the form `E.P` or `E[Ei]` where `E` has the compile-time type `dynamic`, then the assignment is dynamically bound ([§12.3.3](expressions.md#1233-dynamic-binding)). In this case, the compile-time type of the assignment expression is `dynamic`, and the resolution described below will take place at run-time based on the run-time type of `E`. If the left operand is of the form `E[Ei]` where at least one element of `Ei` has the compile-time type `dynamic`, and the compile-time type of `E` is not an array, the resulting indexer access is dynamically bound, but with limited compile-time checking ([§12.6.5](expressions.md#1265-compile-time-checking-of-dynamic-member-invocation)). A simple assignment where the left operand is classified as a tuple is also called a ***deconstructing assignment***. If any of the tuple elements of the left operand has an element name, a compile-time error occurs. If any of the tuple elements of the left operand is a *declaration_expression* and any other element is not a *declaration_expression* or a simple discard, a compile-time error occurs. From 82913af202768d42480a15f2f7524e841d7f0819 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Tue, 24 Nov 2020 13:12:43 -0500 Subject: [PATCH 04/20] Update classes.md --- standard/classes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 4b7acf690..70ecce558 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2161,13 +2161,13 @@ In a method that takes reference parameters, it is possible for multiple names t #### 15.6.2.4 Output parameters -A parameter declared with an `out` modifier is an output parameter. Similar to a reference parameter, an output parameter does not create a new storage location. Instead, an output parameter represents the same storage location as the variable given as the argument in the method invocation. +A parameter declared with an `out` modifier is an output parameter. Except in the case of a discard (§discards-new-clause), an output parameter represents the same storage location as the variable given as the argument in the method invocation. -When a formal parameter is an output parameter, the corresponding argument in a method invocation shall consist of the keyword `out` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)) of the same type as the formal parameter. A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, the variable is considered definitely assigned. +When a formal parameter is an output parameter, the corresponding argument in a method invocation shall consist of the keyword `out`, optionally followed by *local_variable_type*, followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)) of the same type as the formal parameter, or declared `var`. A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, except in the case of a discard, the variable is considered definitely assigned. -Within a method, just like a local variable, an output parameter is initially considered unassigned and shall be definitely assigned before its value is used. +Within a method, just like a local variable, an output parameter is initially considered unassigned. -Every output parameter of a method shall be definitely assigned before the method returns. +Except in the case of a discard, every output parameter of a method shall be definitely assigned before the method returns. A method declared as a partial method ([§15.6.9](classes.md#1569-partial-methods)) or an iterator ([§15.14](classes.md#1514-iterators)) may not have output parameters. From be8c9543b42f2bd6a4092cd112b439377cab9823 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Fri, 2 Apr 2021 10:22:30 -0400 Subject: [PATCH 05/20] Fixup link for local variable scope to new patterns subclause Part of adding V7.3 support for out variables in extra places. --- standard/expressions.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index ec05a9b0f..394c643b5 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -565,9 +565,7 @@ If an out variable has no *local_variable_type* and its *variable_reference* is If *local_variable_type* is present and its *variable_reference* is not `_`, the out variable is declared as a local variable. If *local_variable_type* is `var`, the local variable is implicitly typed to that of the corresponding parameter in the signature of the method selected by overload resolution. Otherwise, the local variable is explicitly typed, and that type shall be the same as that of the corresponding parameter in the signature of the method selected by overload resolution. -A local variable’s scope is the same as for a *pattern_variable* ([$$]()). Within that scope, it is an error to refer to that local variable in a textual position that precedes its declaration. It is also an error to reference an implicitly typed out variable in the same argument list that immediately contains its declaration. - -> TODO: Resolve link to *pattern_variable* +The local variable’s scope is the same as for a local variable created by a pattern (§patterns-new-clause). Within that scope, it is an error to refer to that local variable in a textual position that precedes its declaration. It is also an error to reference an implicitly typed out variable in the same argument list that immediately contains its declaration. For an out variable with a *variable_reference* `_`, if no variable named `_` is in scope, the *variable_reference* is a discard. Otherwise, a variable named `_` is in scope, in which case, if the out variable has a *local_variable_type*, the *variable_reference* is a discard; otherwise, *variable_reference* refers to the named variable. From e63bd171ff6f84c083e12f8a5c157dc012683992 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 1 Apr 2022 15:35:14 -0400 Subject: [PATCH 06/20] Fix markdown lint errors, which included a missed conflict --- standard/expressions.md | 2 +- standard/lexical-structure.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 394c643b5..14b31b9a3 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -563,7 +563,7 @@ The *argument_value* can take one of the following forms: If an out variable has no *local_variable_type* and its *variable_reference* is not `_`, its *variable_reference* shall designate an in-scope variable whose type is the same as that of the corresponding parameter in the signature of the method selected by overload resolution. -If *local_variable_type* is present and its *variable_reference* is not `_`, the out variable is declared as a local variable. If *local_variable_type* is `var`, the local variable is implicitly typed to that of the corresponding parameter in the signature of the method selected by overload resolution. Otherwise, the local variable is explicitly typed, and that type shall be the same as that of the corresponding parameter in the signature of the method selected by overload resolution. +If *local_variable_type* is present and its *variable_reference* is not `_`, the out variable is declared as a local variable. If *local_variable_type* is `var`, the local variable is implicitly typed to that of the corresponding parameter in the signature of the method selected by overload resolution. Otherwise, the local variable is explicitly typed, and that type shall be the same as that of the corresponding parameter in the signature of the method selected by overload resolution. The local variable’s scope is the same as for a local variable created by a pattern (§patterns-new-clause). Within that scope, it is an error to refer to that local variable in a textual position that precedes its declaration. It is also an error to reference an implicitly typed out variable in the same argument list that immediately contains its declaration. diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index c44326b14..e2f463bc6 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -67,7 +67,7 @@ The productions for *simple_name* ([§12.8.4](expressions.md#1284-simple-names)) If a sequence of tokens can be parsed (in context) as a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)), *member_access* ([§12.8.7](expressions.md#1286-member-access)), or *pointer_member_access* ([§23.6.3](unsafe-code.md#2363-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 the following: -` ( ) ] : ; , . ? == !=` *identifier* +- ` ( ) ] : ; , . ? == !=` *identifier* - 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. From 500de8833539d2c81ad829c4b19b96872304d98d Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Mon, 20 Jun 2022 04:43:25 -0400 Subject: [PATCH 07/20] undo earlier edits This text has been moved to PR 596. --- standard/lexical-structure.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index e2f463bc6..b2d3366b2 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -564,9 +564,6 @@ Identifiers containing two consecutive underscore characters (`U+005F`) are rese > *Note*: For example, an implementation might provide extended keywords that begin with two underscores. *end note* - -> *Note*: Although a programmer can declare an identifier named `_`, in certain contexts, that name has pre-defined semantics. See §discards-new-clause. *end note* - ### 6.4.4 Keywords A ***keyword*** is an identifier-like sequence of characters that is reserved, and cannot be used as an identifier except when prefaced by the `@` character. From 2a6b252eb04837fb55f669962c637b3e0ea77553 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Mon, 20 Jun 2022 04:50:44 -0400 Subject: [PATCH 08/20] undo previous edits Some of this text has been moved to PR 596 --- standard/variables.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/variables.md b/standard/variables.md index fb8485b06..1254be57c 100644 --- a/standard/variables.md +++ b/standard/variables.md @@ -12,7 +12,7 @@ As described in the following subclauses, variables are either ***initially assi ### 9.2.1 General -C# defines the following categories of variables: static variables, instance variables, array elements, value parameters, reference parameters, output parameters, local variables, and discards. The subclauses that follow describe each of these categories. +C# defines the following categories of variables: static variables, instance variables, array elements, value parameters, reference parameters, output parameters, and local variables. The subclauses that follow describe each of these categories. > *Example*: In the following code > @@ -974,7 +974,7 @@ For an expression *expr* of the form: ## 9.5 Variable references -A *variable_reference* is an *expression* that is classified as a variable. Except in the case of a discard (§discards-new-clause), a *variable_reference* denotes a storage location that can be accessed both to fetch the current value and to store a new value. +A *variable_reference* is an *expression* that is classified as a variable. A *variable_reference* denotes a storage location that can be accessed both to fetch the current value and to store a new value. ```ANTLR variable_reference From e0e94404bbcd062c1dee6abbd36cecd2cd9bf1cd Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Mon, 20 Jun 2022 04:59:24 -0400 Subject: [PATCH 09/20] add new conversion --- standard/conversions.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/standard/conversions.md b/standard/conversions.md index f559542ac..ae3a10c5a 100644 --- a/standard/conversions.md +++ b/standard/conversions.md @@ -351,6 +351,10 @@ An implicit conversion exists from a *default_literal* ([§12.8.20](expressions. While throw expressions do not have a type, they may be implicitly converted to any type. +### §imp-typed-out-var Implicitly-typed out variables + +There is a conversion from an implicitly-typed out variable ([§11.6.2](expressions.md#1162-argument-lists)) to every type. + ## 10.3 Explicit conversions ### 10.3.1 General From 30d23715d2f41203cdf9d4b08a093764ed5c25a9 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Mon, 20 Jun 2022 05:24:17 -0400 Subject: [PATCH 10/20] undo earlier edits - Overhauled argument list text - Added better conversion text - Removed discards-in-assignment text --- standard/expressions.md | 81 +++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 14b31b9a3..f0396449e 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -549,7 +549,7 @@ argument_name argument_value : expression | 'ref' variable_reference - | 'out' local_variable_type? variable_reference + | 'out' local_variable_type? identifier ; ``` @@ -558,55 +558,54 @@ An *argument_list* consists of one or more *argument*s, separated by commas. Eac The *argument_value* can take one of the following forms: - An *expression*, indicating that the argument is passed as a value parameter ([§15.6.2.2](classes.md#15622-value-parameters)). -- The keyword `ref` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as a reference parameter ([§15.6.2.3](classes.md#15623-reference-parameters)). A variable shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) before it can be passed as a reference parameter. -- The keyword `out`, optionally followed by *local_variable_type* ([§13.6.2](statements.md#1362-local-variable-declarations)), followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as an output parameter ([§15.6.2.4](classes.md#15624-output-parameters)). If *variable_reference* is not a discard, the variable it designates is considered definitely assigned ([§9.4](variables.md#94-definite-assignment)) following a function member invocation in which the variable is passed as an output parameter. In this context, the variable designated by *variable_reference* is known as an *out variable*. +- The keyword `ref` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as a reference parameter ([§15.6.2.3](classes.md#14623-reference-parameters)). A variable shall be definitely assigned ([§9.5](variables.md#94-definite-assignment)) before it can be passed as a reference parameter. +- The keyword `out`, optionally followed by *local_variable_type* ([§13.6.2](statements.md#1262-local-variable-declarations)), followed by *identifier*, indicating that the argument is passed as an output parameter ([§15.6.2.4](classes.md#15624-output-parameters)). If *identifier* is not a discard (§9.2.8.1), the variable it designates is considered definitely assigned ([§9.4](variables.md#94-definite-assignment)) following a function member invocation in which the variable is passed as an output parameter. In this context, the variable designated by *identifier* is known as an ***out variable***. -If an out variable has no *local_variable_type* and its *variable_reference* is not `_`, its *variable_reference* shall designate an in-scope variable whose type is the same as that of the corresponding parameter in the signature of the method selected by overload resolution. +*identifier* denotes a new variable, an existing variable, or a discard depending on the context. Specifically, -If *local_variable_type* is present and its *variable_reference* is not `_`, the out variable is declared as a local variable. If *local_variable_type* is `var`, the local variable is implicitly typed to that of the corresponding parameter in the signature of the method selected by overload resolution. Otherwise, the local variable is explicitly typed, and that type shall be the same as that of the corresponding parameter in the signature of the method selected by overload resolution. - -The local variable’s scope is the same as for a local variable created by a pattern (§patterns-new-clause). Within that scope, it is an error to refer to that local variable in a textual position that precedes its declaration. It is also an error to reference an implicitly typed out variable in the same argument list that immediately contains its declaration. - -For an out variable with a *variable_reference* `_`, if no variable named `_` is in scope, the *variable_reference* is a discard. Otherwise, a variable named `_` is in scope, in which case, if the out variable has a *local_variable_type*, the *variable_reference* is a discard; otherwise, *variable_reference* refers to the named variable. +- If *local_variable_type* is present + - If *identifier* is `_`, it is interpreted as a typed discard + - Otherwise, *identifier* denotes a new local variable. It is a compile-time error if a variable by that name is currently in scope or if there is not an implicit conversion between the corresponding parameter’s type and *local_variable_type*. > *Example*: -> Given the following method definition: -> -> ```csharp -> static void M(out string p1, out double p2, out int p3) { … } -> ``` -> -> here are some valid and invalid calls to it: -> > ```csharp -> string ps1; double pd1; int pi1; -> M(out ps1, out pd1, out pi1); // 3 existing variables with compatible types -> M(out pd1, out pi1, out ps1); // Error: 3 existing with incompatible types -> M(out ps1, out double pd2, out int pi2); // 1 existing; 2 new ones declared -> var ps2 = ""; -> M(out ps2, out var pd3, out int pi3); // 1 existing; 2 new ones declared -> M(out _, out var _, out int _); // Error: forward ref to local variable, 2 discards -> M(out string _, out var _, out int _); // 3 discards -> string _; // declare local variable _ -> M(out _, out pd1, out pi1); // 3 existing variables -> M(out _, out var _, out int _); // 1 existing variable, 2 discards -> M(out string _, out var _, out int _); // 3 discards -> M(out _, out _, out _); // Error: 3 local variables, last 2 have incompatible types +> static void M(out int x) { … } +> static void CallM1() +> { +> int not_; +> M(out not_); // OK: untyped existing variable +> M(out _); // OK: untyped discard +> M(out int not_); // error: new variable but a variable by that name already exists +> M(out int not_2); // OK: new variable +> M(out uint pu); // error: new variable but has incompatible type +> M(out int _); // OK: typed discard +> M(out var not_3); // OK: typed new variable +> M(out var _); // OK: typed discard +> } > ``` -> -> Given the previous method definition, here are some valid and invalid calls to it. No local variable called `_` is in scope of the calls: -> +> *end example* + +- If *local_variable_type* is absent + - If *identifier* is `_` + - If an existing variable with that name is in-scope, *identifier* denotes that variable. However, it shall not precede that variable’s declaration. + - Otherwise, *identifier* is interpreted as an untyped discard. + +> *Example*: > ```csharp -> double pd1; int pi1; -> M(out _, out pd1, out pi1); // 1 untyped discard, 2 existing variables -> M(out _, out var _, out int _); // 1 untyped discard, 2 typed discards -> M(out _, out float _, out char _); // Error: typed discards have incompatible types -> M(out string _, out var _, out int _); // 3 typed discards -> M(out _, out _, out _); // 3 untyped discards +> static void M(out int x) { … } +> static void CallM2() +> { +> int not_; +> M(out _); // error: ref to variable before it is declared +> int _ = -5; // declaration of variable _ +> M(out _); // OK: existing variable +> } > ``` -> > *end example* +It is also an error to reference an implicitly-typed out variable in the same argument list that immediately contains its declaration. +The type of an implicitly-typed out variable is the type of the corresponding parameter in the signature of the method selected by overload resolution. + The form determines the ***parameter-passing mode*** of the argument: *value*, *reference*, or *output*, respectively. Passing a volatile field ([§15.5.4](classes.md#1554-volatile-fields)) as a reference parameter or output parameter causes a warning, since the field may not be treated as volatile by the invoked method. @@ -1079,6 +1078,8 @@ Given an implicit conversion `C₁` that converts from an expression `E` to a ty - `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a better conversion target than `T₂` ([§12.6.4.6](expressions.md#12646-better-conversion-target)) - `E` is a method group ([§12.2](expressions.md#122-expression-classifications)), `T₁` is compatible ([§20.4](delegates.md#204-delegate-compatibility)) with the single best method from the method group for conversion `C₁`, and `T₂` is not compatible with the single best method from the method group for conversion `C₂` +The conversion from an implicitly-typed out variable declaration is not considered better than any other conversion from expression. + #### 12.6.4.5 Exactly matching expression Given an expression `E` and a type `T`, `E` ***exactly matches*** `T` if one of the following holds: From 3adc144f0c28ed7717c116772e460a771ac1a245 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Mon, 20 Jun 2022 05:30:53 -0400 Subject: [PATCH 11/20] undo earlier edits --- standard/classes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index 70ecce558..7c28064ba 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2161,13 +2161,13 @@ In a method that takes reference parameters, it is possible for multiple names t #### 15.6.2.4 Output parameters -A parameter declared with an `out` modifier is an output parameter. Except in the case of a discard (§discards-new-clause), an output parameter represents the same storage location as the variable given as the argument in the method invocation. +A parameter declared with an `out` modifier is an output parameter. An output parameter represents the same storage location as the variable given as the argument in the method invocation, except that for a discard argument, there is no variable, and any value assigned to that output parameter is instead discarded. -When a formal parameter is an output parameter, the corresponding argument in a method invocation shall consist of the keyword `out`, optionally followed by *local_variable_type*, followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)) of the same type as the formal parameter, or declared `var`. A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, except in the case of a discard, the variable is considered definitely assigned. +When a formal parameter is an output parameter, the corresponding argument in a method invocation shall consist of the keyword `out`, optionally followed by *local_variable_type*, followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)) of the same type as the formal parameter, or declared `var`. A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, the variable is considered definitely assigned. -Within a method, just like a local variable, an output parameter is initially considered unassigned. +Within a method, just like a local variable, an output parameter is initially considered unassigned and shall be definitely assigned before its value is used. -Except in the case of a discard, every output parameter of a method shall be definitely assigned before the method returns. +Every output parameter of a method shall be definitely assigned before the method returns. A method declared as a partial method ([§15.6.9](classes.md#1569-partial-methods)) or an iterator ([§15.14](classes.md#1514-iterators)) may not have output parameters. From 7cd6bcc647fc61c705ead730c5ec241e7407c627 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Mon, 20 Jun 2022 05:37:04 -0400 Subject: [PATCH 12/20] var-ref becomes identifier --- standard/classes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/classes.md b/standard/classes.md index 7c28064ba..fe4b70ff1 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2163,7 +2163,7 @@ In a method that takes reference parameters, it is possible for multiple names t A parameter declared with an `out` modifier is an output parameter. An output parameter represents the same storage location as the variable given as the argument in the method invocation, except that for a discard argument, there is no variable, and any value assigned to that output parameter is instead discarded. -When a formal parameter is an output parameter, the corresponding argument in a method invocation shall consist of the keyword `out`, optionally followed by *local_variable_type*, followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)) of the same type as the formal parameter, or declared `var`. A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, the variable is considered definitely assigned. +When a formal parameter is an output parameter, the corresponding argument in a method invocation shall consist of the keyword `out`, optionally followed by *local_variable_type*, followed by *identifier* of the same type as the formal parameter, or declared `var`. A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, the variable is considered definitely assigned. Within a method, just like a local variable, an output parameter is initially considered unassigned and shall be definitely assigned before its value is used. From f39b9273ba2f42aa4efd53eb2c459100fc338e16 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Mon, 20 Jun 2022 05:55:05 -0400 Subject: [PATCH 13/20] fix spacing --- standard/expressions.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/standard/expressions.md b/standard/expressions.md index f0396449e..38e56ffbb 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -568,6 +568,7 @@ The *argument_value* can take one of the following forms: - Otherwise, *identifier* denotes a new local variable. It is a compile-time error if a variable by that name is currently in scope or if there is not an implicit conversion between the corresponding parameter’s type and *local_variable_type*. > *Example*: +> > ```csharp > static void M(out int x) { … } > static void CallM1() @@ -583,6 +584,7 @@ The *argument_value* can take one of the following forms: > M(out var _); // OK: typed discard > } > ``` +> > *end example* - If *local_variable_type* is absent @@ -591,6 +593,7 @@ The *argument_value* can take one of the following forms: - Otherwise, *identifier* is interpreted as an untyped discard. > *Example*: +> > ```csharp > static void M(out int x) { … } > static void CallM2() @@ -601,6 +604,7 @@ The *argument_value* can take one of the following forms: > M(out _); // OK: existing variable > } > ``` +> > *end example* It is also an error to reference an implicitly-typed out variable in the same argument list that immediately contains its declaration. From faa8a55f42561748c081534033af7158d82d49cd Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Tue, 21 Jun 2022 04:02:57 -0400 Subject: [PATCH 14/20] fix spacing --- standard/expressions.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 38e56ffbb..4db2e5f9b 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -587,7 +587,7 @@ The *argument_value* can take one of the following forms: > > *end example* -- If *local_variable_type* is absent +- If *local_variable_type* is absent - If *identifier* is `_` - If an existing variable with that name is in-scope, *identifier* denotes that variable. However, it shall not precede that variable’s declaration. - Otherwise, *identifier* is interpreted as an untyped discard. @@ -607,8 +607,7 @@ The *argument_value* can take one of the following forms: > > *end example* -It is also an error to reference an implicitly-typed out variable in the same argument list that immediately contains its declaration. -The type of an implicitly-typed out variable is the type of the corresponding parameter in the signature of the method selected by overload resolution. +It is also an error to reference an implicitly-typed out variable in the same argument list that immediately contains its declaration. The type of an implicitly-typed out variable is the type of the corresponding parameter in the signature of the method selected by overload resolution. The form determines the ***parameter-passing mode*** of the argument: *value*, *reference*, or *output*, respectively. From 91d0247b8d1a1c9b08fa7188fcb5879af1f929d4 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 14 Feb 2023 11:14:29 -0500 Subject: [PATCH 15/20] fix build warning --- standard/expressions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 4db2e5f9b..6bc6d5de2 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -558,8 +558,8 @@ An *argument_list* consists of one or more *argument*s, separated by commas. Eac The *argument_value* can take one of the following forms: - An *expression*, indicating that the argument is passed as a value parameter ([§15.6.2.2](classes.md#15622-value-parameters)). -- The keyword `ref` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as a reference parameter ([§15.6.2.3](classes.md#14623-reference-parameters)). A variable shall be definitely assigned ([§9.5](variables.md#94-definite-assignment)) before it can be passed as a reference parameter. -- The keyword `out`, optionally followed by *local_variable_type* ([§13.6.2](statements.md#1262-local-variable-declarations)), followed by *identifier*, indicating that the argument is passed as an output parameter ([§15.6.2.4](classes.md#15624-output-parameters)). If *identifier* is not a discard (§9.2.8.1), the variable it designates is considered definitely assigned ([§9.4](variables.md#94-definite-assignment)) following a function member invocation in which the variable is passed as an output parameter. In this context, the variable designated by *identifier* is known as an ***out variable***. +- The keyword `ref` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as a reference parameter ([§15.6.2.3](classes.md#15623-reference-parameters)). A variable shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) before it can be passed as a reference parameter. +- The keyword `out`, optionally followed by *local_variable_type* ([§13.6.2](statements.md#1362-local-variable-declarations)), followed by *identifier*, indicating that the argument is passed as an output parameter ([§15.6.2.4](classes.md#15624-output-parameters)). If *identifier* is not a discard, the variable it designates is considered definitely assigned ([§9.4](variables.md#94-definite-assignment)) following a function member invocation in which the variable is passed as an output parameter. In this context, the variable designated by *identifier* is known as an ***out variable***. *identifier* denotes a new variable, an existing variable, or a discard depending on the context. Specifically, From fb0efd83decb3adf0edf1d749c21c02e5ff7d2e5 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 14 Apr 2023 11:17:35 -0400 Subject: [PATCH 16/20] fix build warnings --- standard/conversions.md | 2 +- standard/lexical-structure.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/standard/conversions.md b/standard/conversions.md index ae3a10c5a..3cbf12355 100644 --- a/standard/conversions.md +++ b/standard/conversions.md @@ -353,7 +353,7 @@ While throw expressions do not have a type, they may be implicitly converted to ### §imp-typed-out-var Implicitly-typed out variables -There is a conversion from an implicitly-typed out variable ([§11.6.2](expressions.md#1162-argument-lists)) to every type. +There is a conversion from an implicitly-typed out variable ([§12.6.2](expressions.md#1262-argument-lists)) to every type. ## 10.3 Explicit conversions diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index b2d3366b2..64b975a25 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -65,9 +65,9 @@ The productions for *simple_name* ([§12.8.4](expressions.md#1284-simple-names)) > > *end example* -If a sequence of tokens can be parsed (in context) as a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)), *member_access* ([§12.8.7](expressions.md#1286-member-access)), or *pointer_member_access* ([§23.6.3](unsafe-code.md#2363-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 the following: +If a sequence of tokens can be parsed (in context) as a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)), *member_access* ([§12.8.7](expressions.md#1287-member-access)), or *pointer_member_access* ([§23.6.3](unsafe-code.md#2363-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 the following: -- ` ( ) ] : ; , . ? == !=` *identifier* +- `( ) ] : ; , . ? == !=` *identifier* - 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. From 9aace93788dea5900294dbeb5deb28af8e6ee6c3 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 14 Apr 2023 12:55:48 -0400 Subject: [PATCH 17/20] Final edits. --- standard/classes.md | 2 +- standard/expressions.md | 2 +- standard/lexical-structure.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index fe4b70ff1..dd85cd4b5 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -2161,7 +2161,7 @@ In a method that takes reference parameters, it is possible for multiple names t #### 15.6.2.4 Output parameters -A parameter declared with an `out` modifier is an output parameter. An output parameter represents the same storage location as the variable given as the argument in the method invocation, except that for a discard argument, there is no variable, and any value assigned to that output parameter is instead discarded. +A parameter declared with an `out` modifier is an output parameter. An output parameter represents the same storage location as the variable given as the argument in the method invocation, except that for a discard (§9.2.8.1) argument, there is no variable, and any value assigned to that output parameter is instead discarded. When a formal parameter is an output parameter, the corresponding argument in a method invocation shall consist of the keyword `out`, optionally followed by *local_variable_type*, followed by *identifier* of the same type as the formal parameter, or declared `var`. A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, the variable is considered definitely assigned. diff --git a/standard/expressions.md b/standard/expressions.md index 6bc6d5de2..c1075fbdd 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -549,7 +549,7 @@ argument_name argument_value : expression | 'ref' variable_reference - | 'out' local_variable_type? identifier + | 'out' declaration_expression? identifier ; ``` diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index 64b975a25..250ae3f68 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -65,9 +65,9 @@ The productions for *simple_name* ([§12.8.4](expressions.md#1284-simple-names)) > > *end example* -If a sequence of tokens can be parsed (in context) as a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)), *member_access* ([§12.8.7](expressions.md#1287-member-access)), or *pointer_member_access* ([§23.6.3](unsafe-code.md#2363-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 the following: +If a sequence of tokens can be parsed (in context) as a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)), *member_access* ([§12.8.7](expressions.md#1287-member-access)), or *pointer_member_access* ([§23.6.3](unsafe-code.md#2363-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 the following: -- `( ) ] : ; , . ? == !=` *identifier* +- 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. From 63cc5c939bbd5ee54430a1a4e4e008d60b8636dc Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 19 Apr 2023 12:15:04 -0400 Subject: [PATCH 18/20] Respond to pre-meeting feedback. --- standard/expressions.md | 38 +++++++++++++++++++++++++---------- standard/lexical-structure.md | 2 +- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index c1075fbdd..4982ea2c9 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -565,23 +565,24 @@ The *argument_value* can take one of the following forms: - If *local_variable_type* is present - If *identifier* is `_`, it is interpreted as a typed discard - - Otherwise, *identifier* denotes a new local variable. It is a compile-time error if a variable by that name is currently in scope or if there is not an implicit conversion between the corresponding parameter’s type and *local_variable_type*. + - Otherwise, *identifier* denotes a new local variable. It is a compile-time error if a variable by that name is currently in scope or if there is not an identity conversion between the corresponding parameter’s type and *local_variable_type*. > *Example*: > > ```csharp > static void M(out int x) { … } +> > static void CallM1() > { -> int not_; -> M(out not_); // OK: untyped existing variable +> int v; +> M(out v); // OK: untyped existing variable > M(out _); // OK: untyped discard -> M(out int not_); // error: new variable but a variable by that name already exists -> M(out int not_2); // OK: new variable +> M(out int v); // error: new variable but a variable by that name already exists +> M(out int v2); // OK: new variable > M(out uint pu); // error: new variable but has incompatible type > M(out int _); // OK: typed discard -> M(out var not_3); // OK: typed new variable -> M(out var _); // OK: typed discard +> M(out var v3); // OK: typed new variable +> M(out var _); // OK: implicitly typed discard > } > ``` > @@ -589,7 +590,7 @@ The *argument_value* can take one of the following forms: - If *local_variable_type* is absent - If *identifier* is `_` - - If an existing variable with that name is in-scope, *identifier* denotes that variable. However, it shall not precede that variable’s declaration. + - Otherwise, if an existing variable with that name is in-scope, *identifier* denotes that variable. However, it shall not precede that variable’s declaration. - Otherwise, *identifier* is interpreted as an untyped discard. > *Example*: @@ -598,7 +599,7 @@ The *argument_value* can take one of the following forms: > static void M(out int x) { … } > static void CallM2() > { -> int not_; +> int v; > M(out _); // error: ref to variable before it is declared > int _ = -5; // declaration of variable _ > M(out _); // OK: existing variable @@ -607,7 +608,22 @@ The *argument_value* can take one of the following forms: > > *end example* -It is also an error to reference an implicitly-typed out variable in the same argument list that immediately contains its declaration. The type of an implicitly-typed out variable is the type of the corresponding parameter in the signature of the method selected by overload resolution. +It is an error to reference an implicitly-typed out variable in the same argument list that immediately contains its declaration. + +> *Example*: +> +> ```csharp +> static void M(out int x, int y) { … } +> static void CallM2() +> { +> int v; +> M(out v, v); // error: ref to variable declared in the same argument list +> } +> ``` +> +> *end example* + +The type of an implicitly-typed out variable is the type of the corresponding parameter in the signature of the method selected by overload resolution. The form determines the ***parameter-passing mode*** of the argument: *value*, *reference*, or *output*, respectively. @@ -1081,7 +1097,7 @@ Given an implicit conversion `C₁` that converts from an expression `E` to a ty - `E` exactly matches both or neither of `T₁` and `T₂`, and `T₁` is a better conversion target than `T₂` ([§12.6.4.6](expressions.md#12646-better-conversion-target)) - `E` is a method group ([§12.2](expressions.md#122-expression-classifications)), `T₁` is compatible ([§20.4](delegates.md#204-delegate-compatibility)) with the single best method from the method group for conversion `C₁`, and `T₂` is not compatible with the single best method from the method group for conversion `C₂` -The conversion from an implicitly-typed out variable declaration is not considered better than any other conversion from expression. +The conversion from an implicitly-typed out variable declaration is not considered better than any other conversion from expression. #### 12.6.4.5 Exactly matching expression diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index 250ae3f68..a6e1d3d45 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -65,7 +65,7 @@ The productions for *simple_name* ([§12.8.4](expressions.md#1284-simple-names)) > > *end example* -If a sequence of tokens can be parsed (in context) as a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)), *member_access* ([§12.8.7](expressions.md#1287-member-access)), or *pointer_member_access* ([§23.6.3](unsafe-code.md#2363-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 the following: +If a sequence of tokens can be parsed (in context) as a *simple_name* ([§12.8.4](expressions.md#1284-simple-names)), *member_access* ([§12.8.7](expressions.md#1287-member-access)), or *pointer_member_access* ([§23.6.3](unsafe-code.md#2363-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 one of the following: - One of `( ) ] } : ; , . ? == != | ^ && || & [`; or - One of the relational operators `< > <= >= is as`; or From 0529a19cee5eac1adff3f96b2b58e29bfd54bcb0 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 20 Apr 2023 10:58:12 -0400 Subject: [PATCH 19/20] Apply suggestions from code review Co-authored-by: Jon Skeet Co-authored-by: Nigel-Ecma --- standard/expressions.md | 3 ++- standard/lexical-structure.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index 4982ea2c9..c95d40e1d 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -549,7 +549,8 @@ argument_name argument_value : expression | 'ref' variable_reference - | 'out' declaration_expression? identifier + | 'out' declaration_expression + | 'out' variable_reference ; ``` diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index a6e1d3d45..2f0af8458 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -77,7 +77,7 @@ If the following token is among this list, or an identifier in such a context, t > *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* -> *Note*: In an *argument_value* of the form `out local_variable_type? variable_reference`, *local_variable_type* may be a generic type; for example: `F(out A name)`. As the language grammar for the argument uses *variable_reference* (which is really *expression*), this context is subject to the disambiguation rule. In this case the closing `>` is followed by an identifier. *end note* +> *Note*: In an *argument_value* of the form `out local_variable_type? identifier`, *local_variable_type* may be a generic type; for example: `F(out A name)`. This example would be subject to the disambiguation rule ([§6.2.5](lexical-structure.md#625-grammar-ambiguities)) and is resolved correct;y as the closing `>` is followed by an identifier. *end note* > *Example*: The statement: > From 9665d98da6ae1cb54591339e0f04a121f3001d4e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 20 Apr 2023 10:59:21 -0400 Subject: [PATCH 20/20] feedback from April meeting --- standard/lexical-structure.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index 2f0af8458..ad5317a7d 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -77,8 +77,6 @@ If the following token is among this list, or an identifier in such a context, t > *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* -> *Note*: In an *argument_value* of the form `out local_variable_type? identifier`, *local_variable_type* may be a generic type; for example: `F(out A name)`. This example would be subject to the disambiguation rule ([§6.2.5](lexical-structure.md#625-grammar-ambiguities)) and is resolved correct;y as the closing `>` is followed by an identifier. *end note* - > *Example*: The statement: > >