Skip to content

Commit f56420d

Browse files
RexJaeschkeBillWagner
authored andcommitted
add support for indexers and ranges
1 parent 36e12c3 commit f56420d

File tree

1 file changed

+75
-9
lines changed

1 file changed

+75
-9
lines changed

standard/expressions.md

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ The precedence of an operator is established by the definition of its associated
142142
> | **Subclause** | **Category** | **Operators**
143143
> | ----------------- | ------------------------------- | -------------------------------------------------------
144144
> | [§11.7](expressions.md#117-primary-expressions) | Primary | `x.y` `x?.y` `f(x)` `a[x]` `a?[x]` `x++` `x--` `new` `typeof` `default` `checked` `unchecked` `delegate`
145-
> | [§11.8](expressions.md#118-unary-operators) | Unary | `+` `-` `!` `~` `++x` `--x` `(T)x` `await x`
145+
> | [§11.8](expressions.md#118-unary-operators) | Unary | `+` `-` `!` `~` `^` `++x` `--x` `(T)x` `await x`
146+
> | §range-operator | Range | `..`
146147
> | [§11.9](expressions.md#119-arithmetic-operators) | Multiplicative | `*` `/` `%`
147148
> | [§11.9](expressions.md#119-arithmetic-operators) | Additive | `+` `-`
148149
> | [§11.10](expressions.md#1110-shift-operators) | Shift | `<<` `>>`
@@ -338,8 +339,8 @@ In both of the above cases, a cast expression can be used to explicitly convert
338339
339340
***Lifted operators*** permit predefined and user-defined operators that operate on non-nullable value types to also be used with nullable forms of those types. Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:
340341
341-
- For the unary operators `+`, `++`, `-`, `--`, `!`, and `~`, a lifted form of an operator exists if the operand and result types are both non-nullable value types. The lifted form is constructed by adding a single `?modifier to the operand and result types. The lifted operator produces a `null` value if the operand is `null`. Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.
342-
- For the binary operators `+`, `-`, `*`, `/`, `%`, `&`, `|`, `^`, `<<`, and `>>`, a lifted form of an operator exists if the operand and result types are all non-nullable value types. The lifted form is constructed by adding a single `?modifier to each operand and result type. The lifted operator produces a `null` value if one or both operands are `null` (an exception being the `&` and `|operators of the `bool?` type, as described in11.12.5](expressions.md#11125-nullable-boolean--and--operators)). Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.
342+
- For the unary operators `+`, `++`, `-`, `--`, `!`, `~`, and `^`, a lifted form of an operator exists if the operand and result types are both non-nullable value types. The lifted form is constructed by adding a single `?modifier to the operand and result types. The lifted operator produces a `null` value if the operand is `null`. Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.
343+
- For the binary operators `+`, `-`, `*`, `/`, `%`, `&`, `|`, `^`, `<<`, `>>`, and `..`, a lifted form of an operator exists if the operand and result types are all non-nullable value types. The lifted form is constructed by adding a single `?modifier to each operand and result type. The lifted operator produces a `null` value if one or both operands are `null` (an exception being the `&` and `|operators of the `bool?` type, as described in11.12.5](expressions.md#11125-nullable-boolean--and--operators)). Otherwise, the lifted operator unwraps the operands, applies the underlying operator, and wraps the result.
343344
- For the equality operators `==` and `!=`, a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is `bool`. The lifted form is constructed by adding a single `?modifier to each operand type. The lifted operator considers two `null` values equal, and a `null` value unequal to any non-`null` value. If both operands are non-`null`, the lifted operator unwraps the operands and applies the underlying operator to produce the `bool` result.
344345
- For the relational operators `<`, `>`, `<=`, and `>=`, a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is `bool`. The lifted form is constructed by adding a single `?modifier to each operand type. The lifted operator produces the value `false` if one or both operands are `null`. Otherwise, the lifted operator unwraps the operands and applies the underlying operator to produce the `bool` result.
345346
@@ -1863,17 +1864,78 @@ If the *primary_no_array_creation_expression* of an *element_access* is a value
18631864

18641865
#### 11.7.10.2 Array access
18651866

1866-
For an array access, the *primary_no_array_creation_expression* of the *element_access* shall be a value of an *array_type*. Furthermore, the *argument_list* of an array access is not allowed to contain named arguments. The number of expressions in the *argument_list* shall be the same as the rank of the *array_type*, and each expression shall be of type `int`, `uint`, `long`, or `ulong,` or shall be implicitly convertible to one or more of these types.
1867+
For an array access, the *primary_no_array_creation_expression* of the *element_access* shall be a value of an *array_type*. Furthermore, the *argument_list* of an array access shall not contain named arguments. The number of expressions in the *argument_list* shall be the same as the rank of the *array_type*, and each expression shall be of type `int`, `uint`, `long`, `ulong`, `System.Index`, or `System.Range`, or shall be implicitly convertible to one or more of the types `int`, `uint`, `long`, or `ulong`. However, it is a compile-time error for an *argument_list* expression of type `System.Index` or `System.Range` to be used for any dimension of a multi-dimensional array.
18671868

1868-
The result of evaluating an array access is a variable of the element type of the array, namely the array element selected by the value(s) of the expression(s) in the *argument_list*.
1869+
The result of evaluating an array access that does not involve `System.Range` is a variable of the element type of the array, namely the array element selected by the value(s) of the expression(s) in the *argument_list*.
1870+
1871+
The result of evaluating an array access that involves `System.Range` is a slice of the array being accessed, as selected by the value(s) of the expression(s) in the *argument_list*. The resulting slice’s element type is the same as the element type of the array being accessed.
18691872

18701873
The run-time processing of an array access of the form `P[A]`, where `P` is a *primary_no_array_creation_expression* of an *array_type* and `A` is an *argument_list*, consists of the following steps:
18711874

18721875
- `P` is evaluated. If this evaluation causes an exception, no further steps are executed.
1873-
- The index expressions of the *argument_list* are evaluated in order, from left to right. Following evaluation of each index expression, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) to one of the following types is performed: `int`, `uint`, `long`, `ulong`. The first type in this list for which an implicit conversion exists is chosen. For instance, if the index expression is of type `short` then an implicit conversion to `int` is performed, since implicit conversions from `short` to `int` and from `short` to `long` are possible. If evaluation of an index expression or the subsequent implicit conversion causes an exception, then no further index expressions are evaluated and no further steps are executed.
1874-
- The value of `P` is checked to be valid. If the value of `P` is `null`, a `System.NullReferenceException` is thrown and no further steps are executed.
1875-
- The value of each expression in the *argument_list* is checked against the actual bounds of each dimension of the array instance referenced by `P`. If one or more values are out of range, a `System.IndexOutOfRangeException` is thrown and no further steps are executed.
1876-
- The location of the array element given by the index expression(s) is computed, and this location becomes the result of the array access.
1876+
- The index expressions of the *argument_list* are evaluated in order, from left to right. Following evaluation of each index expression, for expressions not having type `System.Index` or `System.Range`, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) to one of the following types is performed: `int`, `uint`, `long`, `ulong`. The first type in this list for which an implicit conversion exists is chosen. For instance, if the index expression is of type `short` then an implicit conversion to `int` is performed, since implicit conversions from `short` to `int` and from `short` to `long` are possible. For an index expression having type `System.Index`, the Index is transformed into the corresponding `int` index using `System.Index.GetOffset`.
1877+
1878+
- For an index expression not having type `System.Range`:
1879+
- If evaluation of an index expression, the subsequent implicit conversion, or Index transformation causes an exception, then no further index expressions are evaluated, and no further steps are executed.
1880+
- The value of `P` is checked to be valid. If the value of `P` is `null`, a `System.NullReferenceException` is thrown and no further steps are executed.
1881+
- The value of each expression in the *argument_list* is checked against the actual bounds of each dimension of the array instance referenced by `P`. If one or more values are out of range, a `System.IndexOutOfRangeException` is thrown and no further steps are executed.
1882+
- The location of the array element given by the index expression(s) is computed, and this location becomes the result of the array access.
1883+
- Else, for an index expression having type `System.Range`:
1884+
- The value of `P` is checked to be valid. If the value of `P` is `null`, a `System.NullReferenceException` is thrown and no further steps are executed.
1885+
- The Range is transformed into the corresponding slice using `System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray<T>`. If this transformation causes an exception, no further steps are executed.
1886+
- The result of the transformation becomes the result of the array access.
1887+
1888+
> *Example*: Given the following one-dimensional array and Index:
1889+
> ```csharp
1890+
> string[] words = new string[] { "red", "green", "blue" };
1891+
> Index idx = 1;
1892+
> ```
1893+
> `words[idx]` is transformed by the implementation to
1894+
> ```csharp
1895+
> words[idx.GetOffset(words.Length)]
1896+
> ```
1897+
> which results in `"green"`. Similarly, `words[^0]` is transformed by the implementation to `words[(^0).GetOffset(words.Length)]`, which results in `System.IndexOutOfRangeException`. *end example*
1898+
1899+
> *Example*: Given the following jagged array and Indexes:
1900+
> ```csharp
1901+
> int[][] values = new int[][] { … };
1902+
> Index idx1 = 1;
1903+
> Index idx2 = ^1;
1904+
> ```
1905+
> ` values[idx1][idx2]` is transformed by the implementation to
1906+
> ```csharp
1907+
> values[idx1.GetOffset(values.Length)][idx2.GetOffset(values[idx1].Length)]
1908+
> ```
1909+
> *end example*
1910+
1911+
> *Example*: Given the following multidimensional array and Indexes:
1912+
> ```csharp
1913+
> int[,] values2D = { … };
1914+
> Index idx3 = 1;
1915+
> Index idx4 = ^1;
1916+
> ```
1917+
> as `Index`-typed subscripts are not supported in this context, what one might like to express simply as `values2D[idx3, idx4]` must instead be rewritten explicitly by the programmer as
1918+
> ```csharp
1919+
> values2D[idx3.GetOffset(values2D.GetUpperBound(0) + 1), idx4.GetOffset(values2D.GetUpperBound(1) + 1)]
1920+
> ```
1921+
> *end example*
1922+
1923+
> *Example*: Given the following one-dimensional array:
1924+
> ```csharp
1925+
> string[] seasons = new string[] { "Summer", "Autumn", "Winter", "Spring" };
1926+
> ```
1927+
> `seasons[0..2]` is transformed by the implementation to
1928+
> ```csharp
1929+
> System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray<string>(seasons, 0..2)
1930+
> ```
1931+
> which returns the `string[]` slice containing `"Summer"` and `"Autumn"`. *end example*
1932+
1933+
> *Example*: Given the following jagged array:
1934+
> ```csharp
1935+
> int[][] values = new int[][] { new int[] { 10, 9, 5 },
1936+
> new int[] { 6, 12, 17, 32 }, new int[] { 28, 42 } };
1937+
> ```
1938+
all the Range and Index expressions in `values[1..3][^1][..2][^1]` are transformed by the implementation, resulting in `values[2][1]`, which is 42. *end example*
18771939
18781940
#### 11.7.10.3 Indexer access
18791941
@@ -1892,6 +1954,10 @@ The binding-time processing of an indexer access of the form `P[A]`, where `P` i
18921954
18931955
Depending on the context in which it is used, an indexer access causes invocation of either the *get_accessor* or the *set_accessor* of the indexer. If the indexer access is the target of an assignment, the *set_accessor* is invoked to assign a new value ([§11.18.2](expressions.md#11182-simple-assignment)). In all other cases, the *get_accessor* is invoked to obtain the current value ([§11.2.2](expressions.md#1122-values-of-expressions)).
18941956
1957+
> *Note*: An implementation is required to provide an instance indexer member with a single parameter of type `Index` for any type that meets the criteria specified in §indexable-sequence-impl-support-for-index. *end note*
1958+
1959+
> *Note*: An implementation is required to provide an instance indexer member with a single parameter of type `Range` for any type that meets the criteria specified in §indexable-sequence-impl-support-for-range. *end note*
1960+
18951961
### 11.7.11 Null Conditional Element Access
18961962
18971963
A *null_conditional_element_access* consists of a *primary_no_array_creation_expression* followed by the two tokens “`?`” and “`[`”, followed by an *argument_list*, followed by a “`]`” token, followed by zero or more *dependent_access*es.

0 commit comments

Comments
 (0)