Skip to content

Commit c2bb8dd

Browse files
committed
Incorporate some text from dotnet#700
Bring in the normative text from dotnet#700. Some text is removed because of the decision on normative language in our September meeting.
1 parent 874bfc9 commit c2bb8dd

File tree

2 files changed

+67
-14
lines changed

2 files changed

+67
-14
lines changed

standard/classes.md

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -412,17 +412,18 @@ type_parameter_constraints
412412
;
413413
414414
primary_constraint
415-
: class_type
416-
| 'class'
415+
: class_type '?'?
416+
| 'class' '?'?
417417
| 'struct'
418+
| `notnull`
418419
| 'unmanaged'
419420
;
420421
421422
secondary_constraints
422-
: interface_type
423+
: interface_type '?'?
423424
| type_parameter
424-
| secondary_constraints ',' interface_type
425-
| secondary_constraints ',' type_parameter
425+
| secondary_constraints ',' interface_type '?'?
426+
| secondary_constraints ',' type_parameter '?'?
426427
;
427428
428429
constructor_constraint
@@ -434,14 +435,18 @@ Each *type_parameter_constraints_clause* consists of the token `where`, followed
434435

435436
The list of constraints given in a `where` clause can include any of the following components, in this order: a single primary constraint, one or more secondary constraints, and the constructor constraint, `new()`.
436437

437-
A primary constraint can be a class type, the ***reference type constraint*** `class`, the ***value type constraint*** `struct`, or the ***unmanaged type constraint*** `unmanaged`.
438+
A primary constraint can be a class type, the ***reference type constraint*** `class`, the ***nullable reference type constraint*** `class?`, the ***not null*** constraint `notnull`, the ***value type constraint*** `struct` or the ***unmanaged type constraint*** `unmanaged`.
438439

439-
A secondary constraint can be a *type_parameter* or *interface_type*.
440+
A secondary constraint can be a *type_parameter* or *interface_type*, either optionally followed by `?`.
440441

441-
The reference type constraint specifies that a type argument used for the type parameter shall be a reference type. All class types, interface types, delegate types, array types, and type parameters known to be a reference type (as defined below) satisfy this constraint.
442+
The reference type constraint specifies that a type argument used for the type parameter shall be a non-nullable reference type. All non-nullable class types, non-nullable interface types, non-nullable delegate types, non-nullable array types, and type parameters known to be a non-nullable reference type (as defined below) satisfy this constraint.
443+
444+
The nullable reference type constraint specifies that a type argument shall be either a non-nullable reference type or a nullable reference type. All class types, interface types, delegate types, array types, and type parameters known to be a reference type (as defined below) satisfy this constraint.
442445

443446
The value type constraint specifies that a type argument used for the type parameter shall be a non-nullable value type. All non-nullable struct types, enum types, and type parameters having the value type constraint satisfy this constraint. Note that although classified as a value type, a nullable value type ([§8.3.12](types.md#8312-nullable-value-types)) does not satisfy the value type constraint. A type parameter having the value type constraint shall not also have the *constructor_constraint*, although it may be used as a type argument for another type parameter with a *constructor_constraint*.
444447

448+
The ***not null*** constraint specifies that a type argument used for the type parameter shall be a non-nullable value type or a non-nullable reference type. All non-nullable class types, interface types, delegate types, array types, struct types, enum types, and type parameters known to be a non-nullable value type or non-nullable reference type satisfy this constraint.
449+
445450
> *Note*: The `System.Nullable<T>` type specifies the non-nullable value type constraint for `T`. Thus, recursively constructed types of the forms `T??` and `Nullable<Nullable<T>>` are prohibited. *end note*
446451
447452
Because `unmanaged` is not a keyword, in *primary_constraint* the unmanaged constraint is always syntactically ambiguous with *class_type*. For compatibility reasons, if a name lookup ([§12.8.4](expressions.md#1284-simple-names)) of the name `unmanaged` succeeds it is treated as a `class_type`. Otherwise it is treated as the unmanaged constraint.
@@ -604,7 +609,9 @@ The ***effective interface set*** of a type parameter `T` is defined as follows
604609
- If `T` has no *interface_type* constraints but has *type_parameter* constraints, its effective interface set is the union of the effective interface sets of its *type_parameter* constraints.
605610
- If `T` has both *interface_type* constraints and *type_parameter* constraints, its effective interface set is the union of the set of dynamic erasures of its *interface_type* constraints and the effective interface sets of its *type_parameter* constraints.
606611
607-
A type parameter is *known to be a reference type* if it has the reference type constraint or its effective base class is not `object` or `System.ValueType`.
612+
A type parameter is *known to be a non-nullable reference type* if it has the non-nullable reference type constraint or its effective base class is not `object` or `System.ValueType`.
613+
614+
A type parameter is *known to be a reference type* if it has the non-nullable reference type constraint, reference type constraint or its effective base class is not `object` or `System.ValueType`.
608615
609616
Values of a constrained type parameter type can be used to access the instance members implied by the constraints.
610617
@@ -878,7 +885,7 @@ All members of a generic class can use type parameters from any enclosing class,
878885
> class C<V>
879886
> {
880887
> public V f1;
881-
> public C<V> f2 = null;
888+
> public C<V> f2 = null!;
882889
>
883890
> public C(V x)
884891
> {
@@ -1055,17 +1062,17 @@ Non-nested types can have `public` or `internal` declared accessibility and have
10551062
> private class Node
10561063
> {
10571064
> public object Data;
1058-
> public Node Next;
1065+
> public Node? Next;
10591066
>
1060-
> public Node(object data, Node next)
1067+
> public Node(object data, Node? next)
10611068
> {
10621069
> this.Data = data;
10631070
> this.Next = next;
10641071
> }
10651072
> }
10661073
>
1067-
> private Node first = null;
1068-
> private Node last = null;
1074+
> private Node? first = null;
1075+
> private Node? last = null;
10691076
>
10701077
> // Public interface
10711078
> public void AddToFront(object o) {...}

standard/types.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,20 @@ A type parameter is an identifier designating a value type or reference type tha
601601
type_parameter
602602
: identifier
603603
;
604+
605+
nullable_type_parameter
606+
: non_nullable_non_value_type_parameter '?'
607+
;
608+
609+
non_nullable_non_value_type_parameter
610+
: type_parameter
611+
;
604612
```
605613
614+
The *non_nullable_non_value_type_parameter* in *nullable_type_parameter* shall be a type parameter that isn’t constrained to be a value type.
615+
616+
In *nullable_type_parameter*, the annotation `?` indicates the intent that type arguments of this type are nullable. The absence of the annotation `?` indicates the intent that type arguments of this type are non-nullable.
617+
606618
Since a type parameter can be instantiated with many different type arguments, type parameters have slightly different operations and restrictions than other types.
607619

608620
> *Note*: These include:
@@ -705,3 +717,37 @@ An *unmanaged_type* is any type that isn’t a *reference_type*, a *type_paramet
705717
- `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, or `bool`.
706718
- Any *enum_type*.
707719
- Any user-defined *struct_type* that is not a constructed type and contains instance fields of *unmanaged_type*s only.
720+
721+
## §Generics-and-nullable-placeholder
722+
723+
This is a placeholder for text that will be added in the clause on "nullable context" described in `#1124`. I'll rebase and edit once that's done.
724+
725+
The distinction between the null states “maybe null” and “maybe default” is subtle and applies to type parameters. A type parameter `T` that has the state “maybe null” means the value is in the domain of valid values for `T`; however, that valid value may include `null`. A “maybe default” state means that the value may be outside the valid domain of values for `T`.
726+
727+
> *Example*:
728+
>
729+
> <!-- Example: {template:"code-in-class-lib-without-using", name:"TypeParameters", ignoredWarnings:["CS0219"]} -->
730+
> ```csharp
731+
> #nullable enable
732+
> // The value t here has the state "maybe null". It's possible for T to be instantiated
733+
> // with string?, in which case null would be within the domain of valid values here. The
734+
> // assumption though is the value provided here is within the valid values of T. Hence
735+
> // if T is `string` then null will not be a value, just as we assume that null is not
736+
> // provided for a normal string parameter
737+
> void M<T>(T t)
738+
> {
739+
> // if `T` is a `string`, `t` is not null.
740+
> // There is no guarantee that default(T) is within the valid values for T hence the
741+
> // state *must* be "maybe default" and hence local must be T?
742+
> // For example, default(string) is null, which must be assigned to a string?
743+
> T? local = default(T);
744+
> }
745+
> ```
746+
>
747+
> *end example*
748+
749+
The `class?` constraint generates a warning when the `annotations` flag is false.
750+
751+
- For any reference type `T`, the annotation `?` in `T?` makes `T?` a nullable type, whereas the unannotated `T` is non-nullable.
752+
753+
When the nullable annotation context is enabled, the compiler shall recognize these intents. When the nullable annotation context is disabled, the compiler shall ignore these intents, thereby treating `T` and `T?` in the same (nullable) manner, and generate a warning. (The latter scenario was the only one that existed prior to the addition of nullable reference types.)

0 commit comments

Comments
 (0)