diff --git a/standard/arrays.md b/standard/arrays.md index ccfcfe278..f9d7d6c1e 100644 --- a/standard/arrays.md +++ b/standard/arrays.md @@ -46,9 +46,11 @@ In effect, the *rank_specifier*s are read from left to right *before* the final > *Example*: The type in `T[][,,][,]` is a single-dimensional array of three-dimensional arrays of two-dimensional arrays of `int`. *end example* -At run-time, a value of an array type can be `null` or a reference to an instance of that array type. +At run-time, a value of an array type can be: -> *Note*: Following the rules of [§17.6](arrays.md#176-array-covariance), the value may also be a reference to a covariant array type. *end note* +- `null`; or +- a reference to an instance of that array type; or +- a reference to an instance of a covariant array type, following the rules of [§17.6](arrays.md#176-array-covariance). ### 17.2.2 The System.Array type diff --git a/standard/types.md b/standard/types.md index a431c7273..869d587b5 100644 --- a/standard/types.md +++ b/standard/types.md @@ -55,6 +55,7 @@ interface_type array_type : non_array_type rank_specifier+ + | non_array_type ( nullable_type_annotation rank_specifier+ )+ ; non_array_type @@ -738,6 +739,8 @@ There are two forms of nullability for reference types: 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 only exception to this general rule is that adding a nullable annotation can change the syntactic meaning of the type of an array of arrays. Specifically, a type such as `A[][,]` is an array of two-dimensional arrays. That is because the syntactic meaning of the array dimensions in the array type are read from the inside out. However, by adding a nullable annotation between the dimensions, writing `A[]?[,]`, changes the parsing and therefore syntactic meaning of the type. In this case, the element type of the array is `A[]?`. The type is now a two-dimensional array of a nullable array type. + ### 8.9.2 Non-nullable reference types A ***non-nullable reference type*** is a reference type of the form `T`, where `T` is the name of the type. The default null-state of a non-nullable variable is *not-null*. Warnings may be generated when an expression that is *maybe-null* is used where a *not-null* value is required. diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v8/Arrays of nullables/ReadMe.md b/tools/GrammarTesting/Tests/Parsing/Samples/v8/Arrays of nullables/ReadMe.md new file mode 100644 index 000000000..d1ef23063 --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v8/Arrays of nullables/ReadMe.md @@ -0,0 +1,3 @@ +# Sample: Arrays of NRT + +Samples for nullable arrays, arrays of nullables, and nullable arrays of nullables. diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v8/Arrays of nullables/_Sample_Options.txt b/tools/GrammarTesting/Tests/Parsing/Samples/v8/Arrays of nullables/_Sample_Options.txt new file mode 100644 index 000000000..a96c4cd34 --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v8/Arrays of nullables/_Sample_Options.txt @@ -0,0 +1 @@ +-ms Rules -rt diff --git a/tools/GrammarTesting/Tests/Parsing/Samples/v8/Arrays of nullables/sample.cs b/tools/GrammarTesting/Tests/Parsing/Samples/v8/Arrays of nullables/sample.cs new file mode 100644 index 000000000..714f34241 --- /dev/null +++ b/tools/GrammarTesting/Tests/Parsing/Samples/v8/Arrays of nullables/sample.cs @@ -0,0 +1,36 @@ +class ArraysOfNullable +{ + class A { } + + void ArraysOfNullable() + { + A[] p_1 = new A[5]; // Array of non-nullable A all elements inited to null (oops) + A[]? q_1 = null; // Nullable array of non-nullable A, array inited to null + A?[] r_1 = new A[5]; // Array of nullable A all elements inited to null + A?[]? s_1 = null; // Nullable array of nullable A, array inited to null + + string[] p_2 = new string[5]; // Array of non-nullable string all elements inited to null (oops) + string[]? q_2 = null; // Nullable array of non-nullable string, array inited to null + string?[] r_2 = new string[5]; // Array of nullable string all elements inited to null + string?[]? s_2 = null; // Nullable array of nullable string, array inited to null + + int[] p_3 = new int[5]; // Array of non-nullable int all elements inited to 0 + int[]? q_3 = null; // Nullable array of non-nullable int, array inited to null + int?[] r_3 = new int[5]; // Array of nullable int all elements inited to null + int?[]? s_3 = null; // Nullable array of nullable int, array inited to null + + dynamic[] p_4 = new dynamic[5]; // Array of non-nullable dynamic all elements inited to 0 + dynamic[]? q_4 = null; // Nullable array of non-nullable dynamic, array inited to null + dynamic?[] r_4 = new dynamic[5]; // Array of nullable dynamic all elements inited to null + dynamic?[]? s_4 = null; // Nullable array of nullable dynamic, array inited to null + + A[][,] p_5 = new A[1][1,1]; // Array of two-dimensional array + A[][,]? q_5 = null; // Array of two-dimensional array + A[]?[,] r_5 = new A[]?[1,1]; // Two dimensional array of array + A[]?[,]? s_5 = null; // Two dimensional array of array + A?[][,] t_5 = new A[1][1,1]; // Array of two-dimensional array + A?[][,]? u_5 = null; // Array of two-dimensional array + A?[]?[,] v_5 = new A[]?[1,1]; // Two dimensional array of array + A?[]?[,]? w_5 = null; // Two dimensional array of array + } +}