Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 41 additions & 39 deletions standard/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1639,12 +1639,12 @@

A tuple expression has a type if and only if each of its element expressions `Ei` has a type `Ti`. The type shall be a tuple type of the same arity as the tuple expression, where each element is given by the following:

- If the tuple element in the corresponding position has a name `Ni`, then the tuple type element shall be `Ti Ni`.
- Otherwise, if `Ei` is of the form `Ni` or `E.Ni` or `E?.Ni` then the tuple type element shall be `Ti Ni`, *unless* any of the following holds:
- Another element of the tuple expression has the name `Ni`, or
- Another tuple element without a name has a tuple element expression of the form `Ni` or `E.Ni` or `E?.Ni`, or
- `Ni` is of the form `ItemX`, where `X` is a sequence of non-`0`-initiated decimal digits that could represent the position of a tuple element, and `X` does not represent the position of the element.
- Otherwise, the tuple type element shall be `Ti`.
- If the tuple element in the corresponding position has a name `Nᵢ`, then the tuple type element shall be `Tᵢ Nᵢ`.
- Otherwise, if `Eᵢ` is of the form `Nᵢ` or `E.Nᵢ` or `E?.Nᵢ` then the tuple type element shall be `Tᵢ Nᵢ`, *unless* any of the following holds:
- Another element of the tuple expression has the name `Nᵢ`, or
- Another tuple element without a name has a tuple element expression of the form `Nᵢ` or `E.Nᵢ` or `E?.Nᵢ`, or
- `Nᵢ` is of the form `ItemX`, where `X` is a sequence of non-`0`-initiated decimal digits that could represent the position of a tuple element, and `X` does not represent the position of the element.
- Otherwise, the tuple type element shall be `Tᵢ`.

A tuple expression is evaluated by evaluating each of its element expressions in order from left to right.

Expand Down Expand Up @@ -2177,8 +2177,8 @@
A *null_conditional_invocation_expression* is syntactically either a *null_conditional_member_access* ([§12.8.8](expressions.md#1288-null-conditional-member-access)) or *null_conditional_element_access* ([§12.8.13](expressions.md#12813-null-conditional-element-access)) where the final *dependent_access* is an invocation expression ([§12.8.10](expressions.md#12810-invocation-expressions)).

A *null_conditional_invocation_expression* occurs within the context of a *statement_expression* ([§13.7](statements.md#137-expression-statements)), *anonymous_function_body* ([§12.21.1](expressions.md#12211-general)), or *method_body* ([§15.6.1](classes.md#1561-general)).

Check warning on line 2180 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L2180

MDC032::Line length 84 > maximum 81
Unlike the syntactically equivalent *null_conditional_member_access* or *null_conditional_element_access*, a *null_conditional_invocation_expression* may be classified as nothing.

Check warning on line 2181 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L2181

MDC032::Line length 85 > maximum 81

```ANTLR
null_conditional_invocation_expression
Expand Down Expand Up @@ -2258,7 +2258,7 @@
- The *primary_expression* has compile-time type `dynamic`.
- At least one expression of the *argument_list* has compile-time type `dynamic`.

In this case the compile-time type of the *element_access* depends on the compile-time type of its *primary_expression*: if it has an array type then the compile-time type is the element type of that array type; otherwise the compile-time type is `dynamic` and the *element_access* is classified as a value of type `dynamic`. The rules below to determine the meaning of the *element_access* are then applied at run-time, using the run-time type instead of the compile-time type of those of the *primary_expression* and *argument_list* expressions which have the compile-time type `dynamic`. If the *primary_expression* does not have compile-time type `dynamic`, then the element access undergoes a limited compile-time check as described in [§12.6.5](expressions.md#1265-compile-time-checking-of-dynamic-member-invocation).

Check warning on line 2261 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L2261

MDC032::Line length 82 > maximum 81

> *Example*:
>
Expand Down Expand Up @@ -3396,7 +3396,7 @@
- one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool,`; or
- any enumeration type.

### 12.8.22 Stack allocation

Check warning on line 3399 in standard/expressions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/expressions.md#L3399

MDC032::Line length 86 > maximum 81

A stack allocation expression allocates a block of memory from the execution stack. The ***execution stack*** is an area of memory where local variables are stored. The execution stack is not part of the managed heap. The memory used for local variable storage is automatically recovered when the current function returns.

Expand Down Expand Up @@ -4422,7 +4422,7 @@
<!-- markdownlint-disable MD028 -->

<!-- markdownlint-enable MD028 -->
> *Note*: There is a grammar ambiguity between *type* and *constant_pattern* in a `relational_expression` on the right-hand-side of `is`; either might be a valid parse of a qualified identifier. In such a case, only if it fails to bind as a type (for compatibility with previous versions of the language), is it resolved to be the first thing found (which must be either a constant or a type). This ambiguity is only present on the right-hand side of such an expression.
> *Note*: There is a grammar ambiguity between *type* and *constant_pattern* in a `relational_expression` on the right-hand-side of `is`; either might be a valid parse of a qualified identifier. In such a case, only if it fails to bind as a type (for compatibility with previous versions of the language), is it resolved to be the first thing found (which must be either a constant or a type). This ambiguity is only present on the right-hand side of such an expression. *end note*

The `is` operator is described in [§12.14.12](expressions.md#121412-the-is-operator) and the `as` operator is described in [§12.14.13](expressions.md#121413-the-as-operator).

Expand Down Expand Up @@ -4751,16 +4751,16 @@

If each operand `x` and `y` of a `==` or `!=` operator is classified either as a tuple or as a value with a tuple type ([§8.3.11](types.md#8311-tuple-types)), the operator is a *tuple equality operator*.

If an operand `e` is classified as a tuple, the elements `e1...en` shall be the results of evaluating the element expressions of the tuple expression. Otherwise if `e` is a value of a tuple type, the elements shall be `t.Item1...t.Itemn` where `t` is the result of evaluating `e`.
If an operand `e` is classified as a tuple, the elements `e₁...eₙ` shall be the results of evaluating the element expressions of the tuple expression. Otherwise if `e` is a value of a tuple type, the elements shall be `t.Item1...t.Itemn` where `t` is the result of evaluating `e`.

The operands `x` and `y` of a tuple equality operator shall have the same arity, or a compile time error occurs. For each pair of elements `xi` and `yi`, the same equality operator shall apply, and shall yield a result of type `bool`, `dynamic`, a type that has an implicit conversion to `bool`, or a type that defines the `true` and `false` operators.
The operands `x` and `y` of a tuple equality operator shall have the same arity, or a compile time error occurs. For each pair of elements `xᵢ` and `yᵢ`, the same equality operator shall apply, and shall yield a result of type `bool`, `dynamic`, a type that has an implicit conversion to `bool`, or a type that defines the `true` and `false` operators.

The tuple equality operator `x == y` is evaluated as follows:

- The left side operand `x` is evaluated.
- The right side operand `y` is evaluated.
- For each pair of elements `xi` and `yi` in lexical order:
- The operator `xi == yi` is evaluated, and a result of type `bool` is obtained in the following way:
- For each pair of elements `xᵢ` and `yᵢ` in lexical order:
- The operator `xᵢ == yᵢ` is evaluated, and a result of type `bool` is obtained in the following way:
- If the comparison yielded a `bool` then that is the result.
- Otherwise if the comparison yielded a `dynamic` then the operator `false` is dynamically invoked on it, and the resulting `bool` value is negated with the logical negation operator (`!`).
- Otherwise, if the type of the comparison has an implicit conversion to `bool`, that conversion is applied.
Expand All @@ -4772,8 +4772,8 @@

- The left side operand `x` is evaluated.
- The right side operand `y` is evaluated.
- For each pair of elements `xi` and `yi` in lexical order:
- The operator `xi != yi` is evaluated, and a result of type `bool` is obtained in the following way:
- For each pair of elements `xᵢ` and `yᵢ` in lexical order:
- The operator `xᵢ != yᵢ` is evaluated, and a result of type `bool` is obtained in the following way:
- If the comparison yielded a `bool` then that is the result.
- Otherwise if the comparison yielded a `dynamic` then the operator `true` is dynamically invoked on it, and the resulting `bool` value is the result.
- Otherwise, if the type of the comparison has an implicit conversion to `bool`, that conversion is applied.
Expand Down Expand Up @@ -6819,24 +6819,25 @@
> ```csharp
> struct Point
> {
> int x, y;
> int x, y;
>
> public Point(int x, int y)
> {
> this.x = x;
> this.y = y;
> }
> public Point(int x, int y)
> {
> this.x = x;
> this.y = y;
> }
>
> public int X
> {
> get { return x; }
> set { x = value; }
> }
> public int X
> {
> get { return x; }
> set { x = value; }
> }
>
> public int Y {
> get { return y; }
> set { y = value; }
> }
> public int Y
> {
> get { return y; }
> set { y = value; }
> }
> }
>
> struct Rectangle
Expand Down Expand Up @@ -6920,17 +6921,18 @@
> public static ref readonly int M3() { ... }
> public static void Test()
> {
> int v = 42;
> ref int r1 = ref v; // OK, r1 refers to v, which has value 42
> r1 = ref M1(); // Error; M1 returns a value, not a reference
> r1 = ref M2(); // OK; makes an alias
> r1 = ref M2u(); // Error; lhs and rhs have different types
> r1 = ref M3(); // error; M3 returns a ref readonly, which r1 cannot honor
> ref readonly int r2 = ref v; // OK; make readonly alias to ref
> r2 = ref M2(); // OK; makes an alias, adding read-only protection
> r2 = ref M3(); // OK; makes an alias and honors the read-only
> r2 = ref (r1 = ref M2()); // OK; r1 is an alias to a writable variable,
> // r2 is an alias (with read-only access) to the same variable
> int v = 42;
> ref int r1 = ref v; // OK, r1 refers to v, which has value 42
> r1 = ref M1(); // Error; M1 returns a value, not a reference
> r1 = ref M2(); // OK; makes an alias
> r1 = ref M2u(); // Error; lhs and rhs have different types
> r1 = ref M3(); // error; M3 returns a ref readonly, which r1 cannot honor
> ref readonly int r2 = ref v; // OK; make readonly alias to ref
> r2 = ref M2(); // OK; makes an alias, adding read-only protection
> r2 = ref M3(); // OK; makes an alias and honors the read-only
> r2 = ref (r1 = ref M2()); // OK; r1 is an alias to a writable variable,
> // r2 is an alias (with read-only access)
> // to the same variable
> }
> ```
>
Expand Down
Loading