diff --git a/standard/arrays.md b/standard/arrays.md index 7f0611678..bd3fdb280 100644 --- a/standard/arrays.md +++ b/standard/arrays.md @@ -31,20 +31,62 @@ Every array type is a reference type ([§8.2](types.md#82-reference-types)). The The grammar productions for array types are provided in [§8.2.1](types.md#821-general). -An array type is written as a *non_array_type* followed by one or more *rank_specifier*s. +An array type is written as a *non_array_type* followed by one or more *rank_specifier*s, or an *array_type* followed by a *nullable_type_annotation* followed by one or more *rank_specifier*s. The latter production is used to represent array types where the element type is an array type which is nullable ([§8.9](types.md#89-reference-types-and-nullability)). A *non_array_type* is any *type* that is not itself an *array_type*. -The rank of an array type is given by the leftmost *rank_specifier* in the *array_type*: A *rank_specifier* indicates that the array is an array with a rank of one plus the number of “`,`” tokens in the *rank_specifier*. - -The element type of an array type is the type that results from deleting the leftmost *rank_specifier*: +When determining the rank and element type of array type as specified below, only the *rank_specifier*s in the outer-most production are considered, so in the production `array_type nullable_type_annotation rank_specifier+`, any `rank_specifier` within the `array_type` is ignored. -- An array type of the form `T[R]` is an array with rank `R` and a non-array element type `T`. -- An array type of the form `T[R][R₁]...[Rₓ]` is an array with rank `R` and an element type `T[R₁]...[Rₓ]`. +The rank of an array type is given by the leftmost *rank_specifier* in the *array_type*: A *rank_specifier* indicates that the array is an array with a rank of one plus the number of “`,`” tokens in the *rank_specifier*. -In effect, the *rank_specifier*s are read from left to right *before* the final non-array element type. +The element type of an array type is the type that results from deleting the leftmost *rank_specifier* from the *array_type*. -> *Example*: The type in `T[][,,][,]` is a single-dimensional array of three-dimensional arrays of two-dimensional arrays of `int`. *end example* +> *Example*: The following code shows several variable declarations, including a mixture of single-dimensional arrays, multi-dimensional arrays, and arrays of arrays, with some using nullable reference types. In each case, the rank and element type is described, and then demonstrated with a second variable declaration which is initialized using an element access expression. +> +> +> ```csharp +> // Rank 1, element type int +> int[] array1 = ...; +> int element1 = array1[0]; +> +> // Rank 2, element type int +> int[,] array2 = ...; +> int element2 = array2[0, 1]; +> +> // Rank 1, element type int? (Nullable) +> int?[] array3 = ...; +> int? element3 = array3[0]; +> +> // Rank 1, element type string? (nullable string) +> string?[] array4 = ...; +> string? element4 = array4[0]; +> +> // Rank 1, element type string[,,][,] +> string[][,,][,] array5 = ...; +> string[,,][,] element5 = array5[0]; +> +> // Rank 1, element type string; the array itself is nullable +> string[]? array6 = ...; +> string element6 = array6?[0] ?? ""; +> +> // Rank 1, element type string[,]? +> string[,]?[] array7 = ...; +> string[,]? element7 = array7[0]; +> +> // Rank 3, element type int[]?[,] +> int[]?[,,][,] array8 = ...; +> int[]?[,] element8 = array8[0, 1, 2]; +> +> // Rank 1, element type string[,]?[]?[,,] +> string[,]?[]?[][,,] array9 = ...; +> string[,]?[]?[,,] element9 = array9[0]; +> +> // Rank 2, element type string[][][,,] +> // Note that this appears the same as the array9 example above other +> // than for the use of ? but the rank and element type are significantly different. +> string[,][][][,,] array10 = ...; +> string[][][,,] element10 = array10[0, 1]; +> ``` At run-time, a value of an array type can be `null` or a reference to an instance of that array type. diff --git a/standard/types.md b/standard/types.md index 865f99dfb..9d1c6ad3a 100644 --- a/standard/types.md +++ b/standard/types.md @@ -54,17 +54,22 @@ interface_type ; array_type - : non_array_type rank_specifier+ + : array_type nullable_type_annotation rank_specifier+ + | non_array_type rank_specifier+ ; non_array_type + : non_array_non_nullable_type nullable_type_annotation? + | pointer_type // unsafe code support + ; + +non_array_non_nullable_type : value_type | class_type | interface_type | delegate_type | 'dynamic' | type_parameter - | pointer_type // unsafe code support ; rank_specifier @@ -732,7 +737,9 @@ There are two forms of nullability for reference types: > *Note:* The types `R` and `R?` are represented by the same underlying type, `R`. A variable of that underlying type can either contain a reference to an object or be the value `null`, which indicates “no reference.” *end note* -The syntactic distinction between a *nullable reference type* and its corresponding *non-nullable reference type* enables a compiler to generate diagnostics. A compiler must allow the *nullable_type_annotation* as defined in [§8.2.1](types.md#821-general). The diagnostics must be limited to warnings. Neither the presence or absence of nullable annotations, nor the state of the nullable context can change the compile time or runtime behavior of a program except for changes in any diagnostic messages generated at compile time. +The syntactic distinction between a *nullable reference type* and its corresponding *non-nullable reference type* enables a compiler to generate diagnostics. A compiler must allow the *nullable_type_annotation* as defined in [§8.2.1](types.md#821-general). The diagnostics must be limited to warnings. Other than in the meaning of array types, neither the presence or absence of nullable annotations, nor the state of the nullable context can change the compile time or runtime behavior of a program except for changes in any diagnostic messages generated at compile time. + +The meaning of array types is significantly impacted by the presence of *nullable_type_annotation* within an *array_type*, as described in [§17.2.1](arrays.md#1721-general). ### 8.9.2 Non-nullable reference types @@ -756,6 +763,8 @@ Throughout this specification, all C# code that does not contain nullable direct > *Note:* A nullable context where both flags are disabled matches the previous standard behavior for reference types. *end note* +The rank and element of an array type declared using *nullable_type_annotation* is not affected by the nullable context ([§8.9.4](types.md#894-nullable-context)). + #### 8.9.4.2 Nullable disable When both the warning and annotations flags are disabled, the nullable context is *disabled*. @@ -1106,6 +1115,8 @@ A compiler may issue a warning when nullability annotations differ between two t A compiler may follow rules for interface variance ([§19.2.3.3](interfaces.md#19233-variance-conversion)), delegate variance ([§21.4](delegates.md#214-delegate-compatibility)), and array covariance ([§17.6](arrays.md#176-array-covariance)) in determining whether to issue a warning for type conversions. +(See [§17.2.1](arrays.md#1721-general) for the specification of the corresponding non-nullable array type used in `M7` and `M8`.) + > > ```csharp > #nullable enable @@ -1143,6 +1154,17 @@ A compiler may follow rules for interface variance ([§19.2.3.3](interfaces.md#1 > string[] v1 = p; // Warning > string[] v2 = p!; // No warning > } +> +> public void M7(string[][,] p) +> { +> string[,]?[] v1 = p; // No warning +> } +> +> public void M8(string[]?[,] p) +> { +> string[,][] v1 = p; // Warning +> string[,][] v2 = p!; // No warning +> } > } > ``` >